diff options
| -rw-r--r-- | libs/hwui/BakedOpRenderer.cpp | 90 | ||||
| -rw-r--r-- | libs/hwui/BakedOpRenderer.h | 18 | ||||
| -rw-r--r-- | libs/hwui/GlopBuilder.cpp | 14 | ||||
| -rw-r--r-- | libs/hwui/GlopBuilder.h | 1 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/renderstate/MeshState.cpp | 18 | ||||
| -rw-r--r-- | libs/hwui/renderstate/MeshState.h | 3 | ||||
| -rw-r--r-- | libs/hwui/unit_tests/FatVectorTests.cpp | 21 | ||||
| -rw-r--r-- | libs/hwui/utils/FatVector.h | 4 |
9 files changed, 146 insertions, 25 deletions
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 705583941067..2fca5ea8b962 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -20,6 +20,7 @@ #include "Glop.h" #include "GlopBuilder.h" #include "renderstate/RenderState.h" +#include "utils/FatVector.h" #include "utils/GLUtils.h" namespace android { @@ -29,12 +30,13 @@ namespace uirenderer { // OffscreenBuffer //////////////////////////////////////////////////////////////////////////////// -OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight, +OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, + uint32_t textureWidth, uint32_t textureHeight, uint32_t viewportWidth, uint32_t viewportHeight) - : viewportWidth(viewportWidth) + : renderState(renderState) + , viewportWidth(viewportWidth) , viewportHeight(viewportHeight) - , texture(caches) - , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) { + , texture(caches) { texture.width = textureWidth; texture.height = textureHeight; @@ -50,19 +52,58 @@ OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } +void OffscreenBuffer::updateMeshFromRegion() { + // avoid T-junctions as they cause artifacts in between the resultant + // geometry when complex transforms occur. + // TODO: generate the safeRegion only if necessary based on drawing transform + Region safeRegion = Region::createTJunctionFreeRegion(region); + + size_t count; + const android::Rect* rects = safeRegion.getArray(&count); + + const float texX = 1.0f / float(viewportWidth); + const float texY = 1.0f / float(viewportHeight); + + FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed + TextureVertex* mesh = &meshVector[0]; + for (size_t i = 0; i < count; i++) { + const android::Rect* r = &rects[i]; + + const float u1 = r->left * texX; + const float v1 = (viewportHeight - r->top) * texY; + const float u2 = r->right * texX; + const float v2 = (viewportHeight - 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); + } + elementCount = count * 6; + renderState.meshState().genOrUpdateMeshBuffer(&vbo, + sizeof(TextureVertex) * count * 4, + &meshVector[0], + GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer +} + +OffscreenBuffer::~OffscreenBuffer() { + texture.deleteTexture(); + renderState.meshState().deleteMeshBuffer(vbo); + elementCount = 0; + vbo = 0; +} + //////////////////////////////////////////////////////////////////////////////// // BakedOpRenderer //////////////////////////////////////////////////////////////////////////////// -OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(uint32_t width, uint32_t height) { +OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(RenderState& renderState, + uint32_t width, uint32_t height) { // TODO: get from cache! - return new OffscreenBuffer(Caches::getInstance(), width, height, width, height); + return new OffscreenBuffer(renderState, Caches::getInstance(), width, height, width, height); } void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) { - // destroy and delete, since each clipped saveLayer is only drawn once. - offscreenBuffer->texture.deleteTexture(); - // TODO: return texture/offscreenbuffer to cache! delete offscreenBuffer; } @@ -70,7 +111,7 @@ void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) { OffscreenBuffer* BakedOpRenderer::createLayer(uint32_t width, uint32_t height) { LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); - OffscreenBuffer* buffer = createOffscreenBuffer(width, height); + OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height); startLayer(buffer); return buffer; } @@ -98,6 +139,7 @@ void BakedOpRenderer::startLayer(OffscreenBuffer* offscreenBuffer) { } void BakedOpRenderer::endLayer() { + mRenderTarget.offscreenBuffer->updateMeshFromRegion(); mRenderTarget.offscreenBuffer = nullptr; // Detach the texture from the FBO @@ -162,6 +204,12 @@ void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) { mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom, clip.getWidth(), clip.getHeight()); } + if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw + // register layer damage to draw-back region + const Rect& uiDirty = state.computedState.clippedBounds; + android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom); + mRenderTarget.offscreenBuffer->region.orSelf(dirty); + } mRenderState.render(glop, mRenderTarget.orthoMatrix); mHasDrawn = true; } @@ -174,6 +222,14 @@ void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, co LOG_ALWAYS_FATAL("unsupported operation"); } +void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + +void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + 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); @@ -217,28 +273,20 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR renderer.renderGlop(state, glop); } -void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - -void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - 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.alpha * state.alpha; - const bool tryToSnap = state.computedState.transform.isPureTranslate(); Glop glop; GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUvQuad(nullptr, buffer->texCoords) + .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds) + .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, + Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) .build(); renderer.renderGlop(state, glop); diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index 722bf02ff81e..aa1e67d45d56 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -35,13 +35,24 @@ class RenderState; */ class OffscreenBuffer { public: - OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight, + OffscreenBuffer(RenderState& renderState, Caches& caches, + uint32_t textureWidth, uint32_t textureHeight, uint32_t viewportWidth, uint32_t viewportHeight); + ~OffscreenBuffer(); + + // must be called prior to rendering, to construct/update vertex buffer + void updateMeshFromRegion(); + + RenderState& renderState; uint32_t viewportWidth; uint32_t viewportHeight; Texture texture; - Rect texCoords; + + // Portion of offscreen buffer that has been drawn to. Used to minimize drawing area when + // drawing back to screen / parent FBO. Region region; + GLsizei elementCount = 0; + GLuint vbo = 0; }; /** @@ -61,7 +72,8 @@ public: , mOpaque(opaque) { } - static OffscreenBuffer* createOffscreenBuffer(uint32_t width, uint32_t height); + static OffscreenBuffer* createOffscreenBuffer(RenderState& renderState, + uint32_t width, uint32_t height); static void destroyOffscreenBuffer(OffscreenBuffer*); RenderState& renderState() { return mRenderState; } diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index d2da8513ff56..f3ac93b89893 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -70,6 +70,20 @@ GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop // Mesh //////////////////////////////////////////////////////////////////////////////// +GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementCount) { + TRIGGER_STAGE(kMeshStage); + + mOutGlop->mesh.primitiveMode = GL_TRIANGLES; + mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; + mOutGlop->mesh.vertices = { + vbo, + VertexAttribFlags::TextureCoord, + nullptr, nullptr, nullptr, + kTextureVertexStride }; + mOutGlop->mesh.elementCount = elementCount; + return *this; +} + GlopBuilder& GlopBuilder::setMeshUnitQuad() { TRIGGER_STAGE(kMeshStage); diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 6f5802eedefd..6270dcbe7a84 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -47,6 +47,7 @@ class GlopBuilder { public: GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop); + GlopBuilder& setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementCount); GlopBuilder& setMeshUnitQuad(); GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper); GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index de02bb89ac73..0601944905a8 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -250,7 +250,7 @@ void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) { layer_t* createLayer(RenderState& renderState, uint32_t width, uint32_t height) { #if HWUI_NEW_OPS - return BakedOpRenderer::createOffscreenBuffer(width, height); + return BakedOpRenderer::createOffscreenBuffer(renderState, width, height); #else return LayerRenderer::createRenderLayer(renderState, width, height); #endif diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp index 0521f6573e39..03cb5ce8ce2e 100644 --- a/libs/hwui/renderstate/MeshState.cpp +++ b/libs/hwui/renderstate/MeshState.cpp @@ -100,6 +100,24 @@ bool MeshState::bindMeshBufferInternal(GLuint buffer) { return false; } +void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, + const void* data, GLenum usage) { + if (!*buffer) { + glGenBuffers(1, buffer); + } + bindMeshBuffer(*buffer); + glBufferData(GL_ARRAY_BUFFER, size, data, usage); +} + +void MeshState::deleteMeshBuffer(GLuint buffer) { + if (buffer == mCurrentBuffer) { + // GL defines that deleting the currently bound VBO rebinds to 0 (no VBO). + // Reflect this in our cached value. + mCurrentBuffer = 0; + } + glDeleteBuffers(1, &buffer); +} + /////////////////////////////////////////////////////////////////////////////// // Vertices /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h index e80f4d0d6c41..6c0fb78cae17 100644 --- a/libs/hwui/renderstate/MeshState.h +++ b/libs/hwui/renderstate/MeshState.h @@ -75,6 +75,9 @@ public: */ bool unbindMeshBuffer(); + void genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, GLenum usage); + void deleteMeshBuffer(GLuint); + /////////////////////////////////////////////////////////////////////////////// // Vertices /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/unit_tests/FatVectorTests.cpp b/libs/hwui/unit_tests/FatVectorTests.cpp index fb760ac549cd..1f1f50a87473 100644 --- a/libs/hwui/unit_tests/FatVectorTests.cpp +++ b/libs/hwui/unit_tests/FatVectorTests.cpp @@ -56,6 +56,27 @@ TEST(FatVector, simpleAllocate) { } } +TEST(FatVector, preSizeConstructor) { + { + FatVector<int, 4> v(32); + EXPECT_EQ(32u, v.capacity()); + EXPECT_EQ(32u, v.size()); + EXPECT_FALSE(allocationIsInternal(v)); + } + { + FatVector<int, 4> v(4); + EXPECT_EQ(4u, v.capacity()); + EXPECT_EQ(4u, v.size()); + EXPECT_TRUE(allocationIsInternal(v)); + } + { + FatVector<int, 4> v(2); + EXPECT_EQ(4u, v.capacity()); + EXPECT_EQ(2u, v.size()); + EXPECT_TRUE(allocationIsInternal(v)); + } +} + TEST(FatVector, shrink) { FatVector<int, 10> v; EXPECT_TRUE(allocationIsInternal(v)); diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h index c3c16c5ae27d..315c24978a1f 100644 --- a/libs/hwui/utils/FatVector.h +++ b/libs/hwui/utils/FatVector.h @@ -91,6 +91,10 @@ public: InlineStdAllocator<T, SIZE>(mAllocation)) { this->reserve(SIZE); } + + FatVector(size_t capacity) : FatVector() { + this->resize(capacity); + } private: typename InlineStdAllocator<T, SIZE>::Allocation mAllocation; }; |