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