diff options
author | Chris Craik <ccraik@google.com> | 2015-01-29 09:45:09 -0800 |
---|---|---|
committer | Chris Craik <ccraik@google.com> | 2015-01-30 10:49:05 -0800 |
commit | 44eb2c00861098dd3e2950d923646814b4cc57c2 (patch) | |
tree | 2d232b14b931137cc7ebb3b012c3ce4530fa5cf4 /libs/hwui/renderstate | |
parent | 1b68ce327aa37ee0c4e9580d75cb6781337c4312 (diff) | |
download | frameworks_base-44eb2c00861098dd3e2950d923646814b4cc57c2.zip frameworks_base-44eb2c00861098dd3e2950d923646814b4cc57c2.tar.gz frameworks_base-44eb2c00861098dd3e2950d923646814b4cc57c2.tar.bz2 |
Refactor blending and texture gl state
Change-Id: Ia6b3c8b2afd3dfcee7f3ce401d846b789612054a
Diffstat (limited to 'libs/hwui/renderstate')
-rw-r--r-- | libs/hwui/renderstate/Blend.cpp | 121 | ||||
-rw-r--r-- | libs/hwui/renderstate/Blend.h | 46 | ||||
-rw-r--r-- | libs/hwui/renderstate/RenderState.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/renderstate/RenderState.h | 12 | ||||
-rw-r--r-- | libs/hwui/renderstate/TextureState.cpp | 103 | ||||
-rw-r--r-- | libs/hwui/renderstate/TextureState.h | 88 |
6 files changed, 376 insertions, 19 deletions
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp new file mode 100644 index 0000000..3e7b721 --- /dev/null +++ b/libs/hwui/renderstate/Blend.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <renderstate/Blend.h> +#include "Program.h" + +#include "ShadowTessellator.h" + +namespace android { +namespace uirenderer { + +/** + * Structure mapping Skia xfermodes to OpenGL blending factors. + */ +struct Blender { + SkXfermode::Mode mode; + GLenum src; + GLenum dst; +}; + +// In this array, the index of each Blender equals the value of the first +// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] +const Blender kBlends[] = { + { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, + { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, + { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, + { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, + { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, + { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, + { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, + { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR }, + { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR } +}; + +// This array contains the swapped version of each SkXfermode. For instance +// this array's SrcOver blending mode is actually DstOver. You can refer to +// createLayer() for more information on the purpose of this array. +const Blender kBlendsSwap[] = { + { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, + { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, + { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, + { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, + { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, + { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, + { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, + { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO }, + { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE } +}; + +Blend::Blend() + : mEnabled(false) + , mSrcMode(GL_ZERO) + , mDstMode(GL_ZERO) { + // gl blending off by default +} + +void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) { + // enable + if (!mEnabled) { + glEnable(GL_BLEND); + mEnabled = true; + } + + // select blend mode + GLenum sourceMode = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src; + GLenum destMode = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst; + + if (sourceMode != mSrcMode || destMode != mSrcMode) { + glBlendFunc(sourceMode, destMode); + mSrcMode = sourceMode; + mDstMode = destMode; + } +} + +void Blend::disable() { + if (mEnabled) { + glDisable(GL_BLEND); + mEnabled = false; + } +} + +void Blend::invalidate() { + syncEnabled(); + mSrcMode = mDstMode = GL_ZERO; +} + +void Blend::syncEnabled() { + if (mEnabled) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } +} + +} /* namespace uirenderer */ +} /* namespace android */ + diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h new file mode 100644 index 0000000..b82b477 --- /dev/null +++ b/libs/hwui/renderstate/Blend.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RENDERSTATE_BLEND_H +#define RENDERSTATE_BLEND_H + +#include "Vertex.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <SkXfermode.h> +#include <memory> + +namespace android { +namespace uirenderer { + +class Blend { + friend class RenderState; +public: + void enable(SkXfermode::Mode mode, bool swapSrcDst); + void disable(); + void syncEnabled(); +private: + Blend(); + void invalidate(); + bool mEnabled; + GLenum mSrcMode; + GLenum mDstMode; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif // RENDERSTATE_BLEND_H diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index e4c8745..f913cd9 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -23,10 +23,6 @@ namespace uirenderer { RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thread) - , mCaches(nullptr) - , mMeshState(nullptr) - , mScissor(nullptr) - , mStencil(nullptr) , mViewportWidth(0) , mViewportHeight(0) , mFramebuffer(0) { @@ -34,13 +30,14 @@ RenderState::RenderState(renderthread::RenderThread& thread) } RenderState::~RenderState() { - LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil, + LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, "State object lifecycle not managed correctly"); } void RenderState::onGLContextCreated() { - LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil, + LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, "State object lifecycle not managed correctly"); + mBlend = new Blend(); mMeshState = new MeshState(); mScissor = new Scissor(); mStencil = new Stencil(); @@ -92,6 +89,10 @@ void RenderState::onGLContextDestroyed() { std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext); mAssetAtlas.terminate(); + mCaches->terminate(); + + delete mBlend; + mBlend = nullptr; delete mMeshState; mMeshState = nullptr; delete mScissor; @@ -132,7 +133,7 @@ void RenderState::interruptForFunctorInvoke() { mCaches->currentProgram = nullptr; } } - mCaches->resetActiveTexture(); + mCaches->textureState().resetActiveTexture(); meshState().unbindMeshBuffer(); meshState().unbindIndicesBuffer(); meshState().resetVertexPointers(); @@ -148,14 +149,10 @@ void RenderState::resumeFromFunctorInvoke() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); scissor().invalidate(); + blend().invalidate(); - mCaches->activeTexture(0); - mCaches->resetBoundTextures(); - - mCaches->blend = true; - glEnable(GL_BLEND); - glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode); - glBlendEquation(GL_FUNC_ADD); + mCaches->textureState().activateTexture(0); + mCaches->textureState().resetBoundTextures(); } void RenderState::debugOverdraw(bool enable, bool clear) { diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index d1ee64a..4180f44 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -24,7 +24,7 @@ #include <utils/RefBase.h> #include <private/hwui/DrawGlInfo.h> - +#include <renderstate/Blend.h> #include "AssetAtlas.h" #include "Caches.h" #include "renderstate/MeshState.h" @@ -84,6 +84,7 @@ public: void postDecStrong(VirtualLightRefBase* object); AssetAtlas& assetAtlas() { return mAssetAtlas; } + Blend& blend() { return *mBlend; } MeshState& meshState() { return *mMeshState; } Scissor& scissor() { return *mScissor; } Stencil& stencil() { return *mStencil; } @@ -100,11 +101,12 @@ private: renderthread::RenderThread& mRenderThread; - Caches* mCaches; + Caches* mCaches = nullptr; - MeshState* mMeshState; - Scissor* mScissor; - Stencil* mStencil; + Blend* mBlend = nullptr; + MeshState* mMeshState = nullptr; + Scissor* mScissor = nullptr; + Stencil* mStencil = nullptr; AssetAtlas mAssetAtlas; std::set<Layer*> mActiveLayers; diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp new file mode 100644 index 0000000..1a638d2 --- /dev/null +++ b/libs/hwui/renderstate/TextureState.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <renderstate/TextureState.h> + +namespace android { +namespace uirenderer { + +// Must define as many texture units as specified by kTextureUnitsCount +const GLenum kTextureUnits[] = { + GL_TEXTURE0, + GL_TEXTURE1, + GL_TEXTURE2 +}; + +TextureState::TextureState() + : mTextureUnit(0) { + glActiveTexture(kTextureUnits[0]); + resetBoundTextures(); + + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount, + "At least %d texture units are required!", kTextureUnitsCount); +} + +void TextureState::activateTexture(GLuint textureUnit) { + if (mTextureUnit != textureUnit) { + glActiveTexture(kTextureUnits[textureUnit]); + mTextureUnit = textureUnit; + } +} + +void TextureState::resetActiveTexture() { + mTextureUnit = -1; +} + +void TextureState::bindTexture(GLuint texture) { + if (mBoundTextures[mTextureUnit] != texture) { + glBindTexture(GL_TEXTURE_2D, texture); + mBoundTextures[mTextureUnit] = texture; + } +} + +void TextureState::bindTexture(GLenum target, GLuint texture) { + if (target == GL_TEXTURE_2D) { + bindTexture(texture); + } else { + // GLConsumer directly calls glBindTexture() with + // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target + // since the cached state could be stale + glBindTexture(target, texture); + } +} + +void TextureState::deleteTexture(GLuint texture) { + // When glDeleteTextures() is called on a currently bound texture, + // OpenGL ES specifies that the texture is then considered unbound + // Consider the following series of calls: + // + // glGenTextures -> creates texture name 2 + // glBindTexture(2) + // glDeleteTextures(2) -> 2 is now unbound + // glGenTextures -> can return 2 again + // + // If we don't call glBindTexture(2) after the second glGenTextures + // call, any texture operation will be performed on the default + // texture (name=0) + + unbindTexture(texture); + + glDeleteTextures(1, &texture); +} + +void TextureState::resetBoundTextures() { + for (int i = 0; i < kTextureUnitsCount; i++) { + mBoundTextures[i] = 0; + } +} + +void TextureState::unbindTexture(GLuint texture) { + for (int i = 0; i < kTextureUnitsCount; i++) { + if (mBoundTextures[i] == texture) { + mBoundTextures[i] = 0; + } + } +} + +} /* namespace uirenderer */ +} /* namespace android */ + diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h new file mode 100644 index 0000000..5a57b9f --- /dev/null +++ b/libs/hwui/renderstate/TextureState.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RENDERSTATE_TEXTURESTATE_H +#define RENDERSTATE_TEXTURESTATE_H + +#include "Vertex.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <SkXfermode.h> +#include <memory> + +namespace android { +namespace uirenderer { + +class TextureState { + friend class Caches; // TODO: move to RenderState +public: + /** + * Activate the specified texture unit. The texture unit must + * be specified using an integer number (0 for GL_TEXTURE0 etc.) + */ + void activateTexture(GLuint textureUnit); + + /** + * Invalidate the cached value of the active texture unit. + */ + void resetActiveTexture(); + + /** + * Binds the specified texture as a GL_TEXTURE_2D texture. + * All texture bindings must be performed with this method or + * bindTexture(GLenum, GLuint). + */ + void bindTexture(GLuint texture); + + /** + * Binds the specified texture with the specified render target. + * All texture bindings must be performed with this method or + * bindTexture(GLuint). + */ + void bindTexture(GLenum target, GLuint texture); + + /** + * Deletes the specified texture and clears it from the cache + * of bound textures. + * All textures must be deleted using this method. + */ + void deleteTexture(GLuint texture); + + /** + * Signals that the cache of bound textures should be cleared. + * Other users of the context may have altered which textures are bound. + */ + void resetBoundTextures(); + + /** + * Clear the cache of bound textures. + */ + void unbindTexture(GLuint texture); +private: + // total number of texture units available for use + static const int kTextureUnitsCount = 3; + + TextureState(); + GLuint mTextureUnit; + + // Caches texture bindings for the GL_TEXTURE_2D target + GLuint mBoundTextures[kTextureUnitsCount]; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif // RENDERSTATE_BLEND_H |