Merge "Early kickoff of shadow tasks"

This commit is contained in:
Chris Craik
2016-02-03 01:17:37 +00:00
committed by Android (Google) Code Review
13 changed files with 187 additions and 160 deletions

View File

@@ -663,13 +663,7 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f
}
void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
TessellationCache::vertexBuffer_pair_t buffers;
renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
&op.shadowMatrixXY, &op.shadowMatrixZ,
op.lightCenter, renderer.getLightInfo().lightRadius,
buffers);
TessellationCache::vertexBuffer_pair_t buffers = *(op.shadowTask->getResult());
renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
}

View File

@@ -45,13 +45,11 @@ public:
* Position agnostic shadow lighting info. Used with all shadow ops in scene.
*/
struct LightInfo {
LightInfo() : LightInfo(0, 0, 0) {}
LightInfo(float lightRadius, uint8_t ambientShadowAlpha,
LightInfo() : LightInfo(0, 0) {}
LightInfo(uint8_t ambientShadowAlpha,
uint8_t spotShadowAlpha)
: lightRadius(lightRadius)
, ambientShadowAlpha(ambientShadowAlpha)
: ambientShadowAlpha(ambientShadowAlpha)
, spotShadowAlpha(spotShadowAlpha) {}
float lightRadius;
uint8_t ambientShadowAlpha;
uint8_t spotShadowAlpha;
};

View File

@@ -63,16 +63,11 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
}
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
transform = *snapshot.transform;
// Since the op doesn't have known bounds, we conservatively set the mapped bounds
// to the current clipRect, and clipSideFlags to Full.
clipState = snapshot.mutateClipArea().serializeClip(allocator);
LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
clippedBounds = clipState->rect;
clipSideFlags = OpClipSideFlags::Full;
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot)
: transform(*snapshot.transform)
, clipState(snapshot.mutateClipArea().serializeClip(allocator))
, clippedBounds(clipState->rect)
, clipSideFlags(OpClipSideFlags::Full) {}
ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect)
: transform(Matrix4::identity())

View File

@@ -33,17 +33,11 @@ namespace uirenderer {
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
: FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightCenter,
Rect(0, 0, 0, 0)) {
}
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
const Rect &contentDrawBounds)
: mCanvasState(*this) {
const std::vector< sp<RenderNode> >& nodes,
const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches* caches)
: mCanvasState(*this)
, mCaches(caches)
, mLightRadius(lightGeometry.radius) {
ATRACE_NAME("prepare drawing commands");
mLayerBuilders.reserve(layers.entries().size());
@@ -55,7 +49,7 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
mLayerStack.push_back(0);
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
lightCenter);
lightGeometry.center);
// Render all layers to be updated, in order. Defer in reverse order, so that they'll be
// updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
@@ -367,13 +361,28 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
casterPath = frameAllocatedPath;
}
ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
mCanvasState.getLocalClipBounds(),
mCanvasState.currentSnapshot()->getRelativeLightCenter());
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
if (CC_LIKELY(bakedOpState)) {
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
node.applyViewPropertyTransforms(shadowMatrixXY, false);
node.applyViewPropertyTransforms(shadowMatrixZ, true);
LOG_ALWAYS_FATAL_IF(!mCaches, "Caches needed for shadows");
sp<TessellationCache::ShadowTask> task = mCaches->tessellationCache.getShadowTask(
mCanvasState.currentTransform(),
mCanvasState.getLocalClipBounds(),
casterAlpha >= 1.0f,
casterPath,
&shadowMatrixXY, &shadowMatrixZ,
mCanvasState.currentSnapshot()->getRelativeLightCenter(),
mLightRadius);
ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha);
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
if (CC_LIKELY(bakedOpState)) {
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
}
}
}

View File

@@ -55,14 +55,24 @@ class Rect;
*/
class FrameBuilder : public CanvasStateClient {
public:
struct LightGeometry {
Vector3 center;
float radius;
};
// TODO: remove
FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
const std::vector< sp<RenderNode> >& nodes,
const LightGeometry& lightGeometry,
Caches* caches)
: FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightGeometry, Rect(), caches) {}
FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
const Rect &contentDrawBounds);
const std::vector< sp<RenderNode> >& nodes,
const LightGeometry& lightGeometry,
const Rect &contentDrawBounds, Caches* caches);
virtual ~FrameBuilder() {}
@@ -216,7 +226,11 @@ private:
CanvasState mCanvasState;
// contains ResolvedOps and Batches
Caches* mCaches = nullptr;
float mLightRadius;
// contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
LinearAllocator mAllocator;
};

View File

@@ -22,6 +22,7 @@
#include "Matrix.h"
#include "Rect.h"
#include "RenderNode.h"
#include "TessellationCache.h"
#include "utils/LinearAllocator.h"
#include "Vector.h"
@@ -346,25 +347,13 @@ struct VectorDrawableOp : RecordedOp {
* State construction handles these properties specially, ignoring matrix/bounds.
*/
struct ShadowOp : RecordedOp {
ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
const Rect& localClipRect, const Vector3& lightCenter)
ShadowOp(sp<TessellationCache::ShadowTask>& shadowTask, float casterAlpha)
: RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowMatrixXY(casterOp.localMatrix)
, shadowMatrixZ(casterOp.localMatrix)
, casterAlpha(casterAlpha)
, casterPath(casterPath)
, localClipRect(localClipRect)
, lightCenter(lightCenter) {
const RenderNode& node = *casterOp.renderNode;
node.applyViewPropertyTransforms(shadowMatrixXY, false);
node.applyViewPropertyTransforms(shadowMatrixZ, true);
, shadowTask(shadowTask)
, casterAlpha(casterAlpha) {
};
Matrix4 shadowMatrixXY;
Matrix4 shadowMatrixZ;
sp<TessellationCache::ShadowTask> shadowTask;
const float casterAlpha;
const SkPath* casterPath;
const Rect localClipRect;
const Vector3 lightCenter;
};
struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)

View File

@@ -160,45 +160,6 @@ private:
// Shadow tessellation task processing
///////////////////////////////////////////////////////////////////////////////
class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
public:
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius)
: drawTransform(*drawTransform)
, localClip(localClip)
, opaque(opaque)
, casterPerimeter(*casterPerimeter)
, transformXY(*transformXY)
, transformZ(*transformZ)
, lightCenter(lightCenter)
, lightRadius(lightRadius) {
}
~ShadowTask() {
TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
delete bufferPair->getFirst();
delete bufferPair->getSecond();
delete bufferPair;
}
/* Note - we deep copy all task parameters, because *even though* pointers into Allocator
* controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
* certain Allocators are destroyed before trim() is called to flush incomplete tasks.
*
* These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
* before tearning down single-frame LinearAllocators.
*/
const Matrix4 drawTransform;
const Rect localClip;
bool opaque;
const SkPath casterPerimeter;
const Matrix4 transformXY;
const Matrix4 transformZ;
const Vector3 lightCenter;
const float lightRadius;
};
static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
// map z coordinate with true 3d matrix
point.z = transformZ->mapZ(point);
@@ -288,7 +249,7 @@ public:
~ShadowProcessor() {}
virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override {
ShadowTask* t = static_cast<ShadowTask*>(task.get());
TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(task.get());
ATRACE_NAME("shadow tessellation");
VertexBuffer* ambientBuffer = new VertexBuffer;
@@ -415,6 +376,29 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec
outBuffers = *(task->getResult());
}
sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
const Matrix4* drawTransform, const Rect& localClip,
bool opaque, const SkPath* casterPerimeter,
const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
if (!task) {
precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
transformXY, transformZ, lightCenter, lightRadius);
task = static_cast<ShadowTask*>(mShadowCache.get(key));
}
LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
return task;
}
TessellationCache::ShadowTask::~ShadowTask() {
TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
delete bufferPair->getFirst();
delete bufferPair->getSecond();
delete bufferPair;
}
///////////////////////////////////////////////////////////////////////////////
// Tessellation precaching
///////////////////////////////////////////////////////////////////////////////

View File

@@ -26,6 +26,7 @@
#include "utils/Pair.h"
#include <SkPaint.h>
#include <SkPath.h>
#include <utils/LruCache.h>
#include <utils/Mutex.h>
@@ -33,7 +34,6 @@
class SkBitmap;
class SkCanvas;
class SkPath;
struct SkRect;
namespace android {
@@ -89,6 +89,40 @@ public:
hash_t hash() const;
};
class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
public:
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius)
: drawTransform(*drawTransform)
, localClip(localClip)
, opaque(opaque)
, casterPerimeter(*casterPerimeter)
, transformXY(*transformXY)
, transformZ(*transformZ)
, lightCenter(lightCenter)
, lightRadius(lightRadius) {
}
~ShadowTask();
/* Note - we deep copy all task parameters, because *even though* pointers into Allocator
* controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
* certain Allocators are destroyed before trim() is called to flush incomplete tasks.
*
* These deep copies could be avoided, long term, by cancelling or flushing outstanding
* tasks before tearing down single-frame LinearAllocators.
*/
const Matrix4 drawTransform;
const Rect localClip;
bool opaque;
const SkPath casterPerimeter;
const Matrix4 transformXY;
const Matrix4 transformZ;
const Vector3 lightCenter;
const float lightRadius;
};
TessellationCache();
~TessellationCache();
@@ -133,17 +167,22 @@ public:
const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint,
float width, float height, float rx, float ry);
// TODO: delete these when switching to HWUI_NEW_OPS
void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
bool opaque, const SkPath* casterPerimeter,
const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius);
void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
bool opaque, const SkPath* casterPerimeter,
const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius,
vertexBuffer_pair_t& outBuffers);
sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip,
bool opaque, const SkPath* casterPerimeter,
const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius);
private:
class Buffer;
class TessellationTask;

View File

@@ -33,10 +33,6 @@
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
#if HWUI_NEW_OPS
#include "FrameBuilder.h"
#endif
#include <cutils/properties.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <private/hwui/DrawGlInfo.h>
@@ -152,7 +148,7 @@ bool CanvasContext::pauseSurface(ANativeWindow* window) {
void CanvasContext::setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
#if HWUI_NEW_OPS
mLightInfo.lightRadius = lightRadius;
mLightGeometry.radius = lightRadius;
mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
mLightInfo.spotShadowAlpha = spotShadowAlpha;
#else
@@ -163,7 +159,7 @@ void CanvasContext::setup(int width, int height, float lightRadius,
void CanvasContext::setLightCenter(const Vector3& lightCenter) {
#if HWUI_NEW_OPS
mLightCenter = lightCenter;
mLightGeometry.center = lightCenter;
#else
if (!mCanvas) return;
mCanvas->setLightCenter(lightCenter);
@@ -345,7 +341,7 @@ void CanvasContext::draw() {
#if HWUI_NEW_OPS
FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
mRenderNodes, mLightCenter, mContentDrawBounds);
mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
mLayerUpdateQueue.clear();
BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
mOpaque, mLightInfo);

View File

@@ -31,6 +31,7 @@
#if HWUI_NEW_OPS
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
#include "FrameBuilder.h"
#endif
#include <cutils/compiler.h>
@@ -197,7 +198,7 @@ private:
OpenGLRenderer* mCanvas = nullptr;
#if HWUI_NEW_OPS
BakedOpRenderer::LightInfo mLightInfo;
Vector3 mLightCenter = { 0, 0, 0 };
FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
#endif
bool mHaveNewSurface = false;

View File

@@ -37,7 +37,8 @@ using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::test;
const LayerUpdateQueue sEmptyLayerUpdateQueue;
const Vector3 sLightCenter = {100, 100, 100};
const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
static std::vector<sp<RenderNode>> createTestNodeList() {
auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -67,7 +68,7 @@ void BM_FrameBuilder_defer::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightCenter);
nodes, sLightGeometry, nullptr);
MicroBench::DoNotOptimize(&frameBuilder);
}
StopBenchmarkTiming();
@@ -77,7 +78,6 @@ BENCHMARK_NO_ARG(BM_FrameBuilder_deferAndRender);
void BM_FrameBuilder_deferAndRender::Run(int iters) {
TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
auto nodes = createTestNodeList();
BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 };
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
@@ -85,9 +85,9 @@ void BM_FrameBuilder_deferAndRender::Run(int iters) {
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightCenter);
nodes, sLightGeometry, nullptr);
BakedOpRenderer renderer(caches, renderState, true, lightInfo);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
MicroBench::DoNotOptimize(&renderer);
}
@@ -119,7 +119,7 @@ static void benchDeferScene(testing::Benchmark& benchmark, int iters, const char
for (int i = 0; i < iters; i++) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightCenter);
nodes, sLightGeometry, nullptr);
MicroBench::DoNotOptimize(&frameBuilder);
}
benchmark.StopBenchmarkTiming();
@@ -129,7 +129,6 @@ static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
int iters, const char* sceneName) {
TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
auto nodes = getSyncedSceneNodes(sceneName);
BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 }; // TODO!
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
@@ -138,9 +137,9 @@ static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
for (int i = 0; i < iters; i++) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightCenter);
nodes, sLightGeometry, nullptr);
BakedOpRenderer renderer(caches, renderState, true, lightInfo);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
MicroBench::DoNotOptimize(&renderer);
}

View File

@@ -30,7 +30,8 @@ namespace android {
namespace uirenderer {
const LayerUpdateQueue sEmptyLayerUpdateQueue;
const Vector3 sLightCenter = {100, 100, 100};
const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
/**
* Virtual class implemented by each test to redirect static operation / state transitions to
@@ -132,7 +133,7 @@ TEST(FrameBuilder, simple) {
canvas.drawBitmap(bitmap, 10, 10, nullptr);
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
@@ -158,7 +159,7 @@ TEST(FrameBuilder, simpleStroke) {
canvas.drawPoint(50, 50, strokedPaint);
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SimpleStrokeTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
@@ -173,7 +174,7 @@ TEST(FrameBuilder, simpleRejection) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
FailRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -208,7 +209,7 @@ TEST(FrameBuilder, simpleBatching) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SimpleBatchingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
@@ -250,7 +251,7 @@ TEST(FrameBuilder, DISABLED_clippedMerging) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
ClippedMergingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -278,7 +279,7 @@ TEST(FrameBuilder, textMerging) {
TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
TextMergingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
@@ -309,7 +310,7 @@ TEST(FrameBuilder, textStrikethrough) {
}
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
TextStrikethroughTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
@@ -343,7 +344,7 @@ RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
TextureLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
@@ -388,7 +389,7 @@ TEST(FrameBuilder, renderNode) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(parent), sLightCenter);
TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
RenderNodeTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -412,7 +413,7 @@ TEST(FrameBuilder, clipped) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
ClippedTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -454,7 +455,7 @@ TEST(FrameBuilder, saveLayer_simple) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SaveLayerSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -526,7 +527,7 @@ TEST(FrameBuilder, saveLayer_nested) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SaveLayerNestedTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
@@ -546,7 +547,7 @@ TEST(FrameBuilder, saveLayer_contentRejection) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
FailRenderer renderer;
// should see no ops, even within the layer, since the layer should be rejected
@@ -589,7 +590,7 @@ TEST(FrameBuilder, saveLayerUnclipped_simple) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SaveLayerUnclippedSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -643,7 +644,7 @@ TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
canvas.restoreToCount(restoreTo);
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SaveLayerUnclippedMergedClearsTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex())
@@ -705,7 +706,7 @@ TEST(FrameBuilder, saveLayerUnclipped_complex) {
canvas.restore();
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
SaveLayerUnclippedComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(12, renderer.getIndex());
@@ -763,7 +764,7 @@ RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedNodeList, sLightCenter);
syncedNodeList, sLightGeometry, nullptr);
HwLayerSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(6, renderer.getIndex());
@@ -864,7 +865,7 @@ RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedList, sLightCenter);
syncedList, sLightGeometry, nullptr);
HwLayerComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(13, renderer.getIndex());
@@ -913,7 +914,7 @@ TEST(FrameBuilder, zReorder) {
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
TestUtils::createSyncedNodeList(parent), sLightCenter);
TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
ZReorderTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
@@ -996,7 +997,7 @@ TEST(FrameBuilder, projectionReorder) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
TestUtils::createSyncedNodeList(parent), sLightCenter);
TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
ProjectionReorderTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(3, renderer.getIndex());
@@ -1014,18 +1015,18 @@ static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
});
}
TEST(FrameBuilder, shadow) {
RENDERTHREAD_TEST(FrameBuilder, shadow) {
class ShadowTestRenderer : public TestRendererBase {
public:
void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
EXPECT_TRUE(op.casterPath->isRect(nullptr));
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
Matrix4 expectedZ;
expectedZ.loadTranslate(0, 0, 5);
EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
@@ -1039,13 +1040,13 @@ TEST(FrameBuilder, shadow) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(parent), sLightCenter);
TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
ShadowTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
}
TEST(FrameBuilder, shadowSaveLayer) {
RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
class ShadowSaveLayerTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -1054,8 +1055,8 @@ TEST(FrameBuilder, shadowSaveLayer) {
}
void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
EXPECT_FLOAT_EQ(50, op.lightCenter.x);
EXPECT_FLOAT_EQ(40, op.lightCenter.y);
EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
@@ -1080,7 +1081,9 @@ TEST(FrameBuilder, shadowSaveLayer) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
TestUtils::createSyncedNodeList(parent),
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
&Caches::getInstance());
ShadowSaveLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
@@ -1094,8 +1097,9 @@ RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
}
void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
EXPECT_FLOAT_EQ(50, op.lightCenter.x);
EXPECT_FLOAT_EQ(40, op.lightCenter.y);
EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
@@ -1130,7 +1134,9 @@ RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedList, (Vector3) { 100, 100, 100 });
syncedList,
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
&Caches::getInstance());
ShadowHwLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
@@ -1159,7 +1165,9 @@ TEST(FrameBuilder, shadowLayering) {
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(parent), sLightCenter);
TestUtils::createSyncedNodeList(parent),
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
&Caches::getInstance());
ShadowLayeringTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -1187,7 +1195,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
PropertyTestRenderer renderer(opValidateCallback);
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
@@ -1328,7 +1336,8 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
});
auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
nodes, sLightGeometry, nullptr);
SaveLayerAlphaClipTestRenderer renderer(outObservedData);
frameBuilder.replayBakedOps<TestDispatcher>(renderer);

View File

@@ -27,7 +27,8 @@ using namespace android;
using namespace android::uirenderer;
const LayerUpdateQueue sEmptyLayerUpdateQueue;
const Vector3 sLightCenter = {100, 100, 100};
const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -36,12 +37,11 @@ RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
});
BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128};
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightCenter);
BakedOpRenderer renderer(caches, renderState, true, lightInfo);
TestUtils::createSyncedNodeList(node), sLightGeometery, nullptr);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}