aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-rw-r--r--src/gpu/GrGpuCommandBuffer.cpp3
-rw-r--r--src/gpu/GrGpuCommandBuffer.h5
-rw-r--r--src/gpu/GrPipeline.cpp22
-rw-r--r--src/gpu/GrPipeline.h21
-rw-r--r--src/gpu/gl/GrGLGpu.cpp9
-rw-r--r--src/gpu/gl/GrGLGpu.h3
-rw-r--r--src/gpu/gl/GrGLGpuCommandBuffer.h5
-rw-r--r--src/gpu/ops/GrMeshDrawOp.cpp3
-rw-r--r--src/gpu/vk/GrVkGpuCommandBuffer.cpp35
-rw-r--r--src/gpu/vk/GrVkGpuCommandBuffer.h6
-rw-r--r--src/gpu/vk/GrVkPipeline.cpp76
-rw-r--r--src/gpu/vk/GrVkPipeline.h9
-rw-r--r--tests/GpuSampleLocationsTest.cpp14
-rw-r--r--tests/GrMeshTest.cpp4
-rw-r--r--tests/GrPipelineDynamicStateTest.cpp219
16 files changed, 351 insertions, 84 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 0263dd6249..1b438f44ce 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -92,6 +92,7 @@ tests_sources = [
"$_tests/GrDrawTargetTest.cpp",
"$_tests/GrMemoryPoolTest.cpp",
"$_tests/GrMeshTest.cpp",
+ "$_tests/GrPipelineDynamicStateTest.cpp",
"$_tests/GrPorterDuffTest.cpp",
"$_tests/GrShapeTest.cpp",
"$_tests/GrSKSLPrettyPrintTest.cpp",
diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp
index 5570a5a65e..9659ca3b9a 100644
--- a/src/gpu/GrGpuCommandBuffer.cpp
+++ b/src/gpu/GrGpuCommandBuffer.cpp
@@ -39,6 +39,7 @@ void GrGpuCommandBuffer::clearStencilClip(GrRenderTarget* rt, const GrFixedClip&
bool GrGpuCommandBuffer::draw(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
const GrMesh meshes[],
+ const GrPipeline::DynamicState dynamicStates[],
int meshCount,
const SkRect& bounds) {
#ifdef SK_DEBUG
@@ -58,7 +59,7 @@ bool GrGpuCommandBuffer::draw(const GrPipeline& pipeline,
this->gpu()->stats()->incNumFailedDraws();
return false;
}
- this->onDraw(pipeline, primProc, meshes, meshCount, bounds);
+ this->onDraw(pipeline, primProc, meshes, dynamicStates, meshCount, bounds);
return true;
}
diff --git a/src/gpu/GrGpuCommandBuffer.h b/src/gpu/GrGpuCommandBuffer.h
index fb5dc00943..3a6a3e7005 100644
--- a/src/gpu/GrGpuCommandBuffer.h
+++ b/src/gpu/GrGpuCommandBuffer.h
@@ -9,6 +9,7 @@
#define GrGpuCommandBuffer_DEFINED
#include "GrColor.h"
+#include "GrPipeline.h"
#include "ops/GrDrawOp.h"
class GrOpFlushState;
@@ -69,6 +70,7 @@ public:
bool draw(const GrPipeline&,
const GrPrimitiveProcessor&,
const GrMesh[],
+ const GrPipeline::DynamicState[],
int meshCount,
const SkRect& bounds);
@@ -99,7 +101,8 @@ private:
// overridden by backend-specific derived class to perform the draw call.
virtual void onDraw(const GrPipeline&,
const GrPrimitiveProcessor&,
- const GrMesh*,
+ const GrMesh[],
+ const GrPipeline::DynamicState[],
int meshCount,
const SkRect& bounds) = 0;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 8d1b926be1..9d8b2ef984 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -112,15 +112,19 @@ void GrPipeline::addDependenciesTo(GrRenderTargetProxy* rtp) const {
}
}
-GrPipeline::GrPipeline(GrRenderTarget* rt, SkBlendMode blendmode)
- : fRenderTarget(rt)
- , fScissorState()
- , fWindowRectsState()
- , fUserStencilSettings(&GrUserStencilSettings::kUnused)
- , fFlags()
- , fXferProcessor(GrPorterDuffXPFactory::MakeNoCoverageXP(blendmode))
- , fFragmentProcessors()
- , fNumColorProcessors(0) {}
+GrPipeline::GrPipeline(GrRenderTarget* rt, ScissorState scissorState, SkBlendMode blendmode)
+ : fRenderTarget(rt)
+ , fScissorState()
+ , fWindowRectsState()
+ , fUserStencilSettings(&GrUserStencilSettings::kUnused)
+ , fFlags()
+ , fXferProcessor(GrPorterDuffXPFactory::MakeNoCoverageXP(blendmode))
+ , fFragmentProcessors()
+ , fNumColorProcessors(0) {
+ if (ScissorState::kEnabled == scissorState) {
+ fScissorState.set({0, 0, 0, 0}); // caller will use the DynamicState struct.
+ }
+}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 078cb68437..3fd518985d 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -68,6 +68,11 @@ public:
return flags;
}
+ enum ScissorState : bool {
+ kEnabled = true,
+ kDisabled = false
+ };
+
struct InitArgs {
uint32_t fFlags = 0;
const GrProcessorSet* fProcessors = nullptr; // Must be finalized
@@ -80,16 +85,26 @@ public:
};
/**
+ * Graphics state that can change dynamically without creating a new pipeline.
+ **/
+ struct DynamicState {
+ // Overrides the scissor rectangle (if scissor is enabled in the pipeline).
+ // TODO: eventually this should be the only way to specify a scissor rectangle, as is the
+ // case with the simple constructor.
+ SkIRect fScissorRect;
+ };
+
+ /**
* A Default constructed pipeline is unusable until init() is called.
**/
GrPipeline() = default;
/**
* Creates a simple pipeline with default settings and no processors. The provided blend mode
- * must be "Porter Duff" (<= kLastCoeffMode). This pipeline is initialized without requiring
- * a call to init().
+ * must be "Porter Duff" (<= kLastCoeffMode). If using ScissorState::kEnabled, the caller must
+ * specify a scissor rectangle through the DynamicState struct.
**/
- GrPipeline(GrRenderTarget*, SkBlendMode);
+ GrPipeline(GrRenderTarget*, ScissorState, SkBlendMode);
GrPipeline(const InitArgs& args) { this->init(args); }
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index b6c807656f..50c0edba45 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2449,6 +2449,7 @@ GrGLenum gPrimitiveType2GLMode[] = {
void GrGLGpu::draw(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
const GrMesh meshes[],
+ const GrPipeline::DynamicState dynamicStates[],
int meshCount) {
this->handleDirtyContext();
@@ -2468,6 +2469,14 @@ void GrGLGpu::draw(const GrPipeline& pipeline,
this->xferBarrier(pipeline.getRenderTarget(), barrierType);
}
+ if (dynamicStates) {
+ if (pipeline.getScissorState().enabled()) {
+ GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
+ this->flushScissor(dynamicStates[i].fScissorRect,
+ glRT->getViewport(), glRT->origin());
+ }
+ }
+
meshes[i].sendToGpu(primProc, this);
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 1785eae143..639b589f50 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -101,7 +101,8 @@ public:
// on GrGLGpuCommandBuffer.
void draw(const GrPipeline&,
const GrPrimitiveProcessor&,
- const GrMesh*,
+ const GrMesh[],
+ const GrPipeline::DynamicState[],
int meshCount);
diff --git a/src/gpu/gl/GrGLGpuCommandBuffer.h b/src/gpu/gl/GrGLGpuCommandBuffer.h
index c7c76a4a9c..c6e7208f4c 100644
--- a/src/gpu/gl/GrGLGpuCommandBuffer.h
+++ b/src/gpu/gl/GrGLGpuCommandBuffer.h
@@ -49,7 +49,8 @@ private:
void onDraw(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
- const GrMesh* mesh,
+ const GrMesh mesh[],
+ const GrPipeline::DynamicState dynamicStates[],
int meshCount,
const SkRect& bounds) override {
GrGLRenderTarget* target = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
@@ -57,7 +58,7 @@ private:
fRenderTarget = target;
}
SkASSERT(target == fRenderTarget);
- fGpu->draw(pipeline, primProc, mesh, meshCount);
+ fGpu->draw(pipeline, primProc, mesh, dynamicStates, meshCount);
}
void onClear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) override {
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index d6c2ced38a..d1367e9c9c 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -74,7 +74,8 @@ void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
const QueuedDraw& draw = fQueuedDraws[currDrawIdx];
SkASSERT(draw.fPipeline->getRenderTarget() == state->drawOpArgs().fRenderTarget);
state->commandBuffer()->draw(*draw.fPipeline, *draw.fGeometryProcessor.get(),
- fMeshes.begin() + currMeshIdx, draw.fMeshCnt, this->bounds());
+ fMeshes.begin() + currMeshIdx, nullptr, draw.fMeshCnt,
+ this->bounds());
currMeshIdx += draw.fMeshCnt;
state->flushToken();
}
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 6f39cfa545..6e9c292f04 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -468,7 +468,8 @@ void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
sk_sp<GrVkPipelineState> GrVkGpuCommandBuffer::prepareDrawState(
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
- GrPrimitiveType primitiveType) {
+ GrPrimitiveType primitiveType,
+ bool hasDynamicState) {
CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
SkASSERT(cbInfo.fRenderPass);
@@ -492,7 +493,18 @@ sk_sp<GrVkPipelineState> GrVkGpuCommandBuffer::prepareDrawState(
pipelineState->bind(fGpu, cbInfo.currentCmdBuf());
- GrVkPipeline::SetDynamicState(fGpu, cbInfo.currentCmdBuf(), pipeline);
+ GrRenderTarget* rt = pipeline.getRenderTarget();
+
+ if (!pipeline.getScissorState().enabled()) {
+ GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(), rt,
+ SkIRect::MakeWH(rt->width(), rt->height()));
+ } else if (!hasDynamicState) {
+ GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(), rt,
+ pipeline.getScissorState().rect());
+ }
+ GrVkPipeline::SetDynamicViewportState(fGpu, cbInfo.currentCmdBuf(), rt);
+ GrVkPipeline::SetDynamicBlendConstantState(fGpu, cbInfo.currentCmdBuf(), rt->config(),
+ pipeline.getXferProcessor());
return pipelineState;
}
@@ -533,7 +545,8 @@ static void prepare_sampled_images(const GrResourceIOProcessor& processor, GrVkG
void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
- const GrMesh* meshes,
+ const GrMesh meshes[],
+ const GrPipeline::DynamicState dynamicStates[],
int meshCount,
const SkRect& bounds) {
GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(pipeline.getRenderTarget());
@@ -557,11 +570,14 @@ void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline,
GrPrimitiveType primitiveType = meshes[0].primitiveType();
sk_sp<GrVkPipelineState> pipelineState = this->prepareDrawState(pipeline,
primProc,
- primitiveType);
+ primitiveType,
+ SkToBool(dynamicStates));
if (!pipelineState) {
return;
}
+ CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
+
for (int i = 0; i < meshCount; ++i) {
const GrMesh& mesh = meshes[i];
if (mesh.primitiveType() != primitiveType) {
@@ -573,17 +589,24 @@ void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline,
primitiveType = mesh.primitiveType();
pipelineState = this->prepareDrawState(pipeline,
primProc,
- primitiveType);
+ primitiveType,
+ SkToBool(dynamicStates));
if (!pipelineState) {
return;
}
}
+ if (dynamicStates) {
+ if (pipeline.getScissorState().enabled()) {
+ GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(),
+ target, dynamicStates[i].fScissorRect);
+ }
+ }
+
SkASSERT(pipelineState);
mesh.sendToGpu(primProc, this);
}
- CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
cbInfo.fBounds.join(bounds);
cbInfo.fIsEmpty = false;
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.h b/src/gpu/vk/GrVkGpuCommandBuffer.h
index 6836fac0ca..9ef166e7db 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.h
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.h
@@ -53,11 +53,13 @@ private:
sk_sp<GrVkPipelineState> prepareDrawState(const GrPipeline&,
const GrPrimitiveProcessor&,
- GrPrimitiveType);
+ GrPrimitiveType,
+ bool hasDynamicState);
void onDraw(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
- const GrMesh* mesh,
+ const GrMesh mesh[],
+ const GrPipeline::DynamicState[],
int meshCount,
const SkRect& bounds) override;
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index 2732c6fc80..0b4289edec 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -481,65 +481,56 @@ void GrVkPipeline::freeGPUData(const GrVkGpu* gpu) const {
GR_VK_CALL(gpu->vkInterface(), DestroyPipeline(gpu->device(), fPipeline, nullptr));
}
-static void set_dynamic_scissor_state(GrVkGpu* gpu,
- GrVkCommandBuffer* cmdBuffer,
- const GrPipeline& pipeline,
- const GrRenderTarget& target) {
- // We always use one scissor and if it is disabled we just make it the size of the RT
- const GrScissorState& scissorState = pipeline.getScissorState();
- VkRect2D scissor;
- if (scissorState.enabled() &&
- !scissorState.rect().contains(0, 0, target.width(), target.height())) {
- // This all assumes the scissorState has previously been clipped to the device space render
- // target.
- scissor.offset.x = SkTMax(scissorState.rect().fLeft, 0);
- scissor.extent.width = scissorState.rect().width();
- if (kTopLeft_GrSurfaceOrigin == target.origin()) {
- scissor.offset.y = scissorState.rect().fTop;
- } else {
- SkASSERT(kBottomLeft_GrSurfaceOrigin == target.origin());
- scissor.offset.y = target.height() - scissorState.rect().fBottom;
- }
- scissor.offset.y = SkTMax(scissor.offset.y, 0);
- scissor.extent.height = scissorState.rect().height();
+void GrVkPipeline::SetDynamicScissorRectState(GrVkGpu* gpu,
+ GrVkCommandBuffer* cmdBuffer,
+ const GrRenderTarget* renderTarget,
+ SkIRect scissorRect) {
+ if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) {
+ scissorRect.setEmpty();
+ }
- SkASSERT(scissor.offset.x >= 0);
- SkASSERT(scissor.offset.y >= 0);
+ VkRect2D scissor;
+ scissor.offset.x = scissorRect.fLeft;
+ scissor.extent.width = scissorRect.width();
+ if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) {
+ scissor.offset.y = scissorRect.fTop;
} else {
- scissor.extent.width = target.width();
- scissor.extent.height = target.height();
- scissor.offset.x = 0;
- scissor.offset.y = 0;
+ SkASSERT(kBottomLeft_GrSurfaceOrigin == renderTarget->origin());
+ scissor.offset.y = renderTarget->height() - scissorRect.fBottom;
}
+ scissor.extent.height = scissorRect.height();
+
+ SkASSERT(scissor.offset.x >= 0);
+ SkASSERT(scissor.offset.y >= 0);
cmdBuffer->setScissor(gpu, 0, 1, &scissor);
}
-static void set_dynamic_viewport_state(GrVkGpu* gpu,
- GrVkCommandBuffer* cmdBuffer,
- const GrRenderTarget& target) {
+void GrVkPipeline::SetDynamicViewportState(GrVkGpu* gpu,
+ GrVkCommandBuffer* cmdBuffer,
+ const GrRenderTarget* renderTarget) {
// We always use one viewport the size of the RT
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = 0.0f;
- viewport.width = SkIntToScalar(target.width());
- viewport.height = SkIntToScalar(target.height());
+ viewport.width = SkIntToScalar(renderTarget->width());
+ viewport.height = SkIntToScalar(renderTarget->height());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
cmdBuffer->setViewport(gpu, 0, 1, &viewport);
}
-static void set_dynamic_blend_constant_state(GrVkGpu* gpu,
- GrVkCommandBuffer* cmdBuffer,
- const GrPipeline& pipeline) {
+void GrVkPipeline::SetDynamicBlendConstantState(GrVkGpu* gpu,
+ GrVkCommandBuffer* cmdBuffer,
+ GrPixelConfig pixelConfig,
+ const GrXferProcessor& xferProcessor) {
GrXferProcessor::BlendInfo blendInfo;
- pipeline.getXferProcessor().getBlendInfo(&blendInfo);
+ xferProcessor.getBlendInfo(&blendInfo);
GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
float floatColors[4];
if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) {
// Swizzle the blend to match what the shader will output.
- const GrSwizzle& swizzle = gpu->caps()->shaderCaps()->configOutputSwizzle(
- pipeline.getRenderTarget()->config());
+ const GrSwizzle& swizzle = gpu->caps()->shaderCaps()->configOutputSwizzle(pixelConfig);
GrColor blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
GrColorToRGBAFloat(blendConst, floatColors);
} else {
@@ -547,12 +538,3 @@ static void set_dynamic_blend_constant_state(GrVkGpu* gpu,
}
cmdBuffer->setBlendConstants(gpu, floatColors);
}
-
-void GrVkPipeline::SetDynamicState(GrVkGpu* gpu,
- GrVkCommandBuffer* cmdBuffer,
- const GrPipeline& pipeline) {
- const GrRenderTarget& target = *pipeline.getRenderTarget();
- set_dynamic_scissor_state(gpu, cmdBuffer, pipeline, target);
- set_dynamic_viewport_state(gpu, cmdBuffer, target);
- set_dynamic_blend_constant_state(gpu, cmdBuffer, pipeline);
-}
diff --git a/src/gpu/vk/GrVkPipeline.h b/src/gpu/vk/GrVkPipeline.h
index 585014e53c..d05974b102 100644
--- a/src/gpu/vk/GrVkPipeline.h
+++ b/src/gpu/vk/GrVkPipeline.h
@@ -16,10 +16,13 @@
class GrPipeline;
class GrPrimitiveProcessor;
+class GrRenderTarget;
+class GrXferProcessor;
class GrStencilSettings;
class GrVkCommandBuffer;
class GrVkGpu;
class GrVkRenderPass;
+struct SkIRect;
class GrVkPipeline : public GrVkResource {
public:
@@ -36,7 +39,11 @@ public:
VkPipeline pipeline() const { return fPipeline; }
- static void SetDynamicState(GrVkGpu*, GrVkCommandBuffer*, const GrPipeline&);
+ static void SetDynamicScissorRectState(GrVkGpu*, GrVkCommandBuffer*, const GrRenderTarget*,
+ SkIRect);
+ static void SetDynamicViewportState(GrVkGpu*, GrVkCommandBuffer*, const GrRenderTarget*);
+ static void SetDynamicBlendConstantState(GrVkGpu*, GrVkCommandBuffer*, GrPixelConfig,
+ const GrXferProcessor&);
#ifdef SK_TRACE_VK_RESOURCES
void dumpInfo() const override {
diff --git a/tests/GpuSampleLocationsTest.cpp b/tests/GpuSampleLocationsTest.cpp
index 75d2846dd6..aaab98adda 100644
--- a/tests/GpuSampleLocationsTest.cpp
+++ b/tests/GpuSampleLocationsTest.cpp
@@ -91,10 +91,6 @@ public:
virtual ~TestSampleLocationsInterface() {}
};
-static sk_sp<GrPipeline> construct_dummy_pipeline(GrRenderTargetContext* dc) {
- return sk_sp<GrPipeline>(new GrPipeline(dc->accessRenderTarget(), SkBlendMode::kSrcOver));
-}
-
void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern,
const GrGpu::MultisampleSpecs& specs, bool flipY) {
GrAlwaysAssert(specs.fSampleLocations);
@@ -136,11 +132,13 @@ void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInter
for (int repeat = 0; repeat < 2; ++repeat) {
for (int i = 0; i < numTestPatterns; ++i) {
testInterface->overrideSamplePattern(kTestPatterns[i]);
- for (GrRenderTargetContext* dc : {bottomUps[i].get(), topDowns[i].get()}) {
- sk_sp<GrPipeline> dummyPipeline = construct_dummy_pipeline(dc);
- GrRenderTarget* rt = dc->accessRenderTarget();
+ for (GrRenderTargetContext* rtc : {bottomUps[i].get(), topDowns[i].get()}) {
+ GrPipeline dummyPipeline(rtc->accessRenderTarget(),
+ GrPipeline::ScissorState::kDisabled,
+ SkBlendMode::kSrcOver);
+ GrRenderTarget* rt = rtc->accessRenderTarget();
assert_equal(reporter, kTestPatterns[i],
- rt->renderTargetPriv().getMultisampleSpecs(*dummyPipeline),
+ rt->renderTargetPriv().getMultisampleSpecs(dummyPipeline),
kBottomLeft_GrSurfaceOrigin == rt->origin());
}
}
diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp
index 3a2be784a5..dd2a2d9e33 100644
--- a/tests/GrMeshTest.cpp
+++ b/tests/GrMeshTest.cpp
@@ -364,9 +364,9 @@ sk_sp<const GrBuffer> DrawMeshHelper::getIndexBuffer() {
void DrawMeshHelper::drawMesh(const GrMesh& mesh) {
GrRenderTarget* rt = fState->drawOpArgs().fRenderTarget;
- GrPipeline pipeline(rt, SkBlendMode::kSrc);
+ GrPipeline pipeline(rt, GrPipeline::ScissorState::kDisabled, SkBlendMode::kSrc);
GrMeshTestProcessor mtp(mesh.isInstanced(), mesh.hasVertexData());
- fState->commandBuffer()->draw(pipeline, mtp, &mesh, 1,
+ fState->commandBuffer()->draw(pipeline, mtp, &mesh, nullptr, 1,
SkRect::MakeIWH(kImageWidth, kImageHeight));
}
diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp
new file mode 100644
index 0000000000..4c5843aeb1
--- /dev/null
+++ b/tests/GrPipelineDynamicStateTest.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrColor.h"
+#include "GrGeometryProcessor.h"
+#include "GrOpFlushState.h"
+#include "GrRenderTargetContext.h"
+#include "GrRenderTargetContextPriv.h"
+#include "GrResourceProvider.h"
+#include "SkMakeUnique.h"
+#include "glsl/GrGLSLVertexShaderBuilder.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLGeometryProcessor.h"
+#include "glsl/GrGLSLVarying.h"
+
+/**
+ * This is a GPU-backend specific test for dynamic pipeline state. It draws boxes using dynamic
+ * scissor rectangles then reads back the result to verify a successful test.
+ */
+
+using ScissorState = GrPipeline::ScissorState;
+
+static constexpr int kScreenSize = 6;
+static constexpr int kNumMeshes = 4;
+static constexpr int kScreenSplitX = kScreenSize/2;
+static constexpr int kScreenSplitY = kScreenSize/2;
+
+static const GrPipeline::DynamicState kDynamicStates[kNumMeshes] = {
+ {SkIRect::MakeLTRB(0, 0, kScreenSplitX, kScreenSplitY)},
+ {SkIRect::MakeLTRB(0, kScreenSplitY, kScreenSplitX, kScreenSize)},
+ {SkIRect::MakeLTRB(kScreenSplitX, 0, kScreenSize, kScreenSplitY)},
+ {SkIRect::MakeLTRB(kScreenSplitX, kScreenSplitY, kScreenSize, kScreenSize)},
+};
+
+static const GrColor kMeshColors[kNumMeshes] {
+ GrColorPackRGBA(255, 0, 0, 255),
+ GrColorPackRGBA(0, 255, 0, 255),
+ GrColorPackRGBA(0, 0, 255, 255),
+ GrColorPackRGBA(0, 0, 0, 255)
+};
+
+struct Vertex {
+ float fX;
+ float fY;
+ GrColor fColor;
+};
+
+class GrPipelineDynamicStateTestProcessor : public GrGeometryProcessor {
+public:
+ GrPipelineDynamicStateTestProcessor()
+ : fVertex(this->addVertexAttrib("vertex", kVec2f_GrVertexAttribType))
+ , fColor(this->addVertexAttrib("color", kVec4ub_GrVertexAttribType)) {
+ this->initClassID<GrPipelineDynamicStateTestProcessor>();
+ }
+
+ const char* name() const override { return "GrPipelineDynamicStateTest Processor"; }
+
+ void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
+
+ GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
+
+protected:
+ const Attribute& fVertex;
+ const Attribute& fColor;
+
+ friend class GLSLPipelineDynamicStateTestProcessor;
+ typedef GrGeometryProcessor INHERITED;
+};
+
+class GLSLPipelineDynamicStateTestProcessor : public GrGLSLGeometryProcessor {
+ void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
+ FPCoordTransformIter&& transformIter) final {}
+
+ void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
+ const GrPipelineDynamicStateTestProcessor& mp =
+ args.fGP.cast<GrPipelineDynamicStateTestProcessor>();
+
+ GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
+ varyingHandler->emitAttributes(mp);
+ varyingHandler->addPassThroughAttribute(&mp.fColor, args.fOutputColor);
+
+ GrGLSLVertexBuilder* v = args.fVertBuilder;
+ v->codeAppendf("vec2 vertex = %s;", mp.fVertex.fName);
+ gpArgs->fPositionVar.set(kVec2f_GrSLType, "vertex");
+
+ GrGLSLPPFragmentBuilder* f = args.fFragBuilder;
+ f->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
+ }
+};
+
+GrGLSLPrimitiveProcessor*
+GrPipelineDynamicStateTestProcessor::createGLSLInstance(const GrShaderCaps&) const {
+ return new GLSLPipelineDynamicStateTestProcessor;
+}
+
+class GrPipelineDynamicStateTestOp : public GrDrawOp {
+public:
+ DEFINE_OP_CLASS_ID
+
+ GrPipelineDynamicStateTestOp(ScissorState scissorState, sk_sp<const GrBuffer> vbuff)
+ : INHERITED(ClassID())
+ , fScissorState(scissorState)
+ , fVertexBuffer(std::move(vbuff)) {
+ this->setBounds(SkRect::MakeIWH(kScreenSize, kScreenSize),
+ HasAABloat::kNo, IsZeroArea::kNo);
+ }
+
+private:
+ const char* name() const override { return "GrPipelineDynamicStateTestOp"; }
+ FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
+ bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override { return false; }
+ bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
+ void onPrepare(GrOpFlushState*) override {}
+ void onExecute(GrOpFlushState* state) override {
+ GrRenderTarget* rt = state->drawOpArgs().fRenderTarget;
+ GrPipeline pipeline(rt, fScissorState, SkBlendMode::kSrc);
+ SkSTArray<kNumMeshes, GrMesh> meshes;
+ for (int i = 0; i < kNumMeshes; ++i) {
+ GrMesh& mesh = meshes.emplace_back(kTriangleStrip_GrPrimitiveType);
+ mesh.setNonIndexedNonInstanced(4);
+ mesh.setVertexData(fVertexBuffer.get(), 4 * i);
+ }
+ state->commandBuffer()->draw(pipeline, GrPipelineDynamicStateTestProcessor(),
+ meshes.begin(), kDynamicStates, 4,
+ SkRect::MakeIWH(kScreenSize, kScreenSize));
+ }
+
+ ScissorState fScissorState;
+ const sk_sp<const GrBuffer> fVertexBuffer;
+
+ typedef GrDrawOp INHERITED;
+};
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest, reporter, ctxInfo) {
+ GrContext* const context = ctxInfo.grContext();
+ GrResourceProvider* rp = context->resourceProvider();
+
+ sk_sp<GrRenderTargetContext> rtc(
+ context->makeDeferredRenderTargetContext(SkBackingFit::kExact, kScreenSize, kScreenSize,
+ kRGBA_8888_GrPixelConfig, nullptr));
+ if (!rtc) {
+ ERRORF(reporter, "could not create render target context.");
+ return;
+ }
+
+ constexpr float d = (float) kScreenSize;
+ Vertex vdata[kNumMeshes * 4] = {
+ {0, 0, kMeshColors[0]},
+ {0, d, kMeshColors[0]},
+ {d, 0, kMeshColors[0]},
+ {d, d, kMeshColors[0]},
+
+ {0, 0, kMeshColors[1]},
+ {0, d, kMeshColors[1]},
+ {d, 0, kMeshColors[1]},
+ {d, d, kMeshColors[1]},
+
+ {0, 0, kMeshColors[2]},
+ {0, d, kMeshColors[2]},
+ {d, 0, kMeshColors[2]},
+ {d, d, kMeshColors[2]},
+
+ {0, 0, kMeshColors[3]},
+ {0, d, kMeshColors[3]},
+ {d, 0, kMeshColors[3]},
+ {d, d, kMeshColors[3]}
+ };
+
+ sk_sp<const GrBuffer> vbuff(rp->createBuffer(sizeof(vdata), kVertex_GrBufferType,
+ kDynamic_GrAccessPattern,
+ GrResourceProvider::kNoPendingIO_Flag |
+ GrResourceProvider::kRequireGpuMemory_Flag,
+ vdata));
+ if (!vbuff) {
+ ERRORF(reporter, "vbuff is null.");
+ return;
+ }
+
+ uint32_t resultPx[kScreenSize * kScreenSize];
+
+ for (ScissorState scissorState : {ScissorState::kEnabled, ScissorState::kDisabled}) {
+ rtc->clear(nullptr, 0xbaaaaaad, true);
+ rtc->priv().testingOnly_addDrawOp(
+ skstd::make_unique<GrPipelineDynamicStateTestOp>(scissorState, vbuff));
+ rtc->readPixels(SkImageInfo::Make(kScreenSize, kScreenSize,
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType),
+ resultPx, 4 * kScreenSize, 0, 0, 0);
+ for (int y = 0; y < kScreenSize; ++y) {
+ for (int x = 0; x < kScreenSize; ++x) {
+ int expectedColorIdx;
+ if (ScissorState::kEnabled == scissorState) {
+ expectedColorIdx = (x < kScreenSplitX ? 0 : 2) + (y < kScreenSplitY ? 0 : 1);
+ } else {
+ expectedColorIdx = kNumMeshes - 1;
+ }
+ uint32_t expected = kMeshColors[expectedColorIdx];
+ uint32_t actual = resultPx[y * kScreenSize + x];
+ if (expected != actual) {
+ ERRORF(reporter, "[scissor=%s] pixel (%i,%i): got 0x%x expected 0x%x",
+ ScissorState::kEnabled == scissorState ? "enabled" : "disabled", x, y,
+ actual, expected);
+ return;
+ }
+ }
+ }
+ }
+}
+
+#endif