• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 class GrAppliedClip;
55 class GrDstProxyView;
56 class GrGLSLProgramDataManager;
57 class GrRecordingContext;
58 class GrCaps;
59 enum class GrXferBarrierFlags;
60 namespace skgpu { class KeyBuilder; }
61 struct GrContextOptions;
62 struct GrShaderCaps;
63 
64 /**
65  * This is a GPU-backend specific test for dynamic pipeline state. It draws boxes using dynamic
66  * scissor rectangles then reads back the result to verify a successful test.
67  */
68 
69 static constexpr int kScreenSize = 6;
70 static constexpr int kNumMeshes = 4;
71 static constexpr int kScreenSplitX = kScreenSize/2;
72 static constexpr int kScreenSplitY = kScreenSize/2;
73 
74 static const SkIRect kDynamicScissors[kNumMeshes] = {
75     SkIRect::MakeLTRB(0,              0,              kScreenSplitX,  kScreenSplitY),
76     SkIRect::MakeLTRB(0,              kScreenSplitY,  kScreenSplitX,  kScreenSize),
77     SkIRect::MakeLTRB(kScreenSplitX,  0,              kScreenSize,    kScreenSplitY),
78     SkIRect::MakeLTRB(kScreenSplitX,  kScreenSplitY,  kScreenSize,    kScreenSize),
79 };
80 
81 static const GrColor kMeshColors[kNumMeshes] {
82     GrColorPackRGBA(255, 0, 0, 255),
83     GrColorPackRGBA(0, 255, 0, 255),
84     GrColorPackRGBA(0, 0, 255, 255),
85     GrColorPackRGBA(0, 0, 0, 255)
86 };
87 
88 struct Vertex {
89     float     fX;
90     float     fY;
91     GrColor   fColor;
92 };
93 
94 namespace {
95 class PipelineDynamicStateTestProcessor : public GrGeometryProcessor {
96 public:
Make(SkArenaAlloc * arena)97     static GrGeometryProcessor* Make(SkArenaAlloc* arena) {
98         return arena->make(
99                 [&](void* ptr) { return new (ptr) PipelineDynamicStateTestProcessor(); });
100     }
101 
name() const102     const char* name() const override { return "GrPipelineDynamicStateTest Processor"; }
103 
addToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const104     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const final {}
105 
106     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
107 
108 private:
PipelineDynamicStateTestProcessor()109     PipelineDynamicStateTestProcessor() : INHERITED(kGrPipelineDynamicStateTestProcessor_ClassID) {
110         this->setVertexAttributesWithImplicitOffsets(kAttributes, std::size(kAttributes));
111     }
112 
inVertex() const113     const Attribute& inVertex() const { return kAttributes[0]; }
inColor() const114     const Attribute& inColor() const { return kAttributes[1]; }
115 
116     inline static constexpr Attribute kAttributes[] = {
117             {"vertex", kFloat2_GrVertexAttribType, SkSLType::kHalf2},
118             {"color", kUByte4_norm_GrVertexAttribType, SkSLType::kHalf4},
119     };
120 
121     friend class GLSLPipelineDynamicStateTestProcessor;
122     using INHERITED = GrGeometryProcessor;
123 };
124 }  // anonymous namespace
125 
126 std::unique_ptr<GrGeometryProcessor::ProgramImpl>
makeProgramImpl(const GrShaderCaps &) const127 PipelineDynamicStateTestProcessor::makeProgramImpl(const GrShaderCaps&) const {
128     class Impl : public GrGeometryProcessor::ProgramImpl {
129     public:
130         void setData(const GrGLSLProgramDataManager&,
131                      const GrShaderCaps&,
132                      const GrGeometryProcessor&) final {}
133 
134         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
135             const PipelineDynamicStateTestProcessor& mp =
136                     args.fGeomProc.cast<PipelineDynamicStateTestProcessor>();
137             GrGLSLVertexBuilder* v = args.fVertBuilder;
138             GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
139 
140             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
141             varyingHandler->emitAttributes(mp);
142             f->codeAppendf("half4 %s;", args.fOutputColor);
143             varyingHandler->addPassThroughAttribute(mp.inColor().asShaderVar(), args.fOutputColor);
144 
145             v->codeAppendf("float2 vertex = %s;", mp.inVertex().name());
146             gpArgs->fPositionVar.set(SkSLType::kFloat2, "vertex");
147             f->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
148         }
149     };
150     return std::make_unique<Impl>();
151 }
152 
153 namespace {
154 class GrPipelineDynamicStateTestOp : public GrDrawOp {
155 public:
156     DEFINE_OP_CLASS_ID
157 
Make(GrRecordingContext * context,GrScissorTest scissorTest,sk_sp<const GrBuffer> vbuff)158     static GrOp::Owner Make(GrRecordingContext* context,
159                             GrScissorTest scissorTest,
160                             sk_sp<const GrBuffer> vbuff) {
161         return GrOp::Make<GrPipelineDynamicStateTestOp>(context, scissorTest, std::move(vbuff));
162     }
163 
164 private:
165     friend class GrOp;
166 
GrPipelineDynamicStateTestOp(GrScissorTest scissorTest,sk_sp<const GrBuffer> vbuff)167     GrPipelineDynamicStateTestOp(GrScissorTest scissorTest, sk_sp<const GrBuffer> vbuff)
168         : INHERITED(ClassID())
169         , fScissorTest(scissorTest)
170         , fVertexBuffer(std::move(vbuff)) {
171         this->setBounds(SkRect::MakeIWH(kScreenSize, kScreenSize),
172                         HasAABloat::kNo, IsHairline::kNo);
173     }
174 
name() const175     const char* name() const override { return "GrPipelineDynamicStateTestOp"; }
fixedFunctionFlags() const176     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)177     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
178         return GrProcessorSet::EmptySetAnalysis();
179     }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)180     void onPrePrepare(GrRecordingContext*,
181                       const GrSurfaceProxyView& writeView,
182                       GrAppliedClip*,
183                       const GrDstProxyView&,
184                       GrXferBarrierFlags renderPassXferBarriers,
185                       GrLoadOp colorLoadOp) override {}
onPrepare(GrOpFlushState *)186     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)187     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
188         GrPipeline pipeline(fScissorTest, SkBlendMode::kSrc,
189                             flushState->drawOpArgs().writeView().swizzle());
190         SkSTArray<kNumMeshes, GrSimpleMesh> meshes;
191         for (int i = 0; i < kNumMeshes; ++i) {
192             GrSimpleMesh& mesh = meshes.push_back();
193             mesh.set(fVertexBuffer, 4, 4 * i);
194         }
195 
196         auto geomProc = PipelineDynamicStateTestProcessor::Make(flushState->allocator());
197 
198         GrProgramInfo programInfo(flushState->caps(),
199                                   flushState->writeView(),
200                                   flushState->usesMSAASurface(),
201                                   &pipeline,
202                                   &GrUserStencilSettings::kUnused,
203                                   geomProc,
204                                   GrPrimitiveType::kTriangleStrip,
205                                   flushState->renderPassBarriers(),
206                                   flushState->colorLoadOp());
207 
208         flushState->bindPipeline(programInfo, SkRect::MakeIWH(kScreenSize, kScreenSize));
209         for (int i = 0; i < 4; ++i) {
210             if (fScissorTest == GrScissorTest::kEnabled) {
211                 flushState->setScissorRect(kDynamicScissors[i]);
212             }
213             flushState->drawMesh(meshes[i]);
214         }
215     }
216 
217     GrScissorTest               fScissorTest;
218     const sk_sp<const GrBuffer> fVertexBuffer;
219 
220     using INHERITED = GrDrawOp;
221 };
222 }  // anonymous namespace
223 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)224 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest,
225                                        reporter,
226                                        ctxInfo,
227                                        CtsEnforcement::kApiLevel_T) {
228     auto dContext = ctxInfo.directContext();
229     GrResourceProvider* rp = dContext->priv().resourceProvider();
230 
231     auto sdc = skgpu::v1::SurfaceDrawContext::Make(
232             dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
233             {kScreenSize, kScreenSize}, SkSurfaceProps(), /*label=*/{});
234     if (!sdc) {
235         ERRORF(reporter, "could not create render target context.");
236         return;
237     }
238 
239     constexpr float d = (float) kScreenSize;
240     Vertex vdata[kNumMeshes * 4] = {
241         {0, 0, kMeshColors[0]},
242         {0, d, kMeshColors[0]},
243         {d, 0, kMeshColors[0]},
244         {d, d, kMeshColors[0]},
245 
246         {0, 0, kMeshColors[1]},
247         {0, d, kMeshColors[1]},
248         {d, 0, kMeshColors[1]},
249         {d, d, kMeshColors[1]},
250 
251         {0, 0, kMeshColors[2]},
252         {0, d, kMeshColors[2]},
253         {d, 0, kMeshColors[2]},
254         {d, d, kMeshColors[2]},
255 
256         {0, 0, kMeshColors[3]},
257         {0, d, kMeshColors[3]},
258         {d, 0, kMeshColors[3]},
259         {d, d, kMeshColors[3]}
260     };
261 
262     sk_sp<const GrBuffer> vbuff(rp->createBuffer(vdata,
263                                                  sizeof(vdata),
264                                                  GrGpuBufferType::kVertex,
265                                                  kDynamic_GrAccessPattern));
266     if (!vbuff) {
267         ERRORF(reporter, "vbuff is null.");
268         return;
269     }
270 
271     uint32_t resultPx[kScreenSize * kScreenSize];
272 
273     for (GrScissorTest scissorTest : {GrScissorTest::kEnabled, GrScissorTest::kDisabled}) {
274         sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
275         sdc->addDrawOp(GrPipelineDynamicStateTestOp::Make(dContext, scissorTest, vbuff));
276         auto ii = SkImageInfo::Make(kScreenSize, kScreenSize,
277                                     kRGBA_8888_SkColorType, kPremul_SkAlphaType);
278         GrPixmap resultPM(ii, resultPx, kScreenSize*sizeof(uint32_t));
279         sdc->readPixels(dContext, resultPM, {0, 0});
280         for (int y = 0; y < kScreenSize; ++y) {
281             for (int x = 0; x < kScreenSize; ++x) {
282                 int expectedColorIdx;
283                 if (GrScissorTest::kEnabled == scissorTest) {
284                     expectedColorIdx = (x < kScreenSplitX ? 0 : 2) + (y < kScreenSplitY ? 0 : 1);
285                 } else {
286                     expectedColorIdx = kNumMeshes - 1;
287                 }
288                 uint32_t expected = kMeshColors[expectedColorIdx];
289                 uint32_t actual = resultPx[y * kScreenSize + x];
290                 if (expected != actual) {
291                     ERRORF(reporter, "[scissor=%s] pixel (%i,%i): got 0x%x expected 0x%x",
292                            GrScissorTest::kEnabled == scissorTest ? "enabled" : "disabled", x, y,
293                            actual, expected);
294                     return;
295                 }
296             }
297         }
298     }
299 }
300