From d2dfd8f128b632ed99418ab2b32949c939a9a369 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Wed, 16 Dec 2015 14:27:20 -0800 Subject: [PATCH] Add TextureView support to new renderer/reorderer bug:22480459 Change-Id: I2e4c0bc6b904706132f3f5087ededc9cac9b40fb --- libs/hwui/Android.mk | 2 +- libs/hwui/BakedOpDispatcher.cpp | 14 ++++++++ libs/hwui/DeferredLayerUpdater.cpp | 4 +-- libs/hwui/DeferredLayerUpdater.h | 4 +-- libs/hwui/LayerRenderer.cpp | 2 +- libs/hwui/LayerRenderer.h | 2 +- libs/hwui/Matrix.h | 8 +++-- libs/hwui/OpReorderer.cpp | 8 ++++- libs/hwui/OpReorderer.h | 3 +- libs/hwui/RecordedOp.h | 9 +++++- libs/hwui/RecordingCanvas.cpp | 16 ++++++++++ libs/hwui/RecordingCanvas.h | 4 ++- libs/hwui/renderthread/CanvasContext.cpp | 10 ------ libs/hwui/renderthread/CanvasContext.h | 1 - libs/hwui/renderthread/DrawFrameTask.cpp | 2 +- libs/hwui/tests/common/TestUtils.cpp | 19 +++++++++++ libs/hwui/tests/common/TestUtils.h | 4 +++ libs/hwui/tests/unit/OpReordererTests.cpp | 39 +++++++++++++++++++++-- 18 files changed, 121 insertions(+), 30 deletions(-) diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 0d1ee46712ee4..a1ea9ce6f5f8b 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -HWUI_NEW_OPS := false +HWUI_NEW_OPS := true hwui_src_files := \ font/CacheTexture.cpp \ diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index a892b1b29174c..0f0768f08a5ed 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -735,6 +735,20 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa } } +void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) { + const bool tryToSnap = !op.layer->getForceFilter(); + float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha; + Glop glop; + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) + .setRoundRectClipState(state.roundRectClipState) + .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO + .setFillTextureLayer(*(op.layer), alpha) + .setTransform(state.computedState.transform, TransformFlags::None) + .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight())) + .build(); + renderer.renderGlop(state, glop); +} + void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { OffscreenBuffer* buffer = *op.layerHandle; diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 70383340fc8dc..f833a5405a5c4 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -53,8 +53,7 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { SkRefCnt_SafeAssign(mColorFilter, colorFilter); } -bool DeferredLayerUpdater::apply() { - bool success = true; +void DeferredLayerUpdater::apply() { // These properties are applied the same to both layer types mLayer->setColorFilter(mColorFilter); mLayer->setAlpha(mAlpha, mMode); @@ -73,7 +72,6 @@ bool DeferredLayerUpdater::apply() { setTransform(nullptr); } } - return success; } void DeferredLayerUpdater::doUpdateTexImage() { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index df7c594cf187f..6a3c8902dff10 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -77,13 +77,13 @@ public: ANDROID_API void setPaint(const SkPaint* paint); - ANDROID_API bool apply(); + void apply(); Layer* backingLayer() { return mLayer; } - ANDROID_API void detachSurfaceTexture(); + void detachSurfaceTexture(); private: // Generic properties diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index e9e5d81f1ce24..0cf643fb686ed 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -287,7 +287,7 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { } void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) { + bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) { if (layer) { layer->setBlend(!isOpaque); layer->setForceFilter(forceFilter); diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index e4a54b0a05200..38c3705cfa25a 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -59,7 +59,7 @@ public: static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform); + bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform); static void destroyLayer(Layer* layer); static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap); diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index c017638db8957..1c25f26c0c252 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -139,9 +139,11 @@ public: } void multiply(const Matrix4& v) { - Matrix4 u; - u.loadMultiply(*this, v); - *this = u; + if (!v.isIdentity()) { + Matrix4 u; + u.loadMultiply(*this, v); + *this = u; + } } void multiply(float v); diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index e1472113d25f4..bdc8f68cf3b8e 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -783,7 +783,7 @@ void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { void OpReorderer::deferFunctorOp(const FunctorOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::None); + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); } void OpReorderer::deferLinesOp(const LinesOp& op) { @@ -871,6 +871,12 @@ void OpReorderer::deferTextOnPathOp(const TextOnPathOp& op) { currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint))); } +void OpReorderer::deferTextureLayerOp(const TextureLayerOp& op) { + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); +} + void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, float contentTranslateY, const Rect& repaintRect, diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 35343c8b43581..dbbce8b15170e 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -43,7 +43,6 @@ typedef const void* mergeid_t; namespace OpBatchType { enum { - None = 0, // Don't batch Bitmap, MergedPatch, AlphaVertices, @@ -52,6 +51,8 @@ namespace OpBatchType { Text, ColorText, Shadow, + TextureLayer, + Functor, Count // must be last }; diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index bb230054ad150..cfdd0d211dace 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -63,6 +63,7 @@ struct Vertex; U_OP_FN(SimpleRectsOp) \ M_OP_FN(TextOp) \ U_OP_FN(TextOnPathOp) \ + U_OP_FN(TextureLayerOp) \ U_OP_FN(BeginLayerOp) \ U_OP_FN(EndLayerOp) \ U_OP_FN(LayerOp) @@ -345,11 +346,17 @@ struct TextOnPathOp : RecordedOp { const float vOffset; }; +struct TextureLayerOp : RecordedOp { + TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer) + : SUPER_PAINTLESS(TextureLayerOp) + , layer(layer) {} + Layer* layer; +}; + //////////////////////////////////////////////////////////////////////////////////////////////////// // Layers //////////////////////////////////////////////////////////////////////////////////////////////////// - /** * Stateful operation! denotes the creation of an off-screen layer, * and that commands following will render into it. diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 46ae7904ae78d..f75d8d4f64792 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -16,6 +16,7 @@ #include "RecordingCanvas.h" +#include "DeferredLayerUpdater.h" #include "RecordedOp.h" #include "RenderNode.h" @@ -542,6 +543,21 @@ void RecordingCanvas::drawRenderNode(RenderNode* renderNode) { } } +void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { + // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics. + mDisplayList->ref(layerHandle); + + Layer* layer = layerHandle->backingLayer(); + Matrix4 totalTransform(*(mState.currentSnapshot()->transform)); + totalTransform.multiply(layer->getTransform()); + + addOp(new (alloc()) TextureLayerOp( + Rect(layer->getWidth(), layer->getHeight()), + totalTransform, + mState.getRenderTargetClipBounds(), + layer)); +} + void RecordingCanvas::callDrawGLFunction(Functor* functor) { mDisplayList->functors.push_back(functor); addOp(new (alloc()) FunctorOp( diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index ce7d13507aeae..48cc91abd89c7 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -36,7 +36,7 @@ namespace android { namespace uirenderer { -class OpReceiver; +class DeferredLayerUpdater; struct RecordedOp; class RecordingCanvas: public Canvas, public CanvasStateClient { @@ -59,6 +59,8 @@ public: mDeferredBarrierType = enableReorder ? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder; } + + void drawLayer(DeferredLayerUpdater* layerHandle); void drawRenderNode(RenderNode* renderNode); // TODO: rename for consistency diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index ca85dfbf1bab4..4c586761ea5f4 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -182,16 +182,6 @@ void CanvasContext::makeCurrent() { } } -void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) { -#if !HWUI_NEW_OPS - bool success = layerUpdater->apply(); - LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!"); - if (layerUpdater->backingLayer()->deferredUpdateScheduled) { - mCanvas->pushLayerUpdate(layerUpdater->backingLayer()); - } -#endif -} - static bool wasSkipped(FrameInfo* info) { return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index d36ce993164ec..ca5aa5c6e3126 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -83,7 +83,6 @@ public: void setLightCenter(const Vector3& lightCenter); void setOpaque(bool opaque); void makeCurrent(); - void processLayerUpdate(DeferredLayerUpdater* layerUpdater); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); void draw(); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index ab860c7d3b322..e8b9725fe808b 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -117,7 +117,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { Caches::getInstance().textureCache.resetMarkInUse(mContext); for (size_t i = 0; i < mLayers.size(); i++) { - mContext->processLayerUpdate(mLayers[i].get()); + mLayers[i]->apply(); } mLayers.clear(); mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode); diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 4c8d23dd82ea0..624f3bd1e7107 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -16,6 +16,9 @@ #include "TestUtils.h" +#include "DeferredLayerUpdater.h" +#include "LayerRenderer.h" + namespace android { namespace uirenderer { @@ -36,6 +39,22 @@ SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) | (int)((startB + (int)(fraction * (endB - startB)))); } +sp TestUtils::createTextureLayerUpdater( + renderthread::RenderThread& renderThread, uint32_t width, uint32_t height, + std::function transformSetupCallback) { + bool isOpaque = true; + bool forceFilter = true; + GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES; + + Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState()); + LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter, + renderTarget, Matrix4::identity().data); + transformSetupCallback(&(layer->getTransform())); + + sp layerUpdater = new DeferredLayerUpdater(layer); + return layerUpdater; +} + void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text, const SkPaint& paint, float x, float y) { // drawing text requires GlyphID TextEncoding (which JNI layer would have done) diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 4f84474f99887..d37fad4676ebb 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -113,6 +113,10 @@ public: return bitmap; } + static sp createTextureLayerUpdater( + renderthread::RenderThread& renderThread, uint32_t width, uint32_t height, + std::function transformSetupCallback); + template static std::unique_ptr createDisplayList(int width, int height, std::function canvasCallback) { diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp index ab0cc878178c6..288f8af500818 100644 --- a/libs/hwui/tests/unit/OpReordererTests.cpp +++ b/libs/hwui/tests/unit/OpReordererTests.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -281,6 +282,39 @@ TEST(OpReorderer, textStrikethrough) { << "Expect number of ops = 2 * loop count"; } +RENDERTHREAD_TEST(OpReorderer, textureLayer) { + class TextureLayerTestRenderer : public TestRendererBase { + public: + void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); + EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect); + EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds); + + Matrix4 expected; + expected.loadTranslate(5, 5, 0); + EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); + } + }; + + auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100, + [](Matrix4* transform) { + transform->loadTranslate(5, 5, 0); + }); + + auto node = TestUtils::createNode(0, 0, 200, 200, + [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op); + canvas.drawLayer(layerUpdater.get()); + canvas.restore(); + }); + OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + createSyncedNodeList(node), sLightCenter); + TextureLayerTestRenderer renderer; + reorderer.replayBakedOps(renderer); + EXPECT_EQ(1, renderer.getIndex()); +} + TEST(OpReorderer, renderNode) { class RenderNodeTestRenderer : public TestRendererBase { public: @@ -307,16 +341,15 @@ TEST(OpReorderer, renderNode) { canvas.drawRect(0, 0, 100, 100, paint); }); - RenderNode* childPtr = child.get(); auto parent = TestUtils::createNode(0, 0, 200, 200, - [childPtr](RenderProperties& props, RecordingCanvas& canvas) { + [&child](RenderProperties& props, RecordingCanvas& canvas) { SkPaint paint; paint.setColor(SK_ColorDKGRAY); canvas.drawRect(0, 0, 200, 200, paint); canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); canvas.translate(40, 40); - canvas.drawRenderNode(childPtr); + canvas.drawRenderNode(child.get()); canvas.restore(); });