xref: /aosp_15_r20/external/skia/tests/GrPipelineDynamicStateTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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