xref: /aosp_15_r20/external/skia/gm/attributes.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2021 Google LLC
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 "gm/gm.h"
9 #include "include/core/SkPoint.h"
10 #include "include/core/SkRect.h"
11 #include "include/gpu/ganesh/GrRecordingContext.h"
12 #include "src/core/SkCanvasPriv.h"
13 #include "src/gpu/KeyBuilder.h"
14 #include "src/gpu/ganesh/GrBuffer.h"
15 #include "src/gpu/ganesh/GrCanvas.h"
16 #include "src/gpu/ganesh/GrGeometryProcessor.h"
17 #include "src/gpu/ganesh/GrGpuBuffer.h"
18 #include "src/gpu/ganesh/GrOpFlushState.h"
19 #include "src/gpu/ganesh/GrProcessor.h"
20 #include "src/gpu/ganesh/GrProcessorSet.h"
21 #include "src/gpu/ganesh/GrProgramInfo.h"
22 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
23 #include "src/gpu/ganesh/GrResourceProvider.h"
24 #include "src/gpu/ganesh/GrShaderVar.h"
25 #include "src/gpu/ganesh/SurfaceDrawContext.h"
26 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
27 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
28 #include "src/gpu/ganesh/ops/GrDrawOp.h"
29 #include "src/gpu/ganesh/ops/GrOp.h"
30 #include "tools/gpu/ProxyUtils.h"
31 
32 #include <memory>
33 #include <vector>
34 
35 class GrAppliedClip;
36 class GrGLSLProgramDataManager;
37 
38 namespace {
39 
40 enum class AttrMode {
41     kAuto,
42     kManual,
43     kWacky
44 };
45 
46 class AttributeTestProcessor : public GrGeometryProcessor {
47 public:
Make(SkArenaAlloc * arena,AttrMode mode)48     static GrGeometryProcessor* Make(SkArenaAlloc* arena, AttrMode mode) {
49         return arena->make([&](void* ptr) { return new (ptr) AttributeTestProcessor(mode); });
50     }
51 
name() const52     const char* name() const final { return "AttributeTestProcessor"; }
53 
addToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const54     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const final {
55         b->add32(static_cast<uint32_t>(fMode));
56     }
57 
58     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
59 
60 private:
AttributeTestProcessor(AttrMode mode)61     AttributeTestProcessor(AttrMode mode)
62             : GrGeometryProcessor(kAttributeTestProcessor_ClassID), fMode(mode) {
63         switch (fMode) {
64             case AttrMode::kAuto:
65                 fAttributes.emplace_back("pos", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
66                 fAttributes.emplace_back("color", kUByte4_norm_GrVertexAttribType,
67                                          SkSLType::kHalf4);
68                 this->setVertexAttributesWithImplicitOffsets(fAttributes.data(),
69                                                              fAttributes.size());
70                 break;
71             case AttrMode::kManual:
72                 // Same result as kAuto but with explicitly specified offsets and stride.
73                 fAttributes.emplace_back("pos", kFloat2_GrVertexAttribType, SkSLType::kFloat2, 0);
74                 fAttributes.emplace_back("color", kUByte4_norm_GrVertexAttribType,
75                                          SkSLType::kHalf4, 8);
76                 this->setVertexAttributes(fAttributes.data(), fAttributes.size(), 12);
77                 break;
78             case AttrMode::kWacky:
79                 //  0 thru  7 : float2 aliased to "pos0" and "pos1"
80                 //  8 thru 11: pad
81                 // 12 thru 15: unorm4 "color"
82                 // 16 thru 19: pad
83                 fAttributes.emplace_back("pos0", kFloat2_GrVertexAttribType, SkSLType::kFloat2, 0);
84                 fAttributes.emplace_back("pos1", kFloat2_GrVertexAttribType, SkSLType::kFloat2, 0);
85                 fAttributes.emplace_back("color", kUByte4_norm_GrVertexAttribType,
86                                          SkSLType::kHalf4, 12);
87                 this->setVertexAttributes(fAttributes.data(), fAttributes.size(), 20);
88                 break;
89         }
90     }
91 
92     const AttrMode fMode;
93 
94     std::vector<Attribute> fAttributes;
95 
96     using INHERITED = GrGeometryProcessor;
97 };
98 
makeProgramImpl(const GrShaderCaps &) const99 std::unique_ptr<GrGeometryProcessor::ProgramImpl> AttributeTestProcessor::makeProgramImpl(
100         const GrShaderCaps&) const {
101     class Impl : public ProgramImpl {
102     public:
103         void setData(const GrGLSLProgramDataManager&,
104                      const GrShaderCaps&,
105                      const GrGeometryProcessor&) override {}
106 
107     private:
108         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
109             const AttributeTestProcessor& proc = args.fGeomProc.cast<AttributeTestProcessor>();
110             args.fVaryingHandler->emitAttributes(proc);
111             if (proc.fMode == AttrMode::kWacky) {
112                 args.fVertBuilder->codeAppend("float2 pos = pos0 + pos1;");
113             }
114             args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
115             args.fVaryingHandler->addPassThroughAttribute(GrShaderVar("color", SkSLType::kHalf4),
116                                                           args.fOutputColor);
117             gpArgs->fPositionVar.set(SkSLType::kFloat2, "pos");
118             args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
119         }
120     };
121 
122     return std::make_unique<Impl>();
123 }
124 
125 class AttributeTestOp : public GrDrawOp {
126 public:
127     DEFINE_OP_CLASS_ID
128 
Make(GrRecordingContext * context,AttrMode mode,const SkRect & r)129     static GrOp::Owner Make(GrRecordingContext* context, AttrMode mode, const SkRect& r) {
130         return GrOp::Make<AttributeTestOp>(context, mode, r);
131     }
132 
133 private:
AttributeTestOp(AttrMode mode,SkRect rect)134     AttributeTestOp(AttrMode mode, SkRect rect) : GrDrawOp(ClassID()), fMode(mode), fRect(rect) {
135         this->setBounds(fRect, HasAABloat::kNo, IsHairline::kNo);
136     }
137 
name() const138     const char* name() const override { return "AttributeTestOp"; }
fixedFunctionFlags() const139     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)140     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
141         return GrProcessorSet::EmptySetAnalysis();
142     }
143 
createProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp) const144     GrProgramInfo* createProgramInfo(const GrCaps* caps,
145                                      SkArenaAlloc* arena,
146                                      const GrSurfaceProxyView& writeView,
147                                      bool usesMSAASurface,
148                                      GrAppliedClip&& appliedClip,
149                                      const GrDstProxyView& dstProxyView,
150                                      GrXferBarrierFlags renderPassXferBarriers,
151                                      GrLoadOp colorLoadOp) const {
152         GrGeometryProcessor* geomProc = AttributeTestProcessor::Make(arena, fMode);
153 
154         return sk_gpu_test::CreateProgramInfo(caps,
155                                               arena,
156                                               writeView,
157                                               usesMSAASurface,
158                                               std::move(appliedClip),
159                                               dstProxyView,
160                                               geomProc,
161                                               SkBlendMode::kSrcOver,
162                                               GrPrimitiveType::kTriangleStrip,
163                                               renderPassXferBarriers,
164                                               colorLoadOp);
165     }
166 
createProgramInfo(GrOpFlushState * flushState) const167     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
168         return this->createProgramInfo(&flushState->caps(),
169                                        flushState->allocator(),
170                                        flushState->writeView(),
171                                        flushState->usesMSAASurface(),
172                                        flushState->detachAppliedClip(),
173                                        flushState->dstProxyView(),
174                                        flushState->renderPassBarriers(),
175                                        flushState->colorLoadOp());
176     }
177 
onPrePrepare(GrRecordingContext * context,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)178     void onPrePrepare(GrRecordingContext* context,
179                       const GrSurfaceProxyView& writeView,
180                       GrAppliedClip* clip,
181                       const GrDstProxyView& dstProxyView,
182                       GrXferBarrierFlags renderPassXferBarriers,
183                       GrLoadOp colorLoadOp) final {
184         SkArenaAlloc* arena = context->priv().recordTimeAllocator();
185 
186         // DMSAA is not supported on DDL.
187         bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
188 
189         // This is equivalent to a GrOpFlushState::detachAppliedClip
190         GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
191 
192         fProgramInfo = this->createProgramInfo(context->priv().caps(),
193                                                arena,
194                                                writeView,
195                                                usesMSAASurface,
196                                                std::move(appliedClip),
197                                                dstProxyView,
198                                                renderPassXferBarriers,
199                                                colorLoadOp);
200 
201         context->priv().recordProgramInfo(fProgramInfo);
202     }
203 
makeVB(GrOpFlushState * flushState,const SkRect rect)204     template <typename V> void makeVB(GrOpFlushState* flushState, const SkRect rect) {
205         V v[4];
206         v[0].p = {rect.left() , rect.top()   };
207         v[1].p = {rect.right(), rect.top()   };
208         v[2].p = {rect.left() , rect.bottom()};
209         v[3].p = {rect.right(), rect.bottom()};
210         v[0].color = SK_ColorRED;
211         v[1].color = SK_ColorGREEN;
212         v[2].color = SK_ColorYELLOW;
213         v[3].color = SK_ColorMAGENTA;
214         fVertexBuffer = flushState->resourceProvider()->createBuffer(v,
215                                                                      sizeof(v),
216                                                                      GrGpuBufferType::kVertex,
217                                                                      kStatic_GrAccessPattern);
218     }
219 
onPrepare(GrOpFlushState * flushState)220     void onPrepare(GrOpFlushState* flushState) override {
221         if (fMode == AttrMode::kWacky) {
222             struct V {
223                 SkPoint p;
224                 uint32_t pad0;
225                 uint32_t color;
226                 uint32_t pad1;
227             };
228             SkRect rect {fRect.fLeft/2.f, fRect.fTop/2.f, fRect.fRight/2.f, fRect.fBottom/2.f};
229             this->makeVB<V>(flushState, rect);
230         } else {
231             struct V {
232                 SkPoint p;
233                 uint32_t color;
234             };
235             this->makeVB<V>(flushState, fRect);
236         }
237     }
238 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)239     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
240         if (!fVertexBuffer) {
241             return;
242         }
243 
244         if (!fProgramInfo) {
245             fProgramInfo = this->createProgramInfo(flushState);
246         }
247 
248         flushState->bindPipeline(*fProgramInfo, fRect);
249         flushState->bindBuffers(nullptr, nullptr, std::move(fVertexBuffer));
250         flushState->draw(4, 0);
251     }
252 
253     sk_sp<GrBuffer> fVertexBuffer;
254     const AttrMode  fMode;
255     const SkRect    fRect;
256 
257     // The program info (and both the GrPipeline and GrGeometryProcessor it relies on), when
258     // allocated, are allocated in either the ddl-record-time or flush-time arena. It is the
259     // arena's job to free up their memory so we just have a bare programInfo pointer here. We
260     // don't even store the GrPipeline and GrGeometryProcessor pointers here bc they are
261     // guaranteed to have the same lifetime as the program info.
262     GrProgramInfo* fProgramInfo = nullptr;
263 
264     friend class ::GrOp;  // for ctor
265 
266     using INHERITED = GrDrawOp;
267 };
268 
269 }  // namespace
270 
271 namespace skiagm {
272 
273 /**
274  * This is a GPU-backend specific test that exercises explicit and implicit attribute offsets and
275  * strides.
276  */
277 class AttributesGM : public GpuGM {
getName() const278     SkString getName() const override { return SkString("attributes"); }
getISize()279     SkISize getISize() override { return {120, 340}; }
280     DrawResult onDraw(GrRecordingContext*, SkCanvas*, SkString* errorMsg) override;
281 };
282 
onDraw(GrRecordingContext * rc,SkCanvas * canvas,SkString * errorMsg)283 DrawResult AttributesGM::onDraw(GrRecordingContext* rc, SkCanvas* canvas, SkString* errorMsg) {
284     auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
285     if (!sdc) {
286         *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
287         return DrawResult::kSkip;
288     }
289 
290     sdc->clear(SK_PMColor4fBLACK);
291 
292     // Draw the test directly to the frame buffer.
293     auto r = SkRect::MakeXYWH(10, 10, 100, 100);
294     for (AttrMode m : {AttrMode::kAuto, AttrMode::kManual, AttrMode::kWacky}) {
295         sdc->addDrawOp(AttributeTestOp::Make(rc, m, r));
296         r.offset(0, 110);
297     }
298 
299     return DrawResult::kOk;
300 }
301 
302 ////////////////////////////////////////////////////////////////////////////////////////////////////
303 
304 DEF_GM( return new AttributesGM(); )
305 
306 }  // namespace skiagm
307