diff options
| -rw-r--r-- | libs/hwui/Layer.h | 16 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.cpp | 92 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.h | 5 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 55 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 34 | ||||
| -rw-r--r-- | libs/hwui/Snapshot.h | 2 |
6 files changed, 179 insertions, 25 deletions
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 7d54d3b3255d..bb2843790ed7 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" +#include "Vertex.h" namespace android { namespace uirenderer { @@ -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; } /** @@ -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 diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index a25c95ed6614..cd2554e14a4f 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -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); @@ -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) { diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index ed5d9609c001..f2fb898b21c7 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -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; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index b9332327df99..16a1de7adc32 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -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; @@ -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); @@ -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 } @@ -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 } @@ -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 } @@ -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 } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 56be13458e10..7387b9268c39 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -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: /** @@ -225,6 +230,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. * diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 9898df491eba..595ad4e92e3b 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -268,7 +268,7 @@ public: Rect* clipRect; /** - * The ancestor layer's dirty region.. + * The ancestor layer's dirty region. */ Region* region; |