1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkSurfaceProps.h"
16 #include "include/core/SkTypes.h"
17 #include "include/gpu/ganesh/GrDirectContext.h"
18 #include "include/private/SkColorData.h"
19 #include "include/private/base/SkTArray.h"
20 #include "include/private/gpu/ganesh/GrTypesPriv.h"
21 #include "src/base/SkArenaAlloc.h"
22 #include "src/core/SkSLTypeShared.h"
23 #include "src/gpu/SkBackingFit.h"
24 #include "src/gpu/ganesh/GrBuffer.h"
25 #include "src/gpu/ganesh/GrColor.h"
26 #include "src/gpu/ganesh/GrDirectContextPriv.h"
27 #include "src/gpu/ganesh/GrGeometryProcessor.h"
28 #include "src/gpu/ganesh/GrImageInfo.h"
29 #include "src/gpu/ganesh/GrOpFlushState.h"
30 #include "src/gpu/ganesh/GrPipeline.h"
31 #include "src/gpu/ganesh/GrPixmap.h"
32 #include "src/gpu/ganesh/GrProcessorSet.h"
33 #include "src/gpu/ganesh/GrProgramInfo.h"
34 #include "src/gpu/ganesh/GrResourceProvider.h"
35 #include "src/gpu/ganesh/GrShaderVar.h"
36 #include "src/gpu/ganesh/GrSimpleMesh.h"
37 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
38 #include "src/gpu/ganesh/GrUserStencilSettings.h"
39 #include "src/gpu/ganesh/SurfaceDrawContext.h"
40 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
41 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
42 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
43 #include "src/gpu/ganesh/ops/GrDrawOp.h"
44 #include "src/gpu/ganesh/ops/GrOp.h"
45 #include "tests/CtsEnforcement.h"
46 #include "tests/Test.h"
47
48 #include <array>
49 #include <cstdint>
50 #include <initializer_list>
51 #include <memory>
52 #include <utility>
53
54 using namespace skia_private;
55
56 class GrAppliedClip;
57 class GrDstProxyView;
58 class GrGLSLProgramDataManager;
59 class GrRecordingContext;
60 class GrCaps;
61 enum class GrXferBarrierFlags;
62 namespace skgpu { class KeyBuilder; }
63 struct GrContextOptions;
64 struct GrShaderCaps;
65
66 /**
67 * This is a GPU-backend specific test for dynamic pipeline state. It draws boxes using dynamic
68 * scissor rectangles then reads back the result to verify a successful test.
69 */
70
71 static constexpr int kScreenSize = 6;
72 static constexpr int kNumMeshes = 4;
73 static constexpr int kScreenSplitX = kScreenSize/2;
74 static constexpr int kScreenSplitY = kScreenSize/2;
75
76 static const SkIRect kDynamicScissors[kNumMeshes] = {
77 SkIRect::MakeLTRB(0, 0, kScreenSplitX, kScreenSplitY),
78 SkIRect::MakeLTRB(0, kScreenSplitY, kScreenSplitX, kScreenSize),
79 SkIRect::MakeLTRB(kScreenSplitX, 0, kScreenSize, kScreenSplitY),
80 SkIRect::MakeLTRB(kScreenSplitX, kScreenSplitY, kScreenSize, kScreenSize),
81 };
82
83 static const GrColor kMeshColors[kNumMeshes] {
84 GrColorPackRGBA(255, 0, 0, 255),
85 GrColorPackRGBA(0, 255, 0, 255),
86 GrColorPackRGBA(0, 0, 255, 255),
87 GrColorPackRGBA(0, 0, 0, 255)
88 };
89
90 struct Vertex {
91 float fX;
92 float fY;
93 GrColor fColor;
94 };
95
96 namespace {
97 class PipelineDynamicStateTestProcessor : public GrGeometryProcessor {
98 public:
Make(SkArenaAlloc * arena)99 static GrGeometryProcessor* Make(SkArenaAlloc* arena) {
100 return arena->make(
101 [&](void* ptr) { return new (ptr) PipelineDynamicStateTestProcessor(); });
102 }
103
name() const104 const char* name() const override { return "GrPipelineDynamicStateTest Processor"; }
105
addToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const106 void addToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const final {}
107
108 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
109
110 private:
PipelineDynamicStateTestProcessor()111 PipelineDynamicStateTestProcessor() : INHERITED(kGrPipelineDynamicStateTestProcessor_ClassID) {
112 this->setVertexAttributesWithImplicitOffsets(kAttributes, std::size(kAttributes));
113 }
114
inVertex() const115 const Attribute& inVertex() const { return kAttributes[0]; }
inColor() const116 const Attribute& inColor() const { return kAttributes[1]; }
117
118 inline static constexpr Attribute kAttributes[] = {
119 {"vertex", kFloat2_GrVertexAttribType, SkSLType::kHalf2},
120 {"color", kUByte4_norm_GrVertexAttribType, SkSLType::kHalf4},
121 };
122
123 friend class GLSLPipelineDynamicStateTestProcessor;
124 using INHERITED = GrGeometryProcessor;
125 };
126 } // anonymous namespace
127
128 std::unique_ptr<GrGeometryProcessor::ProgramImpl>
makeProgramImpl(const GrShaderCaps &) const129 PipelineDynamicStateTestProcessor::makeProgramImpl(const GrShaderCaps&) const {
130 class Impl : public GrGeometryProcessor::ProgramImpl {
131 public:
132 void setData(const GrGLSLProgramDataManager&,
133 const GrShaderCaps&,
134 const GrGeometryProcessor&) final {}
135
136 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
137 const PipelineDynamicStateTestProcessor& mp =
138 args.fGeomProc.cast<PipelineDynamicStateTestProcessor>();
139 GrGLSLVertexBuilder* v = args.fVertBuilder;
140 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
141
142 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
143 varyingHandler->emitAttributes(mp);
144 f->codeAppendf("half4 %s;", args.fOutputColor);
145 varyingHandler->addPassThroughAttribute(mp.inColor().asShaderVar(), args.fOutputColor);
146
147 v->codeAppendf("float2 vertex = %s;", mp.inVertex().name());
148 gpArgs->fPositionVar.set(SkSLType::kFloat2, "vertex");
149 f->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
150 }
151 };
152 return std::make_unique<Impl>();
153 }
154
155 namespace {
156 class GrPipelineDynamicStateTestOp : public GrDrawOp {
157 public:
158 DEFINE_OP_CLASS_ID
159
Make(GrRecordingContext * context,GrScissorTest scissorTest,sk_sp<const GrBuffer> vbuff)160 static GrOp::Owner Make(GrRecordingContext* context,
161 GrScissorTest scissorTest,
162 sk_sp<const GrBuffer> vbuff) {
163 return GrOp::Make<GrPipelineDynamicStateTestOp>(context, scissorTest, std::move(vbuff));
164 }
165
166 private:
167 friend class GrOp;
168
GrPipelineDynamicStateTestOp(GrScissorTest scissorTest,sk_sp<const GrBuffer> vbuff)169 GrPipelineDynamicStateTestOp(GrScissorTest scissorTest, sk_sp<const GrBuffer> vbuff)
170 : INHERITED(ClassID())
171 , fScissorTest(scissorTest)
172 , fVertexBuffer(std::move(vbuff)) {
173 this->setBounds(SkRect::MakeIWH(kScreenSize, kScreenSize),
174 HasAABloat::kNo, IsHairline::kNo);
175 }
176
name() const177 const char* name() const override { return "GrPipelineDynamicStateTestOp"; }
fixedFunctionFlags() const178 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)179 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
180 return GrProcessorSet::EmptySetAnalysis();
181 }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)182 void onPrePrepare(GrRecordingContext*,
183 const GrSurfaceProxyView& writeView,
184 GrAppliedClip*,
185 const GrDstProxyView&,
186 GrXferBarrierFlags renderPassXferBarriers,
187 GrLoadOp colorLoadOp) override {}
onPrepare(GrOpFlushState *)188 void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)189 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
190 GrPipeline pipeline(fScissorTest, SkBlendMode::kSrc,
191 flushState->drawOpArgs().writeView().swizzle());
192 STArray<kNumMeshes, GrSimpleMesh> meshes;
193 for (int i = 0; i < kNumMeshes; ++i) {
194 GrSimpleMesh& mesh = meshes.push_back();
195 mesh.set(fVertexBuffer, 4, 4 * i);
196 }
197
198 auto geomProc = PipelineDynamicStateTestProcessor::Make(flushState->allocator());
199
200 GrProgramInfo programInfo(flushState->caps(),
201 flushState->writeView(),
202 flushState->usesMSAASurface(),
203 &pipeline,
204 &GrUserStencilSettings::kUnused,
205 geomProc,
206 GrPrimitiveType::kTriangleStrip,
207 flushState->renderPassBarriers(),
208 flushState->colorLoadOp());
209
210 flushState->bindPipeline(programInfo, SkRect::MakeIWH(kScreenSize, kScreenSize));
211 for (int i = 0; i < 4; ++i) {
212 if (fScissorTest == GrScissorTest::kEnabled) {
213 flushState->setScissorRect(kDynamicScissors[i]);
214 }
215 flushState->drawMesh(meshes[i]);
216 }
217 }
218
219 GrScissorTest fScissorTest;
220 const sk_sp<const GrBuffer> fVertexBuffer;
221
222 using INHERITED = GrDrawOp;
223 };
224 } // anonymous namespace
225
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)226 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest,
227 reporter,
228 ctxInfo,
229 CtsEnforcement::kApiLevel_T) {
230 auto dContext = ctxInfo.directContext();
231 GrResourceProvider* rp = dContext->priv().resourceProvider();
232
233 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
234 GrColorType::kRGBA_8888,
235 nullptr,
236 SkBackingFit::kExact,
237 {kScreenSize, kScreenSize},
238 SkSurfaceProps(),
239 /*label=*/{});
240 if (!sdc) {
241 ERRORF(reporter, "could not create render target context.");
242 return;
243 }
244
245 constexpr float d = (float) kScreenSize;
246 Vertex vdata[kNumMeshes * 4] = {
247 {0, 0, kMeshColors[0]},
248 {0, d, kMeshColors[0]},
249 {d, 0, kMeshColors[0]},
250 {d, d, kMeshColors[0]},
251
252 {0, 0, kMeshColors[1]},
253 {0, d, kMeshColors[1]},
254 {d, 0, kMeshColors[1]},
255 {d, d, kMeshColors[1]},
256
257 {0, 0, kMeshColors[2]},
258 {0, d, kMeshColors[2]},
259 {d, 0, kMeshColors[2]},
260 {d, d, kMeshColors[2]},
261
262 {0, 0, kMeshColors[3]},
263 {0, d, kMeshColors[3]},
264 {d, 0, kMeshColors[3]},
265 {d, d, kMeshColors[3]}
266 };
267
268 sk_sp<const GrBuffer> vbuff(rp->createBuffer(vdata,
269 sizeof(vdata),
270 GrGpuBufferType::kVertex,
271 kDynamic_GrAccessPattern));
272 if (!vbuff) {
273 ERRORF(reporter, "vbuff is null.");
274 return;
275 }
276
277 uint32_t resultPx[kScreenSize * kScreenSize];
278
279 for (GrScissorTest scissorTest : {GrScissorTest::kEnabled, GrScissorTest::kDisabled}) {
280 sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
281 sdc->addDrawOp(GrPipelineDynamicStateTestOp::Make(dContext, scissorTest, vbuff));
282 auto ii = SkImageInfo::Make(kScreenSize, kScreenSize,
283 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
284 GrPixmap resultPM(ii, resultPx, kScreenSize*sizeof(uint32_t));
285 sdc->readPixels(dContext, resultPM, {0, 0});
286 for (int y = 0; y < kScreenSize; ++y) {
287 for (int x = 0; x < kScreenSize; ++x) {
288 int expectedColorIdx;
289 if (GrScissorTest::kEnabled == scissorTest) {
290 expectedColorIdx = (x < kScreenSplitX ? 0 : 2) + (y < kScreenSplitY ? 0 : 1);
291 } else {
292 expectedColorIdx = kNumMeshes - 1;
293 }
294 uint32_t expected = kMeshColors[expectedColorIdx];
295 uint32_t actual = resultPx[y * kScreenSize + x];
296 if (expected != actual) {
297 ERRORF(reporter, "[scissor=%s] pixel (%i,%i): got 0x%x expected 0x%x",
298 GrScissorTest::kEnabled == scissorTest ? "enabled" : "disabled", x, y,
299 actual, expected);
300 return;
301 }
302 }
303 }
304 }
305 }
306