diff options
Diffstat (limited to 'libs/hwui/FrameBuilder.cpp')
-rw-r--r-- | libs/hwui/FrameBuilder.cpp | 152 |
1 files changed, 108 insertions, 44 deletions
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 6fc74a585659..502f027029a7 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -31,18 +31,16 @@ namespace android { namespace uirenderer { -FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip, +FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, - const std::vector< sp<RenderNode> >& nodes, - const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches) - : mCanvasState(*this) + const LightGeometry& lightGeometry, Caches& caches) + : mStdAllocator(mAllocator) + , mLayerBuilders(mStdAllocator) + , mLayerStack(mStdAllocator) + , mCanvasState(*this) , mCaches(caches) , mLightRadius(lightGeometry.radius) - , mDrawFbo0(!nodes.empty()) { - ATRACE_NAME("prepare drawing commands"); - - mLayerBuilders.reserve(layers.entries().size()); - mLayerStack.reserve(layers.entries().size()); + , mDrawFbo0(true) { // Prepare to defer Fbo0 auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip)); @@ -51,7 +49,31 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip, mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, lightGeometry.center); +} + +FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, + const LightGeometry& lightGeometry, Caches& caches) + : mStdAllocator(mAllocator) + , mLayerBuilders(mStdAllocator) + , mLayerStack(mStdAllocator) + , mCanvasState(*this) + , mCaches(caches) + , mLightRadius(lightGeometry.radius) + , mDrawFbo0(false) { + // TODO: remove, with each layer on its own save stack + + // Prepare to defer Fbo0 (which will be empty) + auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1)); + mLayerBuilders.push_back(fbo0); + mLayerStack.push_back(0); + mCanvasState.initializeSaveStack(1, 1, + 0, 0, 1, 1, + lightGeometry.center); + deferLayers(layers); +} + +void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) { // Render all layers to be updated, in order. Defer in reverse order, so that they'll be // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse) for (int i = layers.entries().size() - 1; i >= 0; i--) { @@ -76,10 +98,45 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip, restoreForLayer(); } } +} + +void FrameBuilder::deferRenderNode(RenderNode& renderNode) { + renderNode.computeOrdering(); + + mCanvasState.save(SaveFlags::MatrixClip); + deferNodePropsAndOps(renderNode); + mCanvasState.restore(); +} + +void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode) { + renderNode.computeOrdering(); + mCanvasState.save(SaveFlags::MatrixClip); + mCanvasState.translate(tx, ty); + mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, + SkRegion::kIntersect_Op); + deferNodePropsAndOps(renderNode); + mCanvasState.restore(); +} + +static Rect nodeBounds(RenderNode& node) { + auto& props = node.properties(); + return Rect(props.getLeft(), props.getTop(), + props.getRight(), props.getBottom()); +} + +void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes, + const Rect& contentDrawBounds) { + if (nodes.size() < 1) return; + if (nodes.size() == 1) { + if (!nodes[0]->nothingToDraw()) { + deferRenderNode(*nodes[0]); + } + return; + } // It there are multiple render nodes, they are laid out as follows: // #0 - backdrop (content + caption) - // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds) + // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop) // #2 - additional overlay nodes // Usually the backdrop cannot be seen since it will be entirely covered by the content. While // resizing however it might become partially visible. The following render loop will crop the @@ -88,45 +145,52 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip, // // Additional nodes will be drawn on top with no particular clipping semantics. - // The bounds of the backdrop against which the content should be clipped. - Rect backdropBounds = contentDrawBounds; // Usually the contents bounds should be mContentDrawBounds - however - we will // move it towards the fixed edge to give it a more stable appearance (for the moment). // If there is no content bounds we ignore the layering as stated above and start with 2. - int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0; - - for (const sp<RenderNode>& node : nodes) { - if (node->nothingToDraw()) continue; - node->computeOrdering(); - int count = mCanvasState.save(SaveFlags::MatrixClip); - - if (layer == 0) { - const RenderProperties& properties = node->properties(); - Rect targetBounds(properties.getLeft(), properties.getTop(), - properties.getRight(), properties.getBottom()); - // Move the content bounds towards the fixed corner of the backdrop. - const int x = targetBounds.left; - const int y = targetBounds.top; - // Remember the intersection of the target bounds and the intersection bounds against - // which we have to crop the content. - backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight()); - backdropBounds.doIntersect(targetBounds); - } else if (layer == 1) { - // We shift and clip the content to match its final location in the window. - const float left = contentDrawBounds.left; - const float top = contentDrawBounds.top; - const float dx = backdropBounds.left - left; - const float dy = backdropBounds.top - top; - const float width = backdropBounds.getWidth(); - const float height = backdropBounds.getHeight(); - mCanvasState.translate(dx, dy); - // It gets cropped against the bounds of the backdrop to stay inside. - mCanvasState.clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op); + + // Backdrop bounds in render target space + const Rect backdrop = nodeBounds(*nodes[0]); + + // Bounds that content will fill in render target space (note content node bounds may be bigger) + Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight()); + content.translate(backdrop.left, backdrop.top); + if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) { + // Content doesn't entirely overlap backdrop, so fill around content (right/bottom) + + // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to + // also fill left/top. Currently, both 2up and freeform position content at the top/left of + // the backdrop, so this isn't necessary. + if (content.right < backdrop.right) { + // draw backdrop to right side of content + deferRenderNode(0, 0, Rect(content.right, backdrop.top, + backdrop.right, backdrop.bottom), *nodes[0]); + } + if (content.bottom < backdrop.bottom) { + // draw backdrop to bottom of content + // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill + deferRenderNode(0, 0, Rect(content.left, content.bottom, + content.right, backdrop.bottom), *nodes[0]); } + } + + if (!backdrop.isEmpty()) { + // content node translation to catch up with backdrop + float dx = contentDrawBounds.left - backdrop.left; + float dy = contentDrawBounds.top - backdrop.top; - deferNodePropsAndOps(*node); - mCanvasState.restoreToCount(count); - layer++; + Rect contentLocalClip = backdrop; + contentLocalClip.translate(dx, dy); + deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]); + } else { + deferRenderNode(*nodes[1]); + } + + // remaining overlay nodes, simply defer + for (size_t index = 2; index < nodes.size(); index++) { + if (!nodes[index]->nothingToDraw()) { + deferRenderNode(*nodes[index]); + } } } |