diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Android.common.mk | 7 | ||||
-rw-r--r-- | libs/hwui/Glop.h | 17 | ||||
-rw-r--r-- | libs/hwui/GlopBuilder.cpp | 133 | ||||
-rw-r--r-- | libs/hwui/GlopBuilder.h | 55 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.h | 2 | ||||
-rw-r--r-- | libs/hwui/Snapshot.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/renderstate/Blend.cpp | 41 | ||||
-rw-r--r-- | libs/hwui/renderstate/Blend.h | 3 | ||||
-rw-r--r-- | libs/hwui/renderstate/MeshState.cpp | 14 | ||||
-rw-r--r-- | libs/hwui/renderstate/MeshState.h | 8 | ||||
-rw-r--r-- | libs/hwui/renderstate/RenderState.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/tests/main.cpp | 215 | ||||
-rw-r--r-- | libs/hwui/utils/PaintUtils.h | 3 |
15 files changed, 417 insertions, 112 deletions
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk index de9ef06..2e1364e 100644 --- a/libs/hwui/Android.common.mk +++ b/libs/hwui/Android.common.mk @@ -34,9 +34,9 @@ LOCAL_SRC_FILES := \ CanvasState.cpp \ ClipArea.cpp \ DamageAccumulator.cpp \ - DisplayList.cpp \ DeferredDisplayList.cpp \ DeferredLayerUpdater.cpp \ + DisplayList.cpp \ DisplayListRenderer.cpp \ Dither.cpp \ DrawProfiler.cpp \ @@ -44,6 +44,7 @@ LOCAL_SRC_FILES := \ FboCache.cpp \ FontRenderer.cpp \ GammaFontRenderer.cpp \ + GlopBuilder.cpp \ GradientCache.cpp \ Image.cpp \ Interpolator.cpp \ @@ -69,9 +70,9 @@ LOCAL_SRC_FILES := \ Snapshot.cpp \ SpotShadow.cpp \ TessellationCache.cpp \ + TextDropShadowCache.cpp \ Texture.cpp \ - TextureCache.cpp \ - TextDropShadowCache.cpp + TextureCache.cpp intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index 730d9df..bbeb19e 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -23,10 +23,13 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include <SkXfermode.h> namespace android { namespace uirenderer { +class Program; + /* * Enumerates optional vertex attributes * @@ -53,18 +56,16 @@ struct Glop { Rect bounds; struct Mesh { - VertexAttribFlags vertexFlags = static_cast<VertexAttribFlags>(0); + VertexAttribFlags vertexFlags; GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported - GLuint vertexBufferObject = 0; - GLuint indexBufferObject = 0; + GLuint vertexBufferObject; + GLuint indexBufferObject; int vertexCount; GLsizei stride; } mesh; struct Fill { Program* program; - GLuint shaderId; - GLuint textureId; struct Color { float a, r, g, b; @@ -89,10 +90,8 @@ struct Glop { } transform; struct Blend { - static const SkXfermode::Mode kDisable = - static_cast<SkXfermode::Mode>(SkXfermode::kLastMode + 1); - SkXfermode::Mode mode; - bool swapSrcDst; + GLenum src; + GLenum dst; } blend; /** diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp new file mode 100644 index 0000000..dafe087 --- /dev/null +++ b/libs/hwui/GlopBuilder.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "GlopBuilder.h" + +#include "Caches.h" +#include "Glop.h" +#include "Matrix.h" +#include "Texture.h" +#include "renderstate/MeshState.h" +#include "renderstate/RenderState.h" +#include "utils/PaintUtils.h" + +#include <GLES2/gl2.h> +#include <SkPaint.h> + +namespace android { +namespace uirenderer { + +GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop) + : mRenderState(renderState) + , mCaches(caches) + , mOutGlop(outGlop){ +} + +GlopBuilder& GlopBuilder::setMeshUnitQuad() { + mOutGlop->mesh.vertexFlags = static_cast<VertexAttribFlags>(0); + mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; + mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO(); + mOutGlop->mesh.indexBufferObject = 0; + mOutGlop->mesh.vertexCount = 4; + mOutGlop->mesh.stride = kTextureVertexStride; + return *this; +} + +GlopBuilder& GlopBuilder::setTransformAndRect(ModelViewMode mode, + const Matrix4& ortho, const Matrix4& transform, + float left, float top, float right, float bottom, bool offset) { + mOutGlop->transform.ortho.load(ortho); + + mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); + if (mode == kModelViewMode_TranslateAndScale) { + mOutGlop->transform.modelView.scale(right - left, bottom - top, 1.0f); + } + + mOutGlop->transform.canvas.load(transform); + + mOutGlop->transform.offset = offset; + + mOutGlop->bounds.set(left, top, right, bottom); + mOutGlop->transform.canvas.mapRect(mOutGlop->bounds); + return *this; +} + +GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) { + // TODO: support null paint + const SkShader* shader = paint->getShader(); + const SkColorFilter* colorFilter = paint->getColorFilter(); + + SkXfermode::Mode mode = PaintUtils::getXfermode(paint->getXfermode()); + if (mode != SkXfermode::kClear_Mode) { + int color = paint->getColor(); + float alpha = (SkColorGetA(color) / 255.0f) * alphaScale; + if (shader) { + // shader discards color channels + color |= 0x00FFFFFF; + } + mOutGlop->fill.color = { + alpha, + alpha * SkColorGetR(color), + alpha * SkColorGetG(color), + alpha * SkColorGetB(color) + }; + } else { + mOutGlop->fill.color = { 1, 0, 0, 0 }; + } + const bool SWAP_SRC_DST = false; + const bool HAS_FRAMEBUFFER_FETCH = false; //mExtensions.hasFramebufferFetch(); + + mOutGlop->blend = {GL_ZERO, GL_ZERO}; + if (mOutGlop->fill.color.a < 1.0f + || (shader && !shader->isOpaque()) + || PaintUtils::isBlendedColorFilter(colorFilter) + || mode != SkXfermode::kSrcOver_Mode) { + if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) { + Blend::getFactors(mode, SWAP_SRC_DST, + &mOutGlop->blend.src, &mOutGlop->blend.dst); + } else { + // These blend modes are not supported by OpenGL directly and have + // to be implemented using shaders. Since the shader will perform + // the blending, don't enable GL blending off here + // If the blend mode cannot be implemented using shaders, fall + // back to the default SrcOver blend mode instead + if (CC_UNLIKELY(HAS_FRAMEBUFFER_FETCH)) { + mDescription.framebufferMode = mode; + mDescription.swapSrcDst = SWAP_SRC_DST; + // blending in shader, don't enable + } else { + // unsupported + Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST, + &mOutGlop->blend.src, &mOutGlop->blend.dst); + } + } + } + + return *this; +} + +GlopBuilder& GlopBuilder::setTexture(Texture* texture) { + LOG_ALWAYS_FATAL("not yet supported"); + return *this; +} + +void GlopBuilder::build() { + mDescription.modulate = mOutGlop->fill.color.a < 1.0f; + mOutGlop->fill.program = mCaches.programCache.get(mDescription); +} + +} /* namespace uirenderer */ +} /* namespace android */ + diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h new file mode 100644 index 0000000..d243d76 --- /dev/null +++ b/libs/hwui/GlopBuilder.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RENDERSTATE_GLOPBUILDER_H +#define RENDERSTATE_GLOPBUILDER_H + +#include "OpenGLRenderer.h" +#include "Program.h" +#include "utils/Macros.h" + +class SkPaint; + +namespace android { +namespace uirenderer { + +class Caches; +struct Glop; +class RenderState; +class Texture; +class Matrix4; + +class GlopBuilder { + PREVENT_COPY_AND_ASSIGN(GlopBuilder); +public: + GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop); + GlopBuilder& setMeshUnitQuad(); + GlopBuilder& setTransformAndRect(ModelViewMode mode, + const Matrix4& ortho, const Matrix4& transform, + float left, float top, float right, float bottom, bool offset); + GlopBuilder& setPaint(const SkPaint* paint, float alphaScale); + GlopBuilder& setTexture(Texture* texture); + void build(); +private: + ProgramDescription mDescription; + RenderState& mRenderState; + Caches& mCaches; + Glop* mOutGlop; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif // RENDERSTATE_GLOPBUILDER_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ab6f0ce..b10aea3 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -20,10 +20,13 @@ #include "DisplayListRenderer.h" #include "Fence.h" #include "GammaFontRenderer.h" +#include "Glop.h" +#include "GlopBuilder.h" #include "Patch.h" #include "PathTessellator.h" #include "Properties.h" #include "RenderNode.h" +#include "renderstate/MeshState.h" #include "renderstate/RenderState.h" #include "ShadowTessellator.h" #include "SkiaShader.h" @@ -101,7 +104,7 @@ OpenGLRenderer::OpenGLRenderer(RenderState& renderState) memset(&mDrawModifiers, 0, sizeof(mDrawModifiers)); mDrawModifiers.mOverrideLayerAlpha = 1.0f; - memcpy(mMeshVertices, kMeshVertices, sizeof(kMeshVertices)); + memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices)); } OpenGLRenderer::~OpenGLRenderer() { @@ -1704,9 +1707,9 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw // When the blending mode is kClear_Mode, we need to use a modulate color // argb=1,0,0,0 accountForClear(mode); - blend |= (mColorSet && mColorA < 1.0f) || - (getShader(paint) && !getShader(paint)->isOpaque()) || - PaintUtils::isBlendedColorFilter(getColorFilter(paint)); + blend |= (mColorSet && mColorA < 1.0f) + || (getShader(paint) && !getShader(paint)->isOpaque()) + || PaintUtils::isBlendedColorFilter(getColorFilter(paint)); chooseBlending(blend, mode, mDescription, swapSrcDst); } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index a0a5a1c..659ef6c 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -836,7 +836,6 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& */ template <class T> void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { - const int level = handler.level(); if (mDisplayListData->isEmpty()) { DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName()); return; @@ -860,7 +859,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { #if DEBUG_DISPLAY_LIST const Rect& clipRect = renderer.getLocalClipBounds(); DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f", - level * 2, "", this, getName(), + handler.level() * 2, "", this, getName(), clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); #endif @@ -900,7 +899,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { DisplayListOp *op = mDisplayListData->displayListOps[opIndex]; #if DEBUG_DISPLAY_LIST - op->output(level + 1); + op->output(handler.level() + 1); #endif handler(op, saveCountOffset, properties().getClipToBounds()); diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h index c6483ac..4333792 100644 --- a/libs/hwui/ResourceCache.h +++ b/libs/hwui/ResourceCache.h @@ -81,7 +81,7 @@ private: uint32_t mPixelRefStableID; friend class ResourceCache; - friend class android::key_value_pair_t<BitmapKey, SkBitmap*>; + friend struct android::key_value_pair_t<BitmapKey, SkBitmap*>; }; class ANDROID_API ResourceCache: public Singleton<ResourceCache> { diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 49fb4ba..597d95c 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -203,8 +203,8 @@ void Snapshot::dump() const { ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple()); const Rect& clipRect(mClipArea->getClipRect()); - ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f", - clipRect, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); + ALOGD(" ClipRect %.1f %.1f %.1f %.1f", + clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); ALOGD(" Transform (at %p):", transform); transform->dump(); } diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp index 3e7b721..93088e4 100644 --- a/libs/hwui/renderstate/Blend.cpp +++ b/libs/hwui/renderstate/Blend.cpp @@ -79,21 +79,10 @@ Blend::Blend() } void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) { - // enable - if (!mEnabled) { - glEnable(GL_BLEND); - mEnabled = true; - } - - // select blend mode - GLenum sourceMode = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src; - GLenum destMode = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst; - - if (sourceMode != mSrcMode || destMode != mSrcMode) { - glBlendFunc(sourceMode, destMode); - mSrcMode = sourceMode; - mDstMode = destMode; - } + GLenum srcMode; + GLenum dstMode; + getFactors(mode, swapSrcDst, &srcMode, &dstMode); + setFactors(srcMode, dstMode); } void Blend::disable() { @@ -116,6 +105,28 @@ void Blend::syncEnabled() { } } +void Blend::getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst) { + *outSrc = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src; + *outDst = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst; +} + +void Blend::setFactors(GLenum srcMode, GLenum dstMode) { + if (srcMode == GL_ZERO && dstMode == GL_ZERO) { + disable(); + } else { + if (!mEnabled) { + glEnable(GL_BLEND); + mEnabled = true; + } + + if (srcMode != mSrcMode || dstMode != mSrcMode) { + glBlendFunc(srcMode, dstMode); + mSrcMode = srcMode; + mDstMode = dstMode; + } + } +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h index b82b477..31d7dde 100644 --- a/libs/hwui/renderstate/Blend.h +++ b/libs/hwui/renderstate/Blend.h @@ -32,6 +32,9 @@ public: void enable(SkXfermode::Mode mode, bool swapSrcDst); void disable(); void syncEnabled(); + + static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst); + void setFactors(GLenum src, GLenum dst); private: Blend(); void invalidate(); diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp index 022faf7..50c09c8 100644 --- a/libs/hwui/renderstate/MeshState.cpp +++ b/libs/hwui/renderstate/MeshState.cpp @@ -29,11 +29,11 @@ MeshState::MeshState() , mCurrentTexCoordsStride(0) , mTexCoordsArrayEnabled(false) { - glGenBuffers(1, &meshBuffer); - glBindBuffer(GL_ARRAY_BUFFER, meshBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(kMeshVertices), kMeshVertices, GL_STATIC_DRAW); + glGenBuffers(1, &mUnitQuadBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW); - mCurrentBuffer = meshBuffer; + mCurrentBuffer = mUnitQuadBuffer; mCurrentIndicesBuffer = 0; mCurrentPixelBuffer = 0; @@ -45,7 +45,7 @@ MeshState::MeshState() } MeshState::~MeshState() { - glDeleteBuffers(1, &meshBuffer); + glDeleteBuffers(1, &mUnitQuadBuffer); mCurrentBuffer = 0; glDeleteBuffers(1, &mQuadListIndices); @@ -60,11 +60,11 @@ MeshState::~MeshState() { /////////////////////////////////////////////////////////////////////////////// bool MeshState::bindMeshBuffer() { - return bindMeshBuffer(meshBuffer); + return bindMeshBuffer(mUnitQuadBuffer); } bool MeshState::bindMeshBuffer(GLuint buffer) { - if (!buffer) buffer = meshBuffer; + if (!buffer) buffer = mUnitQuadBuffer; if (mCurrentBuffer != buffer) { glBindBuffer(GL_ARRAY_BUFFER, buffer); mCurrentBuffer = buffer; diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h index 9b1021d..5cb1143 100644 --- a/libs/hwui/renderstate/MeshState.h +++ b/libs/hwui/renderstate/MeshState.h @@ -32,7 +32,7 @@ const uint32_t kMaxNumberOfQuads = 2048; // This array is never used directly but used as a memcpy source in the // OpenGLRenderer constructor -const TextureVertex kMeshVertices[] = { +const TextureVertex kUnitQuadVertices[] = { { 0, 0, 0, 0 }, { 1, 0, 1, 0 }, { 0, 1, 0, 1 }, @@ -110,12 +110,16 @@ public: bool bindShadowIndicesBuffer(); bool unbindIndicesBuffer(); + /////////////////////////////////////////////////////////////////////////////// + // Getters - for use in Glop building + /////////////////////////////////////////////////////////////////////////////// + GLuint getUnitQuadVBO() { return mUnitQuadBuffer; } private: MeshState(); bool bindIndicesBufferInternal(const GLuint buffer); // VBO to draw with - GLuint meshBuffer; + GLuint mUnitQuadBuffer; GLuint mCurrentBuffer; GLuint mCurrentIndicesBuffer; diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 8eda7c9..d3f6277 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -217,7 +217,7 @@ void RenderState::render(const Glop& glop) { mCaches->setProgram(shader.program); Glop::Fill::Color color = shader.color; - shader.program->setColor(color.a, color.r, color.g, color.b); + shader.program->setColor(color.r, color.g, color.b, color.a); shader.program->set(glop.transform.ortho, glop.transform.modelView, @@ -259,14 +259,13 @@ void RenderState::render(const Glop& glop) { meshState().bindIndicesBufferInternal(mesh.indexBufferObject); // ---------- GL state setup ---------- + blend().setFactors(glop.blend.src, glop.blend.dst); - if (glop.blend.mode != Glop::Blend::kDisable) { - blend().enable(glop.blend.mode, glop.blend.swapSrcDst); + if (mesh.indexBufferObject) { + glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount, GL_UNSIGNED_BYTE, nullptr); } else { - blend().disable(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, glop.mesh.vertexCount); } - - glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount, GL_UNSIGNED_BYTE, nullptr); } } /* namespace uirenderer */ diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp index a12dac7..1e7ba23 100644 --- a/libs/hwui/tests/main.cpp +++ b/libs/hwui/tests/main.cpp @@ -42,7 +42,8 @@ public: static DisplayListRenderer* startRecording(RenderNode* node) { DisplayListRenderer* renderer = new DisplayListRenderer(); - renderer->setViewport(node->getWidth(), node->getHeight()); + renderer->setViewport(node->stagingProperties().getWidth(), + node->stagingProperties().getHeight()); renderer->prepare(); return renderer; } @@ -53,80 +54,174 @@ static void endRecording(DisplayListRenderer* renderer, RenderNode* node) { delete renderer; } -sp<RenderNode> createCard(int x, int y, int width, int height) { - sp<RenderNode> node = new RenderNode(); - node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); - node->mutateStagingProperties().setElevation(dp(16)); - node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1); - node->mutateStagingProperties().mutableOutline().setShouldClip(true); - node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z); - - DisplayListRenderer* renderer = startRecording(node.get()); - renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode); - endRecording(renderer, node.get()); +class TreeContentAnimation { +public: + virtual ~TreeContentAnimation() {} + virtual int getFrameCount() { return 150; } + virtual void createContent(int width, int height, DisplayListRenderer* renderer) = 0; + virtual void doFrame(int frameNr) = 0; + + template <class T> + static void run() { + T animation; + + TestContext testContext; + + // create the native surface + const int width = gDisplay.w; + const int height = gDisplay.h; + sp<Surface> surface = testContext.surface(); + + RenderNode* rootNode = new RenderNode(); + rootNode->incStrong(nullptr); + rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height); + rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + rootNode->mutateStagingProperties().setClipToBounds(false); + rootNode->setPropertyFieldsDirty(RenderNode::GENERIC); + + ContextFactory factory; + std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory)); + proxy->loadSystemProperties(); + proxy->initialize(surface); + float lightX = width / 2.0; + proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)}, + dp(800.0f), 255 * 0.075, 255 * 0.15); + + android::uirenderer::Rect DUMMY; + + std::vector< sp<RenderNode> > cards; + + DisplayListRenderer* renderer = startRecording(rootNode); + animation.createContent(width, height, renderer); + endRecording(renderer, rootNode); + + for (int i = 0; i < 150; i++) { + testContext.waitForVsync(); + + ATRACE_NAME("UI-Draw Frame"); + animation.doFrame(i); + nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); + proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density); + } - return node; -} + sleep(5); -int main(int argc, char* argv[]) { - TestContext testContext; - - // create the native surface - const int width = gDisplay.w; - const int height = gDisplay.h; - sp<Surface> surface = testContext.surface(); - - RenderNode* rootNode = new RenderNode(); - rootNode->incStrong(nullptr); - rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height); - rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - rootNode->mutateStagingProperties().setClipToBounds(false); - rootNode->setPropertyFieldsDirty(RenderNode::GENERIC); - - ContextFactory factory; - std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory)); - proxy->loadSystemProperties(); - proxy->initialize(surface); - float lightX = width / 2.0; - proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)}, - dp(800.0f), 255 * 0.075, 255 * 0.15); - - android::uirenderer::Rect DUMMY; + rootNode->decStrong(nullptr); + } +}; +class ShadowGridAnimation : public TreeContentAnimation { +public: std::vector< sp<RenderNode> > cards; + void createContent(int width, int height, DisplayListRenderer* renderer) override { + android::uirenderer::Rect DUMMY; + + renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); + renderer->insertReorderBarrier(true); + + for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { + for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { + sp<RenderNode> card = createCard(x, y, dp(100), dp(100)); + renderer->drawRenderNode(card.get(), DUMMY, 0); + cards.push_back(card); + } + } - DisplayListRenderer* renderer = startRecording(rootNode); - renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - renderer->insertReorderBarrier(true); - - for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { - for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { - sp<RenderNode> card = createCard(x, y, dp(100), dp(100)); - renderer->drawRenderNode(card.get(), DUMMY, 0); - cards.push_back(card); + renderer->insertReorderBarrier(false); + } + void doFrame(int frameNr) override { + for (size_t ci = 0; ci < cards.size(); ci++) { + cards[ci]->mutateStagingProperties().setTranslationX(frameNr); + cards[ci]->mutateStagingProperties().setTranslationY(frameNr); + cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); } } +private: + sp<RenderNode> createCard(int x, int y, int width, int height) { + sp<RenderNode> node = new RenderNode(); + node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); + node->mutateStagingProperties().setElevation(dp(16)); + node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1); + node->mutateStagingProperties().mutableOutline().setShouldClip(true); + node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z); + + DisplayListRenderer* renderer = startRecording(node.get()); + renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode); + endRecording(renderer, node.get()); + return node; + } +}; - renderer->insertReorderBarrier(false); - endRecording(renderer, rootNode); +class RectGridAnimation : public TreeContentAnimation { +public: + sp<RenderNode> card; + void createContent(int width, int height, DisplayListRenderer* renderer) override { + android::uirenderer::Rect DUMMY; - for (int i = 0; i < 150; i++) { - testContext.waitForVsync(); + renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); + renderer->insertReorderBarrier(true); - ATRACE_NAME("UI-Draw Frame"); - for (size_t ci = 0; ci < cards.size(); ci++) { - cards[ci]->mutateStagingProperties().setTranslationX(i); - cards[ci]->mutateStagingProperties().setTranslationY(i); - cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + card = createCard(40, 40, 200, 200); + renderer->drawRenderNode(card.get(), DUMMY, 0); + + renderer->insertReorderBarrier(false); + } + void doFrame(int frameNr) override { + card->mutateStagingProperties().setTranslationX(frameNr); + card->mutateStagingProperties().setTranslationY(frameNr); + card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + } +private: + sp<RenderNode> createCard(int x, int y, int width, int height) { + sp<RenderNode> node = new RenderNode(); + node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); + node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + + DisplayListRenderer* renderer = startRecording(node.get()); + renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode); + + float rects[width * height]; + int index = 0; + for (int xOffset = 0; xOffset < width; xOffset+=2) { + for (int yOffset = 0; yOffset < height; yOffset+=2) { + rects[index++] = xOffset; + rects[index++] = yOffset; + rects[index++] = xOffset + 1; + rects[index++] = yOffset + 1; + } } - nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); - proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density); + int count = width * height; + + SkPaint paint; + paint.setColor(0xff00ffff); + renderer->drawRects(rects, count, &paint); + + endRecording(renderer, node.get()); + return node; } +}; - sleep(5); +struct cstr_cmp { + bool operator()(const char *a, const char *b) const { + return std::strcmp(a, b) < 0; + } +}; - rootNode->decStrong(nullptr); +typedef void (*testProc)(); +std::map<const char*, testProc, cstr_cmp> gTestMap { + {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>}, + {"rectgrid", TreeContentAnimation::run<RectGridAnimation> }, +}; + +int main(int argc, char* argv[]) { + const char* testName = argc > 1 ? argv[1] : "shadowgrid"; + testProc proc = gTestMap[testName]; + if(!proc) { + printf("Error: couldn't find test %s\n", testName); + return 1; + } + proc(); printf("Success!\n"); return 0; } diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h index fa0ae03..2091705 100644 --- a/libs/hwui/utils/PaintUtils.h +++ b/libs/hwui/utils/PaintUtils.h @@ -16,6 +16,9 @@ #ifndef PAINT_UTILS_H #define PAINT_UTILS_H +#include <SkColorFilter.h> +#include <SkXfermode.h> + namespace android { namespace uirenderer { |