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