OSDN Git Service

Rework receiver/dispatcher design slightly, and replace Layer usage.
authorChris Craik <ccraik@google.com>
Mon, 26 Oct 2015 22:49:56 +0000 (15:49 -0700)
committerChris Craik <ccraik@google.com>
Tue, 27 Oct 2015 23:44:50 +0000 (16:44 -0700)
Switched from 'renderer/info' to 'dispatcher/renderer' to make their
interaction more natural. The new BakedOpRenderer is more similar in
responsibilities to the OpenGLRenderer, as it manages layer and frame
lifecycles, and performs the actual rendering.

However, it's still simpler because the BakedOpDispatcher handles
mapping Canvas drawing ops to Glops, and the OpReorderer handles almost
all canvas state operations.

Also switch BakedOpRenderer to use the new OffscreenBuffer, which
serves as a lightweight Layer replacement, with a much simpler
lifecycle.

Change-Id: Ie0e2e248503400041d49729d813d485d28c76eb3

libs/hwui/BakedOpRenderer.cpp
libs/hwui/BakedOpRenderer.h
libs/hwui/OpReorderer.cpp
libs/hwui/OpReorderer.h
libs/hwui/RecordedOp.h
libs/hwui/microbench/OpReordererBench.cpp
libs/hwui/renderstate/RenderState.h
libs/hwui/renderthread/CanvasContext.cpp
libs/hwui/unit_tests/OpReordererTests.cpp

index 7dbba25..0868853 100644 (file)
 namespace android {
 namespace uirenderer {
 
-void BakedOpRenderer::Info::setViewport(uint32_t width, uint32_t height) {
-    viewportWidth = width;
-    viewportHeight = height;
-    orthoMatrix.loadOrtho(viewportWidth, viewportHeight);
-
-    renderState.setViewport(width, height);
-    renderState.blend().syncEnabled();
-}
-
-Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) {
-    Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap);
-    if (!texture) {
-        return caches.textureCache.get(bitmap);
-    }
-    return texture;
-}
-
-void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) {
-    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
-    renderState.scissor().setEnabled(useScissor);
-    if (useScissor) {
-        const Rect& clip = state.computedState.clipRect;
-        renderState.scissor().set(clip.left, viewportHeight - clip.bottom,
-            clip.getWidth(), clip.getHeight());
-    }
-    renderState.render(glop, orthoMatrix);
-    didDraw = true;
+////////////////////////////////////////////////////////////////////////////////
+// OffscreenBuffer
+////////////////////////////////////////////////////////////////////////////////
+
+OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight,
+        uint32_t viewportWidth, uint32_t viewportHeight)
+        : texture(caches)
+        , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) {
+    texture.width = textureWidth;
+    texture.height = textureHeight;
+
+    caches.textureState().activateTexture(0);
+    glGenTextures(1, &texture.id);
+    caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
+
+    texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
+    // not setting filter on texture, since it's set when drawing, based on transform
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
+            GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
 }
 
-Layer* BakedOpRenderer::startLayer(Info& info, uint32_t width, uint32_t height) {
-    info.caches.textureState().activateTexture(0);
-    Layer* layer = info.caches.layerCache.get(info.renderState, width, height);
-    LOG_ALWAYS_FATAL_IF(!layer, "need layer...");
+////////////////////////////////////////////////////////////////////////////////
+// BakedOpRenderer
+////////////////////////////////////////////////////////////////////////////////
 
-    info.layer = layer;
-    layer->texCoords.set(0.0f, width / float(layer->getHeight()),
-            height / float(layer->getWidth()), 0.0f);
+OffscreenBuffer* BakedOpRenderer::startLayer(uint32_t width, uint32_t height) {
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
 
-    layer->setFbo(info.renderState.genFramebuffer());
-    info.renderState.bindFramebuffer(layer->getFbo());
-    layer->bindTexture();
+    // TODO: really should be caching these!
+    OffscreenBuffer* buffer = new OffscreenBuffer(mCaches, width, height, width, height);
+    mRenderTarget.offscreenBuffer = buffer;
 
-    // Initialize the texture if needed
-    if (layer->isEmpty()) {
-        layer->allocateTexture();
-        layer->setEmpty(false);
-    }
+    // create and bind framebuffer
+    mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
+    mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
 
     // attach the texture to the FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            layer->getTextureId(), 0);
+            buffer->texture.id, 0);
     LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
     LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
             "framebuffer incomplete!");
 
     // Clear the FBO
-    info.renderState.scissor().setEnabled(false);
+    mRenderState.scissor().setEnabled(false);
     glClear(GL_COLOR_BUFFER_BIT);
 
     // Change the viewport & ortho projection
-    info.setViewport(width, height);
-    return layer;
+    setViewport(width, height);
+    return buffer;
 }
 
-void BakedOpRenderer::endLayer(Info& info) {
-    Layer* layer = info.layer;
-    info.layer = nullptr;
+void BakedOpRenderer::endLayer() {
+    mRenderTarget.offscreenBuffer = nullptr;
 
     // Detach the texture from the FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
     LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
-    layer->removeFbo(false);
+    mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
+    mRenderTarget.frameBufferId = -1;
 }
 
-void BakedOpRenderer::startFrame(Info& info, uint32_t width, uint32_t height) {
-    info.renderState.bindFramebuffer(0);
-    info.setViewport(width, height);
-    Caches::getInstance().clearGarbage();
+void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
+    mRenderState.bindFramebuffer(0);
+    setViewport(width, height);
+    mCaches.clearGarbage();
 
-    if (!info.opaque) {
+    if (!mOpaque) {
         // TODO: partial invalidate!
-        info.renderState.scissor().setEnabled(false);
+        mRenderState.scissor().setEnabled(false);
         glClear(GL_COLOR_BUFFER_BIT);
-        info.didDraw = true;
+        mHasDrawn = true;
     }
 }
-void BakedOpRenderer::endFrame(Info& info) {
-    info.caches.pathCache.trim();
-    info.caches.tessellationCache.trim();
+
+void BakedOpRenderer::endFrame() {
+    mCaches.pathCache.trim();
+    mCaches.tessellationCache.trim();
 
 #if DEBUG_OPENGL
     GLUtils::dumpGLErrors();
 #endif
 
 #if DEBUG_MEMORY_USAGE
-    info.caches.dumpMemoryUsage();
+    mCaches.dumpMemoryUsage();
 #else
     if (Properties::debugLevel & kDebugMemory) {
-        info.caches.dumpMemoryUsage();
+        mCaches.dumpMemoryUsage();
     }
 #endif
 }
 
-void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) {
+void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
+    mRenderTarget.viewportWidth = width;
+    mRenderTarget.viewportHeight = height;
+    mRenderTarget.orthoMatrix.loadOrtho(width, height);
+
+    mRenderState.setViewport(width, height);
+    mRenderState.blend().syncEnabled();
+}
+
+Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
+    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
+    if (!texture) {
+        return mCaches.textureCache.get(bitmap);
+    }
+    return texture;
+}
+
+void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
+    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
+    mRenderState.scissor().setEnabled(useScissor);
+    if (useScissor) {
+        const Rect& clip = state.computedState.clipRect;
+        mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
+            clip.getWidth(), clip.getHeight());
+    }
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    mHasDrawn = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static BakedOpDispatcher methods
+////////////////////////////////////////////////////////////////////////////////
+
+void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) {
-    info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
-    Texture* texture = info.getTexture(op.bitmap);
+void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
+    renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
+    Texture* texture = renderer.getTexture(op.bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
     const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshUnitQuad()
             .setFillPaint(*op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRect(op.unmappedBounds)
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
             .setFillPaint(*op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewOffsetRect(0, 0, op.unmappedBounds)
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) {
-    Layer* layer = *op.layerHandle;
-
-    // TODO: make this work for HW layers
-    layer->setPaint(op.paint);
-    layer->setBlend(true);
-    float layerAlpha = (layer->getAlpha() / 255.0f) * state.alpha;
+void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
+    OffscreenBuffer* buffer = *op.layerHandle;
 
+    // TODO: extend this to handle HW layers & paint properties which
+    // reside in node.properties().layerProperties()
+    float layerAlpha = (op.paint->getAlpha() / 255.0f) * state.alpha;
     const bool tryToSnap = state.computedState.transform.isPureTranslate();
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
-            .setMeshTexturedUvQuad(nullptr, layer->texCoords)
-            .setFillLayer(layer->getTexture(), layer->getColorFilter(), layerAlpha, layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+            .setMeshTexturedUvQuad(nullptr, buffer->texCoords)
+            .setFillLayer(buffer->texture, op.paint->getColorFilter(), layerAlpha, PaintUtils::getXfermodeDirect(op.paint), Blend::ModeOrderSwap::NoSwap)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
             .build();
-    info.renderGlop(state, glop);
-
-    // return layer to cache, since each clipped savelayer is only drawn once.
-    layer->setConvexMask(nullptr);
-    if (!info.caches.layerCache.put(layer)) {
-        // Failing to add the layer to the cache should happen only if the layer is too large
-        LAYER_LOGD("Deleting layer");
-        layer->decStrong(nullptr);
-    }
+    renderer.renderGlop(state, glop);
+
+    // destroy and delete, since each clipped saveLayer is only drawn once.
+    buffer->texture.deleteTexture();
+
+    // TODO: return texture/offscreenbuffer to cache!
+    delete buffer;
 }
 
 } // namespace uirenderer
index 616adde..16afad4 100644 (file)
@@ -28,48 +28,82 @@ struct Glop;
 class Layer;
 class RenderState;
 
+/**
+ * Lightweight alternative to Layer. Owns the persistent state of an offscreen render target, and
+ * encompasses enough information to draw it back on screen (minus paint properties, which are held
+ * by LayerOp).
+ */
+class OffscreenBuffer {
+public:
+    OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight,
+            uint32_t viewportWidth, uint32_t viewportHeight);
+
+    Texture texture;
+    Rect texCoords;
+    Region region;
+};
+
+/**
+ * Main rendering manager for a collection of work - one frame + any contained FBOs.
+ *
+ * Manages frame and FBO lifecycle, binding the GL framebuffer as appropriate. This is the only
+ * place where FBOs are bound, created, and destroyed.
+ *
+ * All rendering operations will be sent by the Dispatcher, a collection of static methods,
+ * which has intentionally limited access to the renderer functionality.
+ */
 class BakedOpRenderer {
 public:
-    class Info {
-    public:
-        Info(Caches& caches, RenderState& renderState, bool opaque)
-                : renderState(renderState)
-                , caches(caches)
-                , opaque(opaque) {
-        }
+    BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque)
+            : mRenderState(renderState)
+            , mCaches(caches)
+            , mOpaque(opaque) {
+    }
 
-        void setViewport(uint32_t width, uint32_t height);
+    RenderState& renderState() { return mRenderState; }
+    Caches& caches() { return mCaches; }
 
-        Texture* getTexture(const SkBitmap* bitmap);
+    void startFrame(uint32_t width, uint32_t height);
+    void endFrame();
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height);
+    void endLayer();
 
-        void renderGlop(const BakedOpState& state, const Glop& glop);
-        RenderState& renderState;
-        Caches& caches;
+    Texture* getTexture(const SkBitmap* bitmap);
 
-        bool didDraw = false;
+    void renderGlop(const BakedOpState& state, const Glop& glop);
+    bool didDraw() { return mHasDrawn; }
+private:
+    void setViewport(uint32_t width, uint32_t height);
 
-        Layer* layer = nullptr;
+    RenderState& mRenderState;
+    Caches& mCaches;
+    bool mOpaque;
+    bool mHasDrawn = false;
 
-        // where should these live? layer state object?
-        bool opaque;
+    // render target state - setup by start/end layer/frame
+    // only valid to use in between start/end pairs.
+    struct {
+        GLuint frameBufferId = 0;
+        OffscreenBuffer* offscreenBuffer = nullptr;
         uint32_t viewportWidth = 0;
         uint32_t viewportHeight = 0;
         Matrix4 orthoMatrix;
-    };
-
-    static Layer* startLayer(Info& info, uint32_t width, uint32_t height);
-    static void endLayer(Info& info);
-    static void startFrame(Info& info, uint32_t width, uint32_t height);
-    static void endFrame(Info& info);
-
-    /**
-     * Declare all "onBitmapOp(...)" style function for every op type.
-     *
-     * These functions will perform the actual rendering of the individual operations in OpenGL,
-     * given the transform/clip and other state built into the BakedOpState object passed in.
-     */
-    #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info& info, const Type& op, const BakedOpState& state);
-    MAP_OPS(BAKED_OP_RENDERER_METHOD);
+    } mRenderTarget;
+};
+
+/**
+ * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the
+ * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer.
+ *
+ * This dispatcher is separate from the renderer so that the dispatcher / renderer interaction is
+ * minimal through public BakedOpRenderer APIs.
+ */
+class BakedOpDispatcher {
+public:
+    // Declares all "onBitmapOp(...)" style methods for every op type
+#define DISPATCH_METHOD(Type) \
+        static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
+    MAP_OPS(DISPATCH_METHOD);
 };
 
 }; // namespace uirenderer
index cde42f8..ddeb336 100644 (file)
@@ -277,7 +277,8 @@ void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator,
     }
 }
 
-void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const {
+void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const {
+    ATRACE_NAME("flush drawing commands");
     for (const BatchBase* batch : mBatches) {
         // TODO: different behavior based on batch->isMerging()
         for (const BakedOpState* op : batch->getOps()) {
@@ -353,10 +354,6 @@ void OpReorderer::deferImpl(const DisplayList& displayList) {
     }
 }
 
-void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) {
-    ATRACE_NAME("flush drawing commands");
-}
-
 void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
     if (op.renderNode->nothingToDraw()) {
         return;
@@ -435,7 +432,7 @@ void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
             beginLayerOp.localMatrix,
             beginLayerOp.localClipRect,
             beginLayerOp.paint,
-            &mLayerReorderers[finishedLayerIndex].layer);
+            &mLayerReorderers[finishedLayerIndex].offscreenBuffer);
     BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
 
     if (bakedOpState) {
index f32b858..927ecfa 100644 (file)
@@ -33,6 +33,7 @@ namespace uirenderer {
 class BakedOpState;
 class BatchBase;
 class MergingOpBatch;
+class OffscreenBuffer;
 class OpBatch;
 class Rect;
 
@@ -55,7 +56,7 @@ namespace OpBatchType {
 }
 
 class OpReorderer : public CanvasStateClient {
-    typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
+    typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpDispatcher;
 
     /**
      * Stores the deferred render operations and state used to compute ordering
@@ -79,7 +80,7 @@ class OpReorderer : public CanvasStateClient {
         void deferMergeableOp(LinearAllocator& allocator,
                 BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
 
-        void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const;
+        void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const;
 
         bool empty() const {
             return mBatches.empty();
@@ -91,7 +92,7 @@ class OpReorderer : public CanvasStateClient {
 
         void dump() const;
 
-        Layer* layer = nullptr;
+        OffscreenBuffer* offscreenBuffer = nullptr;
         const BeginLayerOp* beginLayerOp = nullptr;
         const uint32_t width;
         const uint32_t height;
@@ -127,15 +128,15 @@ public:
      *
      * For example a BitmapOp would resolve, via the lambda lookup, to calling:
      *
-     * StaticReceiver::onBitmapOp(Arg* arg, const BitmapOp& op, const BakedOpState& state);
+     * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
      */
 #define BAKED_OP_RECEIVER(Type) \
-    [](void* internalArg, const RecordedOp& op, const BakedOpState& state) { \
-        StaticReceiver::on##Type(*(static_cast<Arg*>(internalArg)), static_cast<const Type&>(op), state); \
+    [](void* internalRenderer, const RecordedOp& op, const BakedOpState& state) { \
+        StaticDispatcher::on##Type(*(static_cast<Renderer*>(internalRenderer)), static_cast<const Type&>(op), state); \
     },
-    template <typename StaticReceiver, typename Arg>
-    void replayBakedOps(Arg& arg) {
-        static BakedOpReceiver receivers[] = {
+    template <typename StaticDispatcher, typename Renderer>
+    void replayBakedOps(Renderer& renderer) {
+        static BakedOpDispatcher receivers[] = {
             MAP_OPS(BAKED_OP_RECEIVER)
         };
 
@@ -144,16 +145,16 @@ public:
         for (int i = mLayerReorderers.size() - 1; i >= 1; i--) {
             LayerReorderer& layer = mLayerReorderers[i];
             if (!layer.empty()) {
-                layer.layer = StaticReceiver::startLayer(arg, layer.width, layer.height);
-                layer.replayBakedOpsImpl((void*)&arg, receivers);
-                StaticReceiver::endLayer(arg);
+                layer.offscreenBuffer = renderer.startLayer(layer.width, layer.height);
+                layer.replayBakedOpsImpl((void*)&renderer, receivers);
+                renderer.endLayer();
             }
         }
 
         const LayerReorderer& fbo0 = mLayerReorderers[0];
-        StaticReceiver::startFrame(arg, fbo0.width, fbo0.height);
-        fbo0.replayBakedOpsImpl((void*)&arg, receivers);
-        StaticReceiver::endFrame(arg);
+        renderer.startFrame(fbo0.width, fbo0.height);
+        fbo0.replayBakedOpsImpl((void*)&renderer, receivers);
+        renderer.endFrame();
     }
 
     void dump() const {
@@ -178,7 +179,7 @@ private:
 
     void deferImpl(const DisplayList& displayList);
 
-    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
+    void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers);
 
     /**
      * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
index 6c31b42..7874d85 100644 (file)
@@ -29,7 +29,7 @@ class SkPaint;
 namespace android {
 namespace uirenderer {
 
-class Layer;
+class OffscreenBuffer;
 class RenderNode;
 struct Vertex;
 
@@ -137,12 +137,12 @@ struct EndLayerOp : RecordedOp {
 };
 
 struct LayerOp : RecordedOp {
-    LayerOp(BASE_PARAMS, Layer** layerHandle)
+    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
             : SUPER(LayerOp)
             , layerHandle(layerHandle) {}
     // Records a handle to the Layer object, since the Layer itself won't be
     // constructed until after this operation is constructed.
-    Layer** layerHandle;
+    OffscreenBuffer** layerHandle;
 };
 
 }; // namespace uirenderer
index 382c0bd..43f170f 100644 (file)
@@ -60,10 +60,10 @@ void BM_OpReorderer_deferAndRender::Run(int iters) {
         StartBenchmarkTiming();
         for (int i = 0; i < iters; i++) {
             OpReorderer reorderer(200, 200, *sReorderingDisplayList);
-            MicroBench::DoNotOptimize(&reorderer);
 
-            BakedOpRenderer::Info info(caches, renderState, true);
-            reorderer.replayBakedOps<BakedOpRenderer>(info);
+            BakedOpRenderer renderer(caches, renderState, true);
+            reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
+            MicroBench::DoNotOptimize(&renderer);
         }
         StopBenchmarkTiming();
     });
index 87a7996..3cda170 100644 (file)
 #ifndef RENDERSTATE_H
 #define RENDERSTATE_H
 
-#include <set>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <utils/Mutex.h>
-#include <utils/Functor.h>
-#include <utils/RefBase.h>
-#include <private/hwui/DrawGlInfo.h>
-#include <renderstate/Blend.h>
-
 #include "AssetAtlas.h"
 #include "Caches.h"
 #include "Glop.h"
+#include "renderstate/Blend.h"
 #include "renderstate/MeshState.h"
 #include "renderstate/PixelBufferState.h"
 #include "renderstate/Scissor.h"
 #include "renderstate/Stencil.h"
 #include "utils/Macros.h"
 
+#include <set>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <ui/Region.h>
+#include <utils/Mutex.h>
+#include <utils/Functor.h>
+#include <utils/RefBase.h>
+#include <private/hwui/DrawGlInfo.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -49,6 +50,8 @@ class RenderThread;
 // wrapper of Caches for users to migrate to.
 class RenderState {
     PREVENT_COPY_AND_ASSIGN(RenderState);
+    friend class renderthread::RenderThread;
+    friend class Caches;
 public:
     void onGLContextCreated();
     void onGLContextDestroyed();
@@ -61,7 +64,6 @@ public:
     GLuint genFramebuffer();
     void deleteFramebuffer(GLuint fbo);
 
-
     void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
 
     void debugOverdraw(bool enable, bool clear);
@@ -96,10 +98,8 @@ public:
     Stencil& stencil() { return *mStencil; }
 
     void dump();
-private:
-    friend class renderthread::RenderThread;
-    friend class Caches;
 
+private:
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
     void assertOnGLThread();
index 7c0f0b6..1c6ac8c 100644 (file)
@@ -319,11 +319,11 @@ void CanvasContext::draw() {
 
 #if HWUI_NEW_OPS
     OpReorderer reorderer(dirty, frame.width(), frame.height(), mRenderNodes);
-    BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), mOpaque);
+    BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(), mOpaque);
     // TODO: profiler().draw(mCanvas);
-    reorderer.replayBakedOps<BakedOpRenderer>(info);
+    reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
 
-    bool drew = info.didDraw;
+    bool drew = renderer.didDraw();
 
 #else
     mCanvas->prepareDirty(frame.width(), frame.height(),
index af9c3f2..ffb575f 100644 (file)
 namespace android {
 namespace uirenderer {
 
+
 /**
- * Class that redirects static operation dispatch to virtual methods on a Client class.
+ * Virtual class implemented by each test to redirect static operation / state transitions to
+ * virtual methods.
  *
- * The client is recreated for every op (so data cannot be persisted between operations), but the
- * virtual dispatch allows for default behaviors to be specified without enumerating each operation
- * for every test.
+ * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
+ * and allows Renderer vs Dispatching behavior to be merged.
  *
  * onXXXOp methods fail by default - tests should override ops they expect
  * startLayer fails by default - tests should override if expected
  * startFrame/endFrame do nothing by default - tests should override to intercept
  */
-template<class CustomClient, class Arg>
-class TestReceiver {
+class TestRendererBase {
 public:
-#define CLIENT_METHOD(Type) \
-    virtual void on##Type(Arg&, const Type&, const BakedOpState&) { ADD_FAILURE(); }
-    class Client {
-    public:
-        virtual ~Client() {};
-        MAP_OPS(CLIENT_METHOD)
-
-        virtual Layer* startLayer(Arg& info, uint32_t width, uint32_t height) { ADD_FAILURE(); return nullptr; }
-        virtual void endLayer(Arg& info) { ADD_FAILURE(); }
-        virtual void startFrame(Arg& info, uint32_t width, uint32_t height) {}
-        virtual void endFrame(Arg& info) {}
-    };
+    virtual ~TestRendererBase() {}
+    virtual OffscreenBuffer* startLayer(uint32_t width, uint32_t height) { ADD_FAILURE(); return nullptr; }
+    virtual void endLayer() { ADD_FAILURE(); }
+    virtual void startFrame(uint32_t width, uint32_t height) {}
+    virtual void endFrame() {}
+
+    // define virtual defaults for direct
+#define BASE_OP_METHOD(Type) \
+    virtual void on##Type(const Type&, const BakedOpState&) { ADD_FAILURE(); }
+    MAP_OPS(BASE_OP_METHOD)
+    int getIndex() { return mIndex; }
+
+protected:
+    int mIndex = 0;
+};
 
+/**
+ * Dispatches all static methods to similar formed methods on renderer, which fail by default but
+ * are overriden by subclasses per test.
+ */
+class TestDispatcher {
+public:
 #define DISPATCHER_METHOD(Type) \
-    static void on##Type(Arg& arg, const Type& op, const BakedOpState& state) { \
-        CustomClient client; client.on##Type(arg, op, state); \
-    }
-    MAP_OPS(DISPATCHER_METHOD)
-
-    static Layer* startLayer(Arg& info, uint32_t width, uint32_t height) {
-        CustomClient client;
-        return client.startLayer(info, width, height);
-    }
-    static void endLayer(Arg& info) {
-        CustomClient client;
-        client.endLayer(info);
-    }
-    static void startFrame(Arg& info, uint32_t width, uint32_t height) {
-        CustomClient client;
-        client.startFrame(info, width, height);
-    }
-    static void endFrame(Arg& info) {
-        CustomClient client;
-        client.endFrame(info);
+    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
+        renderer.on##Type(op, state); \
     }
+    MAP_OPS(DISPATCHER_METHOD);
 };
 
-class Info {
-public:
-    int index = 0;
-};
 
-// Receiver class which will fail if it receives any ops
-class FailReceiver : public TestReceiver<FailReceiver, Info>::Client {};
+class FailRenderer : public TestRendererBase {};
 
-class SimpleReceiver : public TestReceiver<SimpleReceiver, Info>::Client {
+class SimpleTestRenderer : public TestRendererBase {
 public:
-    void startFrame(Info& info, uint32_t width, uint32_t height) override {
-        EXPECT_EQ(0, info.index++);
+    void startFrame(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(0, mIndex++);
         EXPECT_EQ(100u, width);
         EXPECT_EQ(200u, height);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(1, info.index++);
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(1, mIndex++);
     }
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(2, info.index++);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(2, mIndex++);
     }
-    void endFrame(Info& info) override {
-        EXPECT_EQ(3, info.index++);
+    void endFrame() override {
+        EXPECT_EQ(3, mIndex++);
     }
 };
 TEST(OpReorderer, simple) {
@@ -111,9 +98,9 @@ TEST(OpReorderer, simple) {
     });
     OpReorderer reorderer(100, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SimpleReceiver, Info>>(info);
-    EXPECT_EQ(4, info.index); // 2 ops + start + end
+    SimpleTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
 
@@ -126,19 +113,19 @@ TEST(OpReorderer, simpleRejection) {
     });
     OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
+    FailRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 
 static int SIMPLE_BATCHING_LOOPS = 5;
-class SimpleBatchingReceiver : public TestReceiver<SimpleBatchingReceiver, Info>::Client {
+class SimpleBatchingTestRenderer : public TestRendererBase {
 public:
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_TRUE(info.index++ >= SIMPLE_BATCHING_LOOPS);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_TRUE(mIndex++ >= SIMPLE_BATCHING_LOOPS);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_TRUE(info.index++ < SIMPLE_BATCHING_LOOPS);
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_TRUE(mIndex++ < SIMPLE_BATCHING_LOOPS);
     }
 };
 TEST(OpReorderer, simpleBatching) {
@@ -158,15 +145,15 @@ TEST(OpReorderer, simpleBatching) {
 
     OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SimpleBatchingReceiver, Info>>(info);
-    EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, info.index); // 2 x loops ops, because no merging (TODO: force no merging)
+    SimpleBatchingTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging)
 }
 
-class RenderNodeReceiver : public TestReceiver<RenderNodeReceiver, Info>::Client {
+class RenderNodeTestRenderer : public TestRendererBase {
 public:
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        switch(info.index++) {
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        switch(mIndex++) {
         case 0:
             EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
             EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
@@ -207,14 +194,14 @@ TEST(OpReorderer, renderNode) {
 
     OpReorderer reorderer(SkRect::MakeWH(200, 200), 200, 200, nodes);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<RenderNodeReceiver, Info>>(info);
+    RenderNodeTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
-class ClippedReceiver : public TestReceiver<ClippedReceiver, Info>::Client {
+class ClippedTestRenderer : public TestRendererBase {
 public:
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(0, info.index++);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(0, mIndex++);
         EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
         EXPECT_TRUE(state.computedState.transform.isIdentity());
@@ -232,24 +219,24 @@ TEST(OpReorderer, clipped) {
     OpReorderer reorderer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
             200, 200, nodes);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<ClippedReceiver, Info>>(info);
+    ClippedTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 
-class SaveLayerSimpleReceiver : public TestReceiver<SaveLayerSimpleReceiver, Info>::Client {
+class SaveLayerSimpleTestRenderer : public TestRendererBase {
 public:
-    Layer* startLayer(Info& info, uint32_t width, uint32_t height) override {
-        EXPECT_EQ(0, info.index++);
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(0, mIndex++);
         EXPECT_EQ(180u, width);
         EXPECT_EQ(180u, height);
         return nullptr;
     }
-    void endLayer(Info& info) override {
-        EXPECT_EQ(2, info.index++);
+    void endLayer() override {
+        EXPECT_EQ(2, mIndex++);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(1, info.index++);
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(1, mIndex++);
         EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
         EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
@@ -258,8 +245,8 @@ public:
         expectedTransform.loadTranslate(-10, -10, 0);
         EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
     }
-    void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(3, info.index++);
+    void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(3, mIndex++);
         EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
         EXPECT_TRUE(state.computedState.transform.isIdentity());
@@ -274,9 +261,9 @@ TEST(OpReorderer, saveLayerSimple) {
 
     OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SaveLayerSimpleReceiver, Info>>(info);
-    EXPECT_EQ(4, info.index);
+    SaveLayerSimpleTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
 }
 
 
@@ -285,46 +272,46 @@ TEST(OpReorderer, saveLayerSimple) {
  * - startLayer1, rect1, drawLayer2, endLayer1
  * - startFrame, layerOp1, endFrame
  */
-class SaveLayerNestedReceiver : public TestReceiver<SaveLayerNestedReceiver, Info>::Client {
+class SaveLayerNestedTestRenderer : public TestRendererBase {
 public:
-    Layer* startLayer(Info& info, uint32_t width, uint32_t height) override {
-        const int index = info.index++;
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override {
+        const int index = mIndex++;
         if (index == 0) {
             EXPECT_EQ(400u, width);
             EXPECT_EQ(400u, height);
-            return (Layer*) 0x400;
+            return (OffscreenBuffer*) 0x400;
         } else if (index == 3) {
             EXPECT_EQ(800u, width);
             EXPECT_EQ(800u, height);
-            return (Layer*) 0x800;
+            return (OffscreenBuffer*) 0x800;
         } else { ADD_FAILURE(); }
-        return (Layer*) nullptr;
+        return (OffscreenBuffer*) nullptr;
     }
-    void endLayer(Info& info) override {
-        int index = info.index++;
+    void endLayer() override {
+        int index = mIndex++;
         EXPECT_TRUE(index == 2 || index == 6);
     }
-    void startFrame(Info& info, uint32_t width, uint32_t height) override {
-        EXPECT_EQ(7, info.index++);
+    void startFrame(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(7, mIndex++);
     }
-    void endFrame(Info& info) override {
-        EXPECT_EQ(9, info.index++);
+    void endFrame() override {
+        EXPECT_EQ(9, mIndex++);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        const int index = info.index++;
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        const int index = mIndex++;
         if (index == 1) {
             EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
         } else if (index == 4) {
             EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
         } else { ADD_FAILURE(); }
     }
-    void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
-        const int index = info.index++;
+    void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+        const int index = mIndex++;
         if (index == 5) {
-            EXPECT_EQ((Layer*)0x400, *op.layerHandle);
+            EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
             EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
         } else if (index == 8) {
-            EXPECT_EQ((Layer*)0x800, *op.layerHandle);
+            EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
             EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
         } else { ADD_FAILURE(); }
     }
@@ -345,9 +332,9 @@ TEST(OpReorderer, saveLayerNested) {
 
     OpReorderer reorderer(800, 800, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SaveLayerNestedReceiver, Info>>(info);
-    EXPECT_EQ(10, info.index);
+    SaveLayerNestedTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(10, renderer.getIndex());
 }
 
 TEST(OpReorderer, saveLayerContentRejection) {
@@ -363,10 +350,10 @@ TEST(OpReorderer, saveLayerContentRejection) {
         canvas.restore();
     });
     OpReorderer reorderer(200, 200, *dl);
-    Info info;
 
+    FailRenderer renderer;
     // should see no ops, even within the layer, since the layer should be rejected
-    reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 } // namespace uirenderer