Loading libs/hwui/Layer.h +16 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" #include "Vertex.h" namespace android { namespace uirenderer { Loading @@ -41,6 +42,14 @@ namespace uirenderer { struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight): width(layerWidth), height(layerHeight) { mesh = NULL; meshIndices = NULL; meshElementCount = 0; } ~Layer() { if (mesh) delete mesh; if (meshIndices) delete meshIndices; } /** Loading Loading @@ -99,6 +108,13 @@ struct Layer { * Color filter used to draw this layer. Optional. */ SkiaColorFilter* colorFilter; /** * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; }; // struct Layer }; // namespace uirenderer Loading libs/hwui/LayerRenderer.cpp +91 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ namespace uirenderer { void LayerRenderer::prepare(bool opaque) { LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo); #if RENDER_LAYERS_AS_REGIONS mLayer->region.clear(); #endif glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo); glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); Loading @@ -39,11 +43,97 @@ void LayerRenderer::finish() { OpenGLRenderer::finish(); glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo); generateMesh(); LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo); } /////////////////////////////////////////////////////////////////////////////// // Static functions // Dirty region tracking /////////////////////////////////////////////////////////////////////////////// bool LayerRenderer::hasLayer() { return true; } Region* LayerRenderer::getRegion() { #if RENDER_LAYERS_AS_REGIONS if (getSnapshot()->flags & Snapshot::kFlagFboTarget) { return OpenGLRenderer::getRegion(); } return &mLayer->region; #else return OpenGLRenderer::getRegion(); #endif } void LayerRenderer::generateMesh() { #if RENDER_LAYERS_AS_REGIONS if (mLayer->region.isRect() || mLayer->region.isEmpty()) { if (mLayer->mesh) { delete mLayer->mesh; delete mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; mLayer->meshElementCount = 0; } return; } size_t count; const android::Rect* rects = mLayer->region.getArray(&count); GLsizei elementCount = count * 6; if (mLayer->mesh && mLayer->meshElementCount < elementCount) { delete mLayer->mesh; delete mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; } if (!mLayer->mesh) { mLayer->mesh = new TextureVertex[count * 4]; mLayer->meshIndices = new uint16_t[elementCount]; mLayer->meshElementCount = elementCount; } const float texX = 1.0f / float(mLayer->width); const float texY = 1.0f / float(mLayer->height); const float height = mLayer->layer.getHeight(); TextureVertex* mesh = mLayer->mesh; uint16_t* indices = mLayer->meshIndices; for (size_t i = 0; i < count; i++) { const android::Rect* r = &rects[i]; const float u1 = r->left * texX; const float v1 = (height - r->top) * texY; const float u2 = r->right * texX; const float v2 = (height - r->bottom) * texY; TextureVertex::set(mesh++, r->left, r->top, u1, v1); TextureVertex::set(mesh++, r->right, r->top, u2, v1); TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); uint16_t quad = i * 4; int index = i * 6; indices[index ] = quad; // top-left indices[index + 1] = quad + 1; // top-right indices[index + 2] = quad + 2; // bottom-left indices[index + 3] = quad + 2; // bottom-left indices[index + 4] = quad + 1; // top-right indices[index + 5] = quad + 3; // bottom-right } #endif } /////////////////////////////////////////////////////////////////////////////// // Layers management /////////////////////////////////////////////////////////////////////////////// Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { Loading libs/hwui/LayerRenderer.h +5 −0 Original line number Diff line number Diff line Loading @@ -49,12 +49,17 @@ public: void prepare(bool opaque); void finish(); bool hasLayer(); Region* getRegion(); static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void destroyLayer(Layer* layer); static void destroyLayerDeferred(Layer* layer); private: void generateMesh(); Layer* mLayer; GLuint mPreviousFbo; Loading libs/hwui/OpenGLRenderer.cpp +40 −15 Original line number Diff line number Diff line Loading @@ -615,6 +615,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const float alpha = layer->alpha / 255.0f; const float texX = 1.0f / float(layer->width); const float texY = 1.0f / float(layer->height); const float height = rect.getHeight(); TextureVertex* mesh = mCaches.getRegionMesh(); GLsizei numQuads = 0; Loading @@ -636,9 +637,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const android::Rect* r = &rects[i]; const float u1 = r->left * texX; const float v1 = (rect.getHeight() - r->top) * texY; const float v1 = (height - r->top) * texY; const float u2 = r->right * texX; const float v2 = (rect.getHeight() - r->bottom) * texY; const float v2 = (height - r->bottom) * texY; // TODO: Reject quads outside of the clip TextureVertex::set(mesh++, r->left, r->top, u1, v1); Loading Loading @@ -694,10 +695,10 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform) { #if RENDER_LAYERS_AS_REGIONS if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); dirtyLayerUnchecked(bounds, mSnapshot->region); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading @@ -705,9 +706,9 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top, void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom) { #if RENDER_LAYERS_AS_REGIONS if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { if (hasLayer()) { Rect bounds(left, top, right, bottom); dirtyLayerUnchecked(bounds, mSnapshot->region); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading Loading @@ -1419,24 +1420,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; bool hasActiveLayer = hasLayer(); #else bool hasLayer = false; bool hasActiveLayer = false; #endif mCaches.unbindMeshBuffer(); if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, hasLayer ? &bounds : NULL)) { hasActiveLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS if (hasLayer) { if (hasActiveLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } bounds.intersect(*mSnapshot->clipRect); bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); mSnapshot->region->orSelf(dirty); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading Loading @@ -1501,8 +1498,36 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { layer->alpha = alpha; layer->mode = mode; #if RENDER_LAYERS_AS_REGIONS if (layer->region.isRect()) { const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); composeLayerRect(layer, r); } else if (!layer->region.isEmpty() && layer->mesh) { const Rect& rect = layer->layer; setupDraw(); setupDrawWithTexture(); setupDrawColor(alpha, alpha, alpha, alpha); setupDrawColorFilter(); setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); setupDrawProgram(); setupDrawDirtyRegionsDisabled(); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawTexture(layer->texture); setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); glDrawElements(GL_TRIANGLES, layer->meshElementCount, GL_UNSIGNED_SHORT, layer->meshIndices); finishDrawTexture(); } #else const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); composeLayerRect(layer, r); #endif } /////////////////////////////////////////////////////////////////////////////// Loading libs/hwui/OpenGLRenderer.h +26 −8 Original line number Diff line number Diff line Loading @@ -133,19 +133,24 @@ protected: virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); /** * Mark the layer as dirty at the specified coordinates. The coordinates * are transformed with the supplied matrix. * Marks the specified region as dirty at the specified bounds. */ virtual void dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform); void dirtyLayerUnchecked(Rect& bounds, Region* region); /** * Mark the layer as dirty at the specified coordinates. * Returns the current snapshot. */ virtual void dirtyLayer(const float left, const float top, const float right, const float bottom); sp<Snapshot> getSnapshot() { return mSnapshot; } void dirtyLayerUnchecked(Rect& bounds, Region* region); virtual Region* getRegion() { return mSnapshot->region; } virtual bool hasLayer() { return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; } private: /** Loading Loading @@ -224,6 +229,19 @@ private: */ void clearLayerRegions(); /** * Mark the layer as dirty at the specified coordinates. The coordinates * are transformed with the supplied matrix. */ void dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform); /** * Mark the layer as dirty at the specified coordinates. */ void dirtyLayer(const float left, const float top, const float right, const float bottom); /** * Draws a colored rectangle with the specified color. The specified coordinates * are transformed by the current snapshot's transform matrix. Loading Loading
libs/hwui/Layer.h +16 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" #include "Vertex.h" namespace android { namespace uirenderer { Loading @@ -41,6 +42,14 @@ namespace uirenderer { struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight): width(layerWidth), height(layerHeight) { mesh = NULL; meshIndices = NULL; meshElementCount = 0; } ~Layer() { if (mesh) delete mesh; if (meshIndices) delete meshIndices; } /** Loading Loading @@ -99,6 +108,13 @@ struct Layer { * Color filter used to draw this layer. Optional. */ SkiaColorFilter* colorFilter; /** * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; }; // struct Layer }; // namespace uirenderer Loading
libs/hwui/LayerRenderer.cpp +91 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ namespace uirenderer { void LayerRenderer::prepare(bool opaque) { LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo); #if RENDER_LAYERS_AS_REGIONS mLayer->region.clear(); #endif glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo); glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); Loading @@ -39,11 +43,97 @@ void LayerRenderer::finish() { OpenGLRenderer::finish(); glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo); generateMesh(); LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo); } /////////////////////////////////////////////////////////////////////////////// // Static functions // Dirty region tracking /////////////////////////////////////////////////////////////////////////////// bool LayerRenderer::hasLayer() { return true; } Region* LayerRenderer::getRegion() { #if RENDER_LAYERS_AS_REGIONS if (getSnapshot()->flags & Snapshot::kFlagFboTarget) { return OpenGLRenderer::getRegion(); } return &mLayer->region; #else return OpenGLRenderer::getRegion(); #endif } void LayerRenderer::generateMesh() { #if RENDER_LAYERS_AS_REGIONS if (mLayer->region.isRect() || mLayer->region.isEmpty()) { if (mLayer->mesh) { delete mLayer->mesh; delete mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; mLayer->meshElementCount = 0; } return; } size_t count; const android::Rect* rects = mLayer->region.getArray(&count); GLsizei elementCount = count * 6; if (mLayer->mesh && mLayer->meshElementCount < elementCount) { delete mLayer->mesh; delete mLayer->meshIndices; mLayer->mesh = NULL; mLayer->meshIndices = NULL; } if (!mLayer->mesh) { mLayer->mesh = new TextureVertex[count * 4]; mLayer->meshIndices = new uint16_t[elementCount]; mLayer->meshElementCount = elementCount; } const float texX = 1.0f / float(mLayer->width); const float texY = 1.0f / float(mLayer->height); const float height = mLayer->layer.getHeight(); TextureVertex* mesh = mLayer->mesh; uint16_t* indices = mLayer->meshIndices; for (size_t i = 0; i < count; i++) { const android::Rect* r = &rects[i]; const float u1 = r->left * texX; const float v1 = (height - r->top) * texY; const float u2 = r->right * texX; const float v2 = (height - r->bottom) * texY; TextureVertex::set(mesh++, r->left, r->top, u1, v1); TextureVertex::set(mesh++, r->right, r->top, u2, v1); TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); uint16_t quad = i * 4; int index = i * 6; indices[index ] = quad; // top-left indices[index + 1] = quad + 1; // top-right indices[index + 2] = quad + 2; // bottom-left indices[index + 3] = quad + 2; // bottom-left indices[index + 4] = quad + 1; // top-right indices[index + 5] = quad + 3; // bottom-right } #endif } /////////////////////////////////////////////////////////////////////////////// // Layers management /////////////////////////////////////////////////////////////////////////////// Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { Loading
libs/hwui/LayerRenderer.h +5 −0 Original line number Diff line number Diff line Loading @@ -49,12 +49,17 @@ public: void prepare(bool opaque); void finish(); bool hasLayer(); Region* getRegion(); static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void destroyLayer(Layer* layer); static void destroyLayerDeferred(Layer* layer); private: void generateMesh(); Layer* mLayer; GLuint mPreviousFbo; Loading
libs/hwui/OpenGLRenderer.cpp +40 −15 Original line number Diff line number Diff line Loading @@ -615,6 +615,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const float alpha = layer->alpha / 255.0f; const float texX = 1.0f / float(layer->width); const float texY = 1.0f / float(layer->height); const float height = rect.getHeight(); TextureVertex* mesh = mCaches.getRegionMesh(); GLsizei numQuads = 0; Loading @@ -636,9 +637,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const android::Rect* r = &rects[i]; const float u1 = r->left * texX; const float v1 = (rect.getHeight() - r->top) * texY; const float v1 = (height - r->top) * texY; const float u2 = r->right * texX; const float v2 = (rect.getHeight() - r->bottom) * texY; const float v2 = (height - r->bottom) * texY; // TODO: Reject quads outside of the clip TextureVertex::set(mesh++, r->left, r->top, u1, v1); Loading Loading @@ -694,10 +695,10 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform) { #if RENDER_LAYERS_AS_REGIONS if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); dirtyLayerUnchecked(bounds, mSnapshot->region); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading @@ -705,9 +706,9 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top, void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom) { #if RENDER_LAYERS_AS_REGIONS if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { if (hasLayer()) { Rect bounds(left, top, right, bottom); dirtyLayerUnchecked(bounds, mSnapshot->region); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading Loading @@ -1419,24 +1420,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; bool hasActiveLayer = hasLayer(); #else bool hasLayer = false; bool hasActiveLayer = false; #endif mCaches.unbindMeshBuffer(); if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, hasLayer ? &bounds : NULL)) { hasActiveLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS if (hasLayer) { if (hasActiveLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } bounds.intersect(*mSnapshot->clipRect); bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); mSnapshot->region->orSelf(dirty); dirtyLayerUnchecked(bounds, getRegion()); } #endif } Loading Loading @@ -1501,8 +1498,36 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { layer->alpha = alpha; layer->mode = mode; #if RENDER_LAYERS_AS_REGIONS if (layer->region.isRect()) { const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); composeLayerRect(layer, r); } else if (!layer->region.isEmpty() && layer->mesh) { const Rect& rect = layer->layer; setupDraw(); setupDrawWithTexture(); setupDrawColor(alpha, alpha, alpha, alpha); setupDrawColorFilter(); setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); setupDrawProgram(); setupDrawDirtyRegionsDisabled(); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawTexture(layer->texture); setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); glDrawElements(GL_TRIANGLES, layer->meshElementCount, GL_UNSIGNED_SHORT, layer->meshIndices); finishDrawTexture(); } #else const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); composeLayerRect(layer, r); #endif } /////////////////////////////////////////////////////////////////////////////// Loading
libs/hwui/OpenGLRenderer.h +26 −8 Original line number Diff line number Diff line Loading @@ -133,19 +133,24 @@ protected: virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); /** * Mark the layer as dirty at the specified coordinates. The coordinates * are transformed with the supplied matrix. * Marks the specified region as dirty at the specified bounds. */ virtual void dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform); void dirtyLayerUnchecked(Rect& bounds, Region* region); /** * Mark the layer as dirty at the specified coordinates. * Returns the current snapshot. */ virtual void dirtyLayer(const float left, const float top, const float right, const float bottom); sp<Snapshot> getSnapshot() { return mSnapshot; } void dirtyLayerUnchecked(Rect& bounds, Region* region); virtual Region* getRegion() { return mSnapshot->region; } virtual bool hasLayer() { return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; } private: /** Loading Loading @@ -224,6 +229,19 @@ private: */ void clearLayerRegions(); /** * Mark the layer as dirty at the specified coordinates. The coordinates * are transformed with the supplied matrix. */ void dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform); /** * Mark the layer as dirty at the specified coordinates. */ void dirtyLayer(const float left, const float top, const float right, const float bottom); /** * Draws a colored rectangle with the specified color. The specified coordinates * are transformed by the current snapshot's transform matrix. Loading