xref: /aosp_15_r20/external/skia/gm/clockwise.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2018 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 "gm/gm.h"
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkString.h"
18 #include "include/core/SkTypes.h"
19 #include "include/gpu/ganesh/GrRecordingContext.h"
20 #include "include/gpu/ganesh/GrTypes.h"
21 #include "include/private/SkColorData.h"
22 #include "include/private/gpu/ganesh/GrTypesPriv.h"
23 #include "src/core/SkCanvasPriv.h"
24 #include "src/gpu/KeyBuilder.h"
25 #include "src/gpu/ganesh/GrBuffer.h"
26 #include "src/gpu/ganesh/GrCanvas.h"
27 #include "src/gpu/ganesh/GrCaps.h"
28 #include "src/gpu/ganesh/GrColorSpaceXform.h"
29 #include "src/gpu/ganesh/GrDirectContextPriv.h"
30 #include "src/gpu/ganesh/GrGeometryProcessor.h"
31 #include "src/gpu/ganesh/GrGpuBuffer.h"
32 #include "src/gpu/ganesh/GrMemoryPool.h"
33 #include "src/gpu/ganesh/GrOpFlushState.h"
34 #include "src/gpu/ganesh/GrOpsRenderPass.h"
35 #include "src/gpu/ganesh/GrPipeline.h"
36 #include "src/gpu/ganesh/GrProcessor.h"
37 #include "src/gpu/ganesh/GrProcessorSet.h"
38 #include "src/gpu/ganesh/GrProgramInfo.h"
39 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
40 #include "src/gpu/ganesh/GrResourceProvider.h"
41 #include "src/gpu/ganesh/GrSamplerState.h"
42 #include "src/gpu/ganesh/GrShaderCaps.h"
43 #include "src/gpu/ganesh/GrShaderVar.h"
44 #include "src/gpu/ganesh/GrSurfaceProxy.h"
45 #include "src/gpu/ganesh/GrTextureProxy.h"
46 #include "src/gpu/ganesh/SurfaceDrawContext.h"
47 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
48 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
49 #include "src/gpu/ganesh/ops/GrDrawOp.h"
50 #include "src/gpu/ganesh/ops/GrOp.h"
51 #include "tools/gpu/ProxyUtils.h"
52 
53 #include <memory>
54 #include <utility>
55 
56 class GrAppliedClip;
57 class GrGLSLProgramDataManager;
58 
59 namespace {
60 
61 static constexpr GrGeometryProcessor::Attribute gVertex =
62         {"position", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
63 
64 ////////////////////////////////////////////////////////////////////////////////////////////////////
65 // SkSL code.
66 
67 class ClockwiseTestProcessor : public GrGeometryProcessor {
68 public:
Make(SkArenaAlloc * arena,bool readSkFragCoord)69     static GrGeometryProcessor* Make(SkArenaAlloc* arena, bool readSkFragCoord) {
70         return arena->make([&](void* ptr) {
71             return new (ptr) ClockwiseTestProcessor(readSkFragCoord);
72         });
73     }
74 
name() const75     const char* name() const final { return "ClockwiseTestProcessor"; }
76 
addToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const77     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const final {
78         b->add32(fReadSkFragCoord);
79     }
80 
81     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
82 
readSkFragCoord() const83     bool readSkFragCoord() const { return fReadSkFragCoord; }
84 
85 private:
ClockwiseTestProcessor(bool readSkFragCoord)86     ClockwiseTestProcessor(bool readSkFragCoord)
87             : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
88             , fReadSkFragCoord(readSkFragCoord) {
89         this->setVertexAttributesWithImplicitOffsets(&gVertex, 1);
90     }
91 
92     const bool fReadSkFragCoord;
93 
94     using INHERITED = GrGeometryProcessor;
95 };
96 
makeProgramImpl(const GrShaderCaps &) const97 std::unique_ptr<GrGeometryProcessor::ProgramImpl> ClockwiseTestProcessor::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 ClockwiseTestProcessor& proc = args.fGeomProc.cast<ClockwiseTestProcessor>();
108             args.fVaryingHandler->emitAttributes(proc);
109             gpArgs->fPositionVar.set(SkSLType::kFloat2, "position");
110             args.fFragBuilder->codeAppendf(
111                     "half4 %s = sk_Clockwise ? half4(0,1,0,1) : half4(1,0,0,1);",
112                     args.fOutputColor);
113             if (!proc.readSkFragCoord()) {
114                 args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
115             } else {
116                 // Verify layout(origin_upper_left) on gl_FragCoord does not affect gl_FrontFacing.
117                 args.fFragBuilder->codeAppendf("half4 %s = half4(min(half(sk_FragCoord.y), 1));",
118                                                args.fOutputCoverage);
119             }
120         }
121     };
122 
123     return std::make_unique<Impl>();
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////////////////////////
127 // Draw Op.
128 
129 class ClockwiseTestOp : public GrDrawOp {
130 public:
131     DEFINE_OP_CLASS_ID
132 
Make(GrRecordingContext * context,bool readSkFragCoord,int y=0)133     static GrOp::Owner Make(GrRecordingContext* context,
134                             bool readSkFragCoord, int y = 0) {
135         return GrOp::Make<ClockwiseTestOp>(context, readSkFragCoord, y);
136     }
137 
138 private:
ClockwiseTestOp(bool readSkFragCoord,float y)139     ClockwiseTestOp(bool readSkFragCoord, float y)
140             : GrDrawOp(ClassID())
141             , fReadSkFragCoord(readSkFragCoord)
142             , fY(y) {
143         this->setBounds(SkRect::MakeXYWH(0, fY, 100, 100), HasAABloat::kNo, IsHairline::kNo);
144     }
145 
name() const146     const char* name() const override { return "ClockwiseTestOp"; }
fixedFunctionFlags() const147     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)148     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
149         return GrProcessorSet::EmptySetAnalysis();
150     }
151 
createProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp) const152     GrProgramInfo* createProgramInfo(const GrCaps* caps,
153                                      SkArenaAlloc* arena,
154                                      const GrSurfaceProxyView& writeView,
155                                      bool usesMSAASurface,
156                                      GrAppliedClip&& appliedClip,
157                                      const GrDstProxyView& dstProxyView,
158                                      GrXferBarrierFlags renderPassXferBarriers,
159                                      GrLoadOp colorLoadOp) const {
160         GrGeometryProcessor* geomProc = ClockwiseTestProcessor::Make(arena, fReadSkFragCoord);
161 
162         return sk_gpu_test::CreateProgramInfo(caps, arena, writeView, usesMSAASurface,
163                                               std::move(appliedClip), dstProxyView,
164                                               geomProc, SkBlendMode::kPlus,
165                                               GrPrimitiveType::kTriangleStrip,
166                                               renderPassXferBarriers, colorLoadOp);
167     }
168 
createProgramInfo(GrOpFlushState * flushState) const169     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
170         return this->createProgramInfo(&flushState->caps(),
171                                        flushState->allocator(),
172                                        flushState->writeView(),
173                                        flushState->usesMSAASurface(),
174                                        flushState->detachAppliedClip(),
175                                        flushState->dstProxyView(),
176                                        flushState->renderPassBarriers(),
177                                        flushState->colorLoadOp());
178     }
179 
onPrePrepare(GrRecordingContext * context,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)180     void onPrePrepare(GrRecordingContext* context,
181                       const GrSurfaceProxyView& writeView,
182                       GrAppliedClip* clip,
183                       const GrDstProxyView& dstProxyView,
184                       GrXferBarrierFlags renderPassXferBarriers,
185                       GrLoadOp colorLoadOp) final {
186         SkArenaAlloc* arena = context->priv().recordTimeAllocator();
187 
188         // DMSAA is not supported on DDL.
189         bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
190 
191         // This is equivalent to a GrOpFlushState::detachAppliedClip
192         GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
193 
194         fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, writeView,
195                                                usesMSAASurface, std::move(appliedClip),
196                                                dstProxyView, renderPassXferBarriers, colorLoadOp);
197 
198         context->priv().recordProgramInfo(fProgramInfo);
199     }
200 
onPrepare(GrOpFlushState * flushState)201     void onPrepare(GrOpFlushState* flushState) override {
202         SkPoint vertices[4] = {
203             {100, fY},
204             {0, fY+100},
205             {0, fY},
206             {100, fY+100},
207         };
208         fVertexBuffer = flushState->resourceProvider()->createBuffer(vertices,
209                                                                      sizeof(vertices),
210                                                                      GrGpuBufferType::kVertex,
211                                                                      kStatic_GrAccessPattern);
212     }
213 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)214     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
215         if (!fVertexBuffer) {
216             return;
217         }
218 
219         if (!fProgramInfo) {
220             fProgramInfo = this->createProgramInfo(flushState);
221         }
222 
223         flushState->bindPipeline(*fProgramInfo, SkRect::MakeXYWH(0, fY, 100, 100));
224         flushState->bindBuffers(nullptr, nullptr, std::move(fVertexBuffer));
225         flushState->draw(4, 0);
226     }
227 
228     sk_sp<GrBuffer> fVertexBuffer;
229     const bool      fReadSkFragCoord;
230     const float     fY;
231 
232     // The program info (and both the GrPipeline and GrGeometryProcessor it relies on), when
233     // allocated, are allocated in either the ddl-record-time or flush-time arena. It is the
234     // arena's job to free up their memory so we just have a bare programInfo pointer here. We
235     // don't even store the GrPipeline and GrGeometryProcessor pointers here bc they are
236     // guaranteed to have the same lifetime as the program info.
237     GrProgramInfo*  fProgramInfo = nullptr;
238 
239     friend class ::GrOp; // for ctor
240 
241     using INHERITED = GrDrawOp;
242 };
243 
244 }  // namespace
245 
246 ////////////////////////////////////////////////////////////////////////////////////////////////////
247 // Test.
248 
249 namespace skiagm {
250 
251 /**
252  * This is a GPU-backend specific test. It ensures that SkSL properly identifies clockwise-winding
253  * triangles (sk_Clockwise), in terms of to Skia device space, in all backends and with all render
254  * target origins. We draw clockwise triangles green and counter-clockwise red.
255  */
256 class ClockwiseGM : public GpuGM {
getName() const257     SkString getName() const override { return SkString("clockwise"); }
getISize()258     SkISize getISize() override { return {300, 200}; }
259     DrawResult onDraw(GrRecordingContext*, SkCanvas*, SkString* errorMsg) override;
260 };
261 
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)262 DrawResult ClockwiseGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
263     auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
264     if (!sdc) {
265         *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
266         return DrawResult::kSkip;
267     }
268 
269     sdc->clear(SK_PMColor4fBLACK);
270 
271     // Draw the test directly to the frame buffer.
272     sdc->addDrawOp(ClockwiseTestOp::Make(rContext, false, 0));
273     sdc->addDrawOp(ClockwiseTestOp::Make(rContext, true, 100));
274 
275     // Draw the test to an off-screen, top-down render target.
276     GrColorType sdcColorType = sdc->colorInfo().colorType();
277     if (auto topLeftSDC = skgpu::ganesh::SurfaceDrawContext::Make(rContext,
278                                                                   sdcColorType,
279                                                                   nullptr,
280                                                                   SkBackingFit::kExact,
281                                                                   {100, 200},
282                                                                   SkSurfaceProps(),
283                                                                   /*label=*/{},
284                                                                   /* sampleCnt= */ 1,
285                                                                   skgpu::Mipmapped::kNo,
286                                                                   GrProtected::kNo,
287                                                                   kTopLeft_GrSurfaceOrigin,
288                                                                   skgpu::Budgeted::kYes)) {
289         topLeftSDC->clear(SK_PMColor4fTRANSPARENT);
290         topLeftSDC->addDrawOp(ClockwiseTestOp::Make(rContext, false, 0));
291         topLeftSDC->addDrawOp(ClockwiseTestOp::Make(rContext, true, 100));
292         sdc->drawTexture(nullptr,
293                          topLeftSDC->readSurfaceView(),
294                          sdc->colorInfo().alphaType(),
295                          GrSamplerState::Filter::kNearest,
296                          GrSamplerState::MipmapMode::kNone,
297                          SkBlendMode::kSrcOver,
298                          SK_PMColor4fWHITE,
299                          {0, 0, 100, 200},
300                          {100, 0, 200, 200},
301                          GrQuadAAFlags::kNone,
302                          SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
303                          SkMatrix::I(),
304                          nullptr);
305     }
306 
307     // Draw the test to an off-screen, bottom-up render target.
308     if (auto topLeftSDC = skgpu::ganesh::SurfaceDrawContext::Make(rContext,
309                                                                   sdcColorType,
310                                                                   nullptr,
311                                                                   SkBackingFit::kExact,
312                                                                   {100, 200},
313                                                                   SkSurfaceProps(),
314                                                                   /*label=*/{})) {
315         topLeftSDC->clear(SK_PMColor4fTRANSPARENT);
316         topLeftSDC->addDrawOp(ClockwiseTestOp::Make(rContext, false, 0));
317         topLeftSDC->addDrawOp(ClockwiseTestOp::Make(rContext, true, 100));
318         sdc->drawTexture(nullptr,
319                          topLeftSDC->readSurfaceView(),
320                          sdc->colorInfo().alphaType(),
321                          GrSamplerState::Filter::kNearest,
322                          GrSamplerState::MipmapMode::kNone,
323                          SkBlendMode::kSrcOver,
324                          SK_PMColor4fWHITE,
325                          {0, 0, 100, 200},
326                          {200, 0, 300, 200},
327                          GrQuadAAFlags::kNone,
328                          SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
329                          SkMatrix::I(),
330                          nullptr);
331     }
332 
333     return DrawResult::kOk;
334 }
335 
336 ////////////////////////////////////////////////////////////////////////////////////////////////////
337 
338 DEF_GM( return new ClockwiseGM(); )
339 
340 }  // namespace skiagm
341