Loading libs/hwui/OpenGLRenderer.cpp +50 −15 Original line number Diff line number Diff line Loading @@ -280,7 +280,49 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot } } /** * Layers are viewed by Skia are slightly different than layers in image editing * programs (for instance.) When a layer is created, previously created layers * and the frame buffer still receive every drawing command. For instance, if a * layer is created and a shape intersecting the bounds of the layers and the * framebuffer is draw, the shape will be drawn on both (unless the layer was * created with the SkCanvas::kClipToLayer_SaveFlag flag.) * * A way to implement layers is to create an FBO for each layer, backed by an RGBA * texture. Unfortunately, this is inefficient as it requires every primitive to * be drawn n + 1 times, where n is the number of active layers. In practice this * means, for every primitive: * - Switch active frame buffer * - Change viewport, clip and projection matrix * - Issue the drawing * * Switching rendering target n + 1 times per drawn primitive is extremely costly. * To avoid this, layers are implemented in a different way here. * * This implementation relies on the frame buffer being at least RGBA 8888. When * a layer is created, only a texture is created, not an FBO. The content of the * frame buffer contained within the layer's bounds is copied into this texture * using glCopyTexImage2D(). The layer's region is then cleared in the frame * buffer and drawing continues as normal. This technique therefore treats the * frame buffer as a scratch buffer for the layers. * * To compose the layers back onto the frame buffer, each layer texture * (containing the original frame buffer data) is drawn as a simple quad over * the frame buffer. The trick is that the quad is set as the composition * destination in the blending equation, and the frame buffer becomes the source * of the composition. * * Drawing layers with an alpha value requires an extra step before composition. * An empty quad is drawn over the layer's region in the frame buffer. This quad * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the * quad is used to multiply the colors in the frame buffer. This is achieved by * changing the GL blend functions for the GL_FUNC_ADD blend equation to * GL_ZERO, GL_SRC_ALPHA. * * Because glCopyTexImage2D() can be slow, an alternative implementation might * be use to draw a single clipped layer. The implementation described above * is correct in every case. */ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); Loading Loading @@ -323,6 +365,9 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, return true; } /** * Read the documentation of createLayer() before doing anything in this method. */ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { if (!current->layer) { LOGE("Attempting to compose a layer that does not exist"); Loading @@ -337,16 +382,8 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { const Rect& rect = layer->layer; if (layer->alpha < 255) { glEnable(GL_BLEND); glBlendFuncSeparate(GL_ZERO, GL_SRC_ALPHA, GL_DST_ALPHA, GL_ZERO); drawColorRect(rect.left, rect.top, rect.right, rect.bottom, layer->alpha << 24, SkXfermode::kSrcOver_Mode, true, true); glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); if (!mCaches.blend) { glDisable(GL_BLEND); } layer->alpha << 24, SkXfermode::kDstIn_Mode, true); } // Layers are already drawn with a top-left origin, don't flip the texture Loading Loading @@ -846,7 +883,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float } void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform, bool ignoreBlending) { int color, SkXfermode::Mode mode, bool ignoreTransform) { clearLayerRegions(); // If a shader is set, preserve only the alpha Loading @@ -872,10 +909,8 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mColorFilter->describe(description, mExtensions); } if (!ignoreBlending) { // Setup the blending mode chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode, description); } // Build and use the appropriate shader useProgram(mCaches.programCache.get(description)); Loading libs/hwui/OpenGLRenderer.h +1 −2 Original line number Diff line number Diff line Loading @@ -176,8 +176,7 @@ private: * @paran ignoreBlending True if the blending is set by the caller */ void drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform = false, bool ignoreBlending = false); int color, SkXfermode::Mode mode, bool ignoreTransform = false); /** * Draws a textured rectangle with the specified texture. The specified coordinates Loading Loading
libs/hwui/OpenGLRenderer.cpp +50 −15 Original line number Diff line number Diff line Loading @@ -280,7 +280,49 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot } } /** * Layers are viewed by Skia are slightly different than layers in image editing * programs (for instance.) When a layer is created, previously created layers * and the frame buffer still receive every drawing command. For instance, if a * layer is created and a shape intersecting the bounds of the layers and the * framebuffer is draw, the shape will be drawn on both (unless the layer was * created with the SkCanvas::kClipToLayer_SaveFlag flag.) * * A way to implement layers is to create an FBO for each layer, backed by an RGBA * texture. Unfortunately, this is inefficient as it requires every primitive to * be drawn n + 1 times, where n is the number of active layers. In practice this * means, for every primitive: * - Switch active frame buffer * - Change viewport, clip and projection matrix * - Issue the drawing * * Switching rendering target n + 1 times per drawn primitive is extremely costly. * To avoid this, layers are implemented in a different way here. * * This implementation relies on the frame buffer being at least RGBA 8888. When * a layer is created, only a texture is created, not an FBO. The content of the * frame buffer contained within the layer's bounds is copied into this texture * using glCopyTexImage2D(). The layer's region is then cleared in the frame * buffer and drawing continues as normal. This technique therefore treats the * frame buffer as a scratch buffer for the layers. * * To compose the layers back onto the frame buffer, each layer texture * (containing the original frame buffer data) is drawn as a simple quad over * the frame buffer. The trick is that the quad is set as the composition * destination in the blending equation, and the frame buffer becomes the source * of the composition. * * Drawing layers with an alpha value requires an extra step before composition. * An empty quad is drawn over the layer's region in the frame buffer. This quad * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the * quad is used to multiply the colors in the frame buffer. This is achieved by * changing the GL blend functions for the GL_FUNC_ADD blend equation to * GL_ZERO, GL_SRC_ALPHA. * * Because glCopyTexImage2D() can be slow, an alternative implementation might * be use to draw a single clipped layer. The implementation described above * is correct in every case. */ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); Loading Loading @@ -323,6 +365,9 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, return true; } /** * Read the documentation of createLayer() before doing anything in this method. */ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { if (!current->layer) { LOGE("Attempting to compose a layer that does not exist"); Loading @@ -337,16 +382,8 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { const Rect& rect = layer->layer; if (layer->alpha < 255) { glEnable(GL_BLEND); glBlendFuncSeparate(GL_ZERO, GL_SRC_ALPHA, GL_DST_ALPHA, GL_ZERO); drawColorRect(rect.left, rect.top, rect.right, rect.bottom, layer->alpha << 24, SkXfermode::kSrcOver_Mode, true, true); glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); if (!mCaches.blend) { glDisable(GL_BLEND); } layer->alpha << 24, SkXfermode::kDstIn_Mode, true); } // Layers are already drawn with a top-left origin, don't flip the texture Loading Loading @@ -846,7 +883,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float } void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform, bool ignoreBlending) { int color, SkXfermode::Mode mode, bool ignoreTransform) { clearLayerRegions(); // If a shader is set, preserve only the alpha Loading @@ -872,10 +909,8 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mColorFilter->describe(description, mExtensions); } if (!ignoreBlending) { // Setup the blending mode chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode, description); } // Build and use the appropriate shader useProgram(mCaches.programCache.get(description)); Loading
libs/hwui/OpenGLRenderer.h +1 −2 Original line number Diff line number Diff line Loading @@ -176,8 +176,7 @@ private: * @paran ignoreBlending True if the blending is set by the caller */ void drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform = false, bool ignoreBlending = false); int color, SkXfermode::Mode mode, bool ignoreTransform = false); /** * Draws a textured rectangle with the specified texture. The specified coordinates Loading