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