diff options
26 files changed, 498 insertions, 345 deletions
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk index 7c1a724..de9ef06 100644 --- a/libs/hwui/Android.common.mk +++ b/libs/hwui/Android.common.mk @@ -7,11 +7,13 @@ LOCAL_CLANG_CFLAGS += \ LOCAL_SRC_FILES := \ font/CacheTexture.cpp \ font/Font.cpp \ + renderstate/Blend.cpp \ renderstate/MeshState.cpp \ renderstate/PixelBufferState.cpp \ renderstate/RenderState.cpp \ renderstate/Scissor.cpp \ renderstate/Stencil.cpp \ + renderstate/TextureState.cpp \ renderthread/CanvasContext.cpp \ renderthread/DrawFrameTask.cpp \ renderthread/EglManager.cpp \ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 1fb8092..cef2c84 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -49,6 +49,7 @@ Caches* Caches::sInstance = nullptr; Caches::Caches(RenderState& renderState) : patchCache(renderState) + , dither(*this) , mRenderState(&renderState) , mExtensions(Extensions::getInstance()) , mInitialized(false) { @@ -71,13 +72,8 @@ bool Caches::init() { ATRACE_NAME("Caches::init"); - glActiveTexture(gTextureUnits[0]); - mTextureUnit = 0; mRegionMesh = nullptr; - blend = false; - lastSrcMode = GL_ZERO; - lastDstMode = GL_ZERO; currentProgram = nullptr; mFunctorsCount = 0; @@ -90,8 +86,8 @@ bool Caches::init() { mInitialized = true; - resetBoundTextures(); - mPixelBufferState.reset(new PixelBufferState()); + mPixelBufferState = new PixelBufferState(); + mTextureState = new TextureState(); return true; } @@ -122,12 +118,6 @@ void Caches::initExtensions() { } void Caches::initConstraints() { - GLint maxTextureUnits; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { - ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); - } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); } @@ -216,8 +206,10 @@ void Caches::terminate() { clearGarbage(); - mPixelBufferState.release(); - + delete mPixelBufferState; + mPixelBufferState = nullptr; + delete mTextureState; + mTextureState = nullptr; mInitialized = false; } @@ -348,70 +340,6 @@ void Caches::flush(FlushMode mode) { } /////////////////////////////////////////////////////////////////////////////// -// Textures -/////////////////////////////////////////////////////////////////////////////// - -void Caches::activeTexture(GLuint textureUnit) { - if (mTextureUnit != textureUnit) { - glActiveTexture(gTextureUnits[textureUnit]); - mTextureUnit = textureUnit; - } -} - -void Caches::resetActiveTexture() { - mTextureUnit = -1; -} - -void Caches::bindTexture(GLuint texture) { - if (mBoundTextures[mTextureUnit] != texture) { - glBindTexture(GL_TEXTURE_2D, texture); - mBoundTextures[mTextureUnit] = texture; - } -} - -void Caches::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 Caches::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 Caches::resetBoundTextures() { - memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint)); -} - -void Caches::unbindTexture(GLuint texture) { - for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) { - if (mBoundTextures[i] == texture) { - mBoundTextures[i] = 0; - } - } -} - -/////////////////////////////////////////////////////////////////////////////// // Tiling /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 8d23833..f6d3476 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -33,6 +33,7 @@ #include "PathCache.h" #include "RenderBufferCache.h" #include "renderstate/PixelBufferState.h" +#include "renderstate/TextureState.h" #include "ResourceCache.h" #include "TessellationCache.h" #include "TextDropShadowCache.h" @@ -59,20 +60,6 @@ namespace uirenderer { class GammaFontRenderer; /////////////////////////////////////////////////////////////////////////////// -// Globals -/////////////////////////////////////////////////////////////////////////////// - -// GL ES 2.0 defines that at least 16 texture units must be supported -#define REQUIRED_TEXTURE_UNITS_COUNT 3 - -// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT -static const GLenum gTextureUnits[] = { - GL_TEXTURE0, - GL_TEXTURE1, - GL_TEXTURE2 -}; - -/////////////////////////////////////////////////////////////////////////////// // Caches /////////////////////////////////////////////////////////////////////////////// @@ -155,49 +142,6 @@ public: void deleteLayerDeferred(Layer* layer); - /** - * Activate the specified texture unit. The texture unit must - * be specified using an integer number (0 for GL_TEXTURE0 etc.) - */ - void activeTexture(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); - void startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard); void endTiling(); @@ -218,9 +162,6 @@ public: void registerFunctors(uint32_t functorCount); void unregisterFunctors(uint32_t functorCount); - bool blend; - GLenum lastSrcMode; - GLenum lastDstMode; Program* currentProgram; bool drawDeferDisabled; @@ -278,7 +219,8 @@ public: int propertyAmbientShadowStrength; int propertySpotShadowStrength; - PixelBufferState& pixelBuffer() { return *mPixelBufferState; } + PixelBufferState& pixelBufferState() { return *mPixelBufferState; } + TextureState& textureState() { return *mTextureState; } private: enum OverdrawColorSet { @@ -305,9 +247,8 @@ private: RenderState* mRenderState; - std::unique_ptr<PixelBufferState> mPixelBufferState; // TODO: move to RenderState - - GLuint mTextureUnit; + PixelBufferState* mPixelBufferState = nullptr; // TODO: move to RenderState + TextureState* mTextureState = nullptr; // TODO: move to RenderState Extensions& mExtensions; @@ -322,9 +263,6 @@ private: uint32_t mFunctorsCount; - // Caches texture bindings for the GL_TEXTURE_2D target - GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT]; - OverdrawColorSet mOverdrawDebugColorSet; }; // class Caches diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index 12d9389..d637ec1 100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp @@ -24,7 +24,10 @@ namespace uirenderer { // Lifecycle /////////////////////////////////////////////////////////////////////////////// -Dither::Dither(): mCaches(nullptr), mInitialized(false), mDitherTexture(0) { +Dither::Dither(Caches& caches) + : mCaches(caches) + , mInitialized(false) + , mDitherTexture(0) { } void Dither::bindDitherTexture() { @@ -32,7 +35,7 @@ void Dither::bindDitherTexture() { bool useFloatTexture = Extensions::getInstance().hasFloatTextures(); glGenTextures(1, &mDitherTexture); - mCaches->bindTexture(mDitherTexture); + mCaches.textureState().bindTexture(mDitherTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -71,13 +74,13 @@ void Dither::bindDitherTexture() { mInitialized = true; } else { - mCaches->bindTexture(mDitherTexture); + mCaches.textureState().bindTexture(mDitherTexture); } } void Dither::clear() { if (mInitialized) { - mCaches->deleteTexture(mDitherTexture); + mCaches.textureState().deleteTexture(mDitherTexture); mInitialized = false; } } @@ -87,10 +90,8 @@ void Dither::clear() { /////////////////////////////////////////////////////////////////////////////// void Dither::setupProgram(Program* program, GLuint* textureUnit) { - if (!mCaches) mCaches = &Caches::getInstance(); - GLuint textureSlot = (*textureUnit)++; - mCaches->activeTexture(textureSlot); + mCaches.textureState().activateTexture(textureSlot); bindDitherTexture(); diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h index 092ebf2..38633af 100644 --- a/libs/hwui/Dither.h +++ b/libs/hwui/Dither.h @@ -36,7 +36,7 @@ class Program; */ class Dither { public: - Dither(); + Dither(Caches& caches); void clear(); void setupProgram(Program* program, GLuint* textureUnit); @@ -44,7 +44,7 @@ public: private: void bindDitherTexture(); - Caches* mCaches; + Caches& mCaches; bool mInitialized; GLuint mDitherTexture; }; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 193474f..6dcd3e1 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -284,7 +284,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp uint32_t cacheWidth = cacheTexture->getWidth(); if (!cacheTexture->getPixelBuffer()) { - Caches::getInstance().activeTexture(0); + Caches::getInstance().textureState().activateTexture(0); // Large-glyph texture memory is allocated only as needed cacheTexture->allocateTexture(); } @@ -397,7 +397,7 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum for CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads); if (allocate) { - Caches::getInstance().activeTexture(0); + Caches::getInstance().textureState().activateTexture(0); cacheTexture->allocateTexture(); cacheTexture->allocateMesh(); } @@ -443,8 +443,8 @@ void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheText if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) { if (cacheTexture->getTextureId() != lastTextureId) { lastTextureId = cacheTexture->getTextureId(); - caches.activeTexture(0); - caches.bindTexture(lastTextureId); + caches.textureState().activateTexture(0); + caches.textureState().bindTexture(lastTextureId); } if (cacheTexture->upload()) { @@ -470,7 +470,7 @@ void FontRenderer::checkTextureUpdate() { checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId); // Unbind any PBO we might have used to update textures - caches.pixelBuffer().unbind(); + caches.pixelBufferState().unbind(); // Reset to default unpack row length to avoid affecting texture // uploads in other parts of the renderer @@ -507,11 +507,11 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) { forceRebind = renderState.meshState().unbindMeshBuffer(); } - caches.activeTexture(0); + caches.textureState().activateTexture(0); first = false; } - caches.bindTexture(texture->getTextureId()); + caches.textureState().bindTexture(texture->getTextureId()); texture->setLinearFiltering(mLinearFiltering, false); TextureVertex* mesh = texture->mesh(); @@ -649,7 +649,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions); // Unbind any PBO we might have used - Caches::getInstance().pixelBuffer().unbind(); + Caches::getInstance().pixelBufferState().unbind(); blurImage(&dataBuffer, paddedWidth, paddedHeight, radius); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 0987d9b..416b0b3 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -285,7 +285,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* memcpy(pixels + rowBytes, pixels, rowBytes); glGenTextures(1, &texture->id); - Caches::getInstance().bindTexture(texture->id); + Caches::getInstance().textureState().bindTexture(texture->id); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); if (mUseFloatTexture) { diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp index edf3930..a31c546 100644 --- a/libs/hwui/Image.cpp +++ b/libs/hwui/Image.cpp @@ -39,7 +39,7 @@ Image::Image(sp<GraphicBuffer> buffer) { } else { // Create a 2D texture to sample from the EGLImage glGenTextures(1, &mTexture); - Caches::getInstance().bindTexture(mTexture); + Caches::getInstance().textureState().bindTexture(mTexture); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage); GLenum status = GL_NO_ERROR; @@ -54,7 +54,7 @@ Image::~Image() { eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage); mImage = EGL_NO_IMAGE_KHR; - Caches::getInstance().deleteTexture(mTexture); + Caches::getInstance().textureState().deleteTexture(mTexture); mTexture = 0; } } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 7a4b830..7a026ef 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -134,7 +134,7 @@ bool Layer::resize(const uint32_t width, const uint32_t height) { setSize(desiredWidth, desiredHeight); if (fbo) { - caches.activeTexture(0); + caches.textureState().activateTexture(0); bindTexture(); allocateTexture(); @@ -195,7 +195,7 @@ void Layer::setColorFilter(SkColorFilter* filter) { void Layer::bindTexture() const { if (texture.id) { - caches.bindTexture(renderTarget, texture.id); + caches.textureState().bindTexture(renderTarget, texture.id); } } @@ -219,7 +219,7 @@ void Layer::deleteTexture() { } void Layer::clearTexture() { - caches.unbindTexture(texture.id); + caches.textureState().unbindTexture(texture.id); texture.id = 0; } diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 076251f..d2f9a94 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -196,7 +196,7 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width return nullptr; } - caches.activeTexture(0); + caches.textureState().activateTexture(0); Layer* layer = caches.layerCache.get(renderState, width, height); if (!layer) { ALOGW("Could not obtain a layer"); @@ -283,7 +283,7 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { layer->region.clear(); layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer() - Caches::getInstance().activeTexture(0); + Caches::getInstance().textureState().activateTexture(0); layer->generateTexture(); return layer; @@ -412,8 +412,8 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* glGenTextures(1, &texture); if ((error = glGetError()) != GL_NO_ERROR) goto error; - caches.activeTexture(0); - caches.bindTexture(texture); + caches.textureState().activateTexture(0); + caches.textureState().bindTexture(texture); glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); @@ -475,7 +475,7 @@ error: renderState.bindFramebuffer(previousFbo); layer->setAlpha(alpha, mode); layer->setFbo(previousLayerFbo); - caches.deleteTexture(texture); + caches.textureState().deleteTexture(texture); caches.fboCache.put(fbo); renderState.setViewport(previousViewportWidth, previousViewportHeight); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 42b246c..2378337 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -71,55 +71,6 @@ static GLenum getFilter(const SkPaint* paint) { // Globals /////////////////////////////////////////////////////////////////////////////// -/** - * Structure mapping Skia xfermodes to OpenGL blending factors. - */ -struct Blender { - SkXfermode::Mode mode; - GLenum src; - GLenum dst; -}; // struct Blender - -// In this array, the index of each Blender equals the value of the first -// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] -static const Blender gBlends[] = { - { 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. -static const Blender gBlendsSwap[] = { - { 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 } -}; /////////////////////////////////////////////////////////////////////////////// // Functions @@ -234,7 +185,7 @@ void OpenGLRenderer::prepareDirty(float left, float top, // for each layer and wait until the first drawing command // to start the frame if (currentSnapshot()->fbo == 0) { - syncState(); + mRenderState.blend().syncEnabled(); updateLayers(); } else { startFrame(); @@ -267,14 +218,6 @@ void OpenGLRenderer::clear(float left, float top, float right, float bottom, boo mRenderState.scissor().reset(); } -void OpenGLRenderer::syncState() { - if (mCaches.blend) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } -} - void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) { if (!mSuppressTiling) { const Snapshot* snapshot = currentSnapshot(); @@ -559,7 +502,7 @@ void OpenGLRenderer::cancelLayerUpdate(Layer* layer) { void OpenGLRenderer::flushLayerUpdates() { ATRACE_NAME("Update HW Layers"); - syncState(); + mRenderState.blend().syncEnabled(); updateLayers(); flushLayers(); // Wait for all the layer updates to be executed @@ -756,7 +699,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto return false; } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight()); if (!layer) { return false; @@ -896,7 +839,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto mRenderState.meshState().unbindMeshBuffer(); - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); // When the layer is stored in an FBO, we can save a bit of fillrate by // drawing only the dirty region @@ -1898,13 +1841,13 @@ void OpenGLRenderer::setupDrawSimpleMesh() { } void OpenGLRenderer::setupDrawTexture(GLuint texture) { - if (texture) bindTexture(texture); + if (texture) mCaches.textureState().bindTexture(texture); mTextureUnit++; mRenderState.meshState().enableTexCoordsVertexArray(); } void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { - bindExternalTexture(texture); + mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture); mTextureUnit++; mRenderState.meshState().enableTexCoordsVertexArray(); } @@ -2050,7 +1993,7 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount, TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); if (!texture) return; @@ -2081,7 +2024,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { return; } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = getTexture(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -2122,7 +2065,7 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m colors = tempColors.get(); } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); const UvMapper& mapper(getMapper(texture)); @@ -2217,7 +2160,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, return; } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = getTexture(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -2317,7 +2260,7 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, } if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -2371,7 +2314,7 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, */ void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -2556,7 +2499,7 @@ void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bot } if (p->getPathEffect() != nullptr) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.getRoundRect( right - left, bottom - top, rx, ry, p); drawShape(left, top, texture, p); @@ -2574,7 +2517,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p return; } if (p->getPathEffect() != nullptr) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.getCircle(radius, p); drawShape(x - radius, y - radius, texture, p); } else { @@ -2597,7 +2540,7 @@ void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, } if (p->getPathEffect() != nullptr) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); drawShape(left, top, texture, p); } else { @@ -2621,7 +2564,7 @@ void OpenGLRenderer::drawArc(float left, float top, float right, float bottom, // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, startAngle, sweepAngle, useCenter, p); drawShape(left, top, texture, p); @@ -2658,7 +2601,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, // only fill style is supported by drawConvexPath, since others have to handle joins if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join || p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.getRect(right - left, bottom - top, p); drawShape(left, top, texture, p); @@ -2687,7 +2630,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, int bytesCount, int count, const float* positions, FontRenderer& fontRenderer, int alpha, float x, float y) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); TextShadow textShadow; if (!getTextShadow(paint, &textShadow)) { @@ -3001,7 +2944,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { if (mState.currentlyIgnored()) return; - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); const PathTexture* texture = mCaches.pathCache.get(path, paint); if (!texture) return; @@ -3046,7 +2989,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { updateLayer(layer, true); mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); if (CC_LIKELY(!layer->region.isEmpty())) { if (layer->region.isRect()) { @@ -3485,33 +3428,16 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, description.framebufferMode = mode; description.swapSrcDst = swapSrcDst; - if (mCaches.blend) { - glDisable(GL_BLEND); - mCaches.blend = false; - } - + mRenderState.blend().disable(); return; } else { mode = SkXfermode::kSrcOver_Mode; } } - - if (!mCaches.blend) { - glEnable(GL_BLEND); - } - - GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; - GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; - - if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { - glBlendFunc(sourceMode, destMode); - mCaches.lastSrcMode = sourceMode; - mCaches.lastDstMode = destMode; - } - } else if (mCaches.blend) { - glDisable(GL_BLEND); + mRenderState.blend().enable(mode, swapSrcDst); + } else { + mRenderState.blend().disable(); } - mCaches.blend = blend; } bool OpenGLRenderer::useProgram(Program* program) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 94054ff..cf6f0c8 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -541,12 +541,6 @@ private: void discardFramebuffer(float left, float top, float right, float bottom); /** - * Ensures the state of the renderer is the same as the state of - * the GL context. - */ - void syncState(); - - /** * Tells the GPU what part of the screen is about to be redrawn. * This method will use the current layer space clip rect. * This method needs to be invoked every time getTargetFbo() is @@ -852,22 +846,6 @@ private: bool canSkipText(const SkPaint* paint) const; /** - * Binds the specified texture. The texture unit must have been selected - * prior to calling this method. - */ - inline void bindTexture(GLuint texture) { - mCaches.bindTexture(texture); - } - - /** - * Binds the specified EGLImage texture. The texture unit must have been selected - * prior to calling this method. - */ - inline void bindExternalTexture(GLuint texture) { - mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture); - } - - /** * Enable or disable blending as necessary. This function sets the appropriate * blend function based on the specified xfermode. */ diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index cc7f88d..d6eff85 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -230,7 +230,7 @@ void PathCache::removeTexture(PathTexture* texture) { } if (texture->id) { - Caches::getInstance().deleteTexture(texture->id); + Caches::getInstance().textureState().deleteTexture(texture->id); } delete texture; } @@ -312,7 +312,7 @@ void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) { glGenTextures(1, &texture->id); - Caches::getInstance().bindTexture(texture->id); + Caches::getInstance().textureState().bindTexture(texture->id); // Textures are Alpha8 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp index 62eb68c..9665a68 100644 --- a/libs/hwui/PixelBuffer.cpp +++ b/libs/hwui/PixelBuffer.cpp @@ -101,9 +101,9 @@ GpuPixelBuffer::GpuPixelBuffer(GLenum format, , mCaches(Caches::getInstance()){ glGenBuffers(1, &mBuffer); - mCaches.pixelBuffer().bind(mBuffer); + mCaches.pixelBufferState().bind(mBuffer); glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW); - mCaches.pixelBuffer().unbind(); + mCaches.pixelBufferState().unbind(); } GpuPixelBuffer::~GpuPixelBuffer() { @@ -112,7 +112,7 @@ GpuPixelBuffer::~GpuPixelBuffer() { uint8_t* GpuPixelBuffer::map(AccessMode mode) { if (mAccessMode == kAccessMode_None) { - mCaches.pixelBuffer().bind(mBuffer); + mCaches.pixelBufferState().bind(mBuffer); mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); #if DEBUG_OPENGL if (!mMappedPointer) { @@ -131,7 +131,7 @@ uint8_t* GpuPixelBuffer::map(AccessMode mode) { void GpuPixelBuffer::unmap() { if (mAccessMode != kAccessMode_None) { if (mMappedPointer) { - mCaches.pixelBuffer().bind(mBuffer); + mCaches.pixelBufferState().bind(mBuffer); GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); if (status == GL_FALSE) { ALOGE("Corrupted GPU pixel buffer"); @@ -148,7 +148,7 @@ uint8_t* GpuPixelBuffer::getMappedPointer() const { void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { // If the buffer is not mapped, unmap() will not bind it - mCaches.pixelBuffer().bind(mBuffer); + mCaches.pixelBufferState().bind(mBuffer); unmap(); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset)); diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 2c09344..e13c861 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -57,7 +57,7 @@ static inline void bindUniformColor(int slot, uint32_t color) { } static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { - caches->bindTexture(texture->id); + caches->textureState().bindTexture(texture->id); texture->setWrapST(wrapS, wrapT); } @@ -176,7 +176,7 @@ void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, } GLuint textureSlot = (*textureUnit)++; - caches->activeTexture(textureSlot); + caches->textureState().activateTexture(textureSlot); const float width = layer->getWidth(); const float height = layer->getHeight(); @@ -270,7 +270,7 @@ void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, } GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); + Caches::getInstance().textureState().activateTexture(textureSlot); BitmapShaderInfo shaderInfo; if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) { @@ -392,7 +392,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri shader.asAGradient(&gradInfo); } GLuint textureSlot = (*textureUnit)++; - caches->activeTexture(textureSlot); + caches->textureState().activateTexture(textureSlot); #ifndef SK_SCALAR_IS_FLOAT #error Need to convert gradInfo.fColorOffsets to float! diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 4ec298d..c2e88f3 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -207,7 +207,7 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* text, glGenTextures(1, &texture->id); - caches.bindTexture(texture->id); + caches.textureState().bindTexture(texture->id); // Textures are Alpha8 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 58fd972..512f5cf 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -24,18 +24,44 @@ namespace android { namespace uirenderer { -Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0), - cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false), - mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE), - mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST), - mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) { +Texture::Texture() + : id(0) + , generation(0) + , blend(false) + , width(0) + , height(0) + , cleanup(false) + , bitmapSize(0) + , mipMap(false) + , uvMapper(nullptr) + , isInUse(false) + , mWrapS(GL_CLAMP_TO_EDGE) + , mWrapT(GL_CLAMP_TO_EDGE) + , mMinFilter(GL_NEAREST) + , mMagFilter(GL_NEAREST) + , mFirstFilter(true) + , mFirstWrap(true) + , mCaches(Caches::getInstance()) { } -Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0), - cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false), - mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE), - mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST), - mFirstFilter(true), mFirstWrap(true), mCaches(caches) { +Texture::Texture(Caches& caches) + : id(0) + , generation(0) + , blend(false) + , width(0) + , height(0) + , cleanup(false) + , bitmapSize(0) + , mipMap(false) + , uvMapper(nullptr) + , isInUse(false) + , mWrapS(GL_CLAMP_TO_EDGE) + , mWrapT(GL_CLAMP_TO_EDGE) + , mMinFilter(GL_NEAREST) + , mMagFilter(GL_NEAREST) + , mFirstFilter(true) + , mFirstWrap(true) + , mCaches(caches) { } void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force, @@ -48,7 +74,7 @@ void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force mWrapT = wrapT; if (bindTexture) { - mCaches.bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, id); } glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); @@ -66,7 +92,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for mMagFilter = mag; if (bindTexture) { - mCaches.bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, id); } if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR; @@ -77,7 +103,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for } void Texture::deleteTexture() const { - mCaches.deleteTexture(id); + mCaches.textureState().deleteTexture(id); } }; // namespace uirenderer diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 524f206..fe8fb5b 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -296,7 +296,7 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo texture->width = bitmap->width(); texture->height = bitmap->height(); - Caches::getInstance().bindTexture(texture->id); + Caches::getInstance().textureState().bindTexture(texture->id); switch (bitmap->colorType()) { case kAlpha_8_SkColorType: diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 128e392..53fa0dc 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -157,7 +157,7 @@ void CacheTexture::releaseTexture() { mTexture = nullptr; } if (mTextureId) { - mCaches.deleteTexture(mTextureId); + mCaches.textureState().deleteTexture(mTextureId); mTextureId = 0; } mDirty = false; @@ -169,7 +169,7 @@ void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) { mLinearFiltering = linearFiltering; const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; - if (bind) mCaches.bindTexture(getTextureId()); + if (bind) mCaches.textureState().bindTexture(getTextureId()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); } @@ -189,7 +189,7 @@ void CacheTexture::allocateTexture() { if (!mTextureId) { glGenTextures(1, &mTextureId); - mCaches.bindTexture(mTextureId); + mCaches.textureState().bindTexture(mTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Initialize texture dimensions glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, 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 diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index c4feb41..f2337cb 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -214,9 +214,6 @@ void EglManager::destroy() { if (mEglDisplay == EGL_NO_DISPLAY) return; usePBufferSurface(); - if (Caches::hasInstance()) { - Caches::getInstance().terminate(); - } mRenderThread.renderState().onGLContextDestroyed(); eglDestroyContext(mEglDisplay, mEglContext); |