Flutter Engine
The Flutter Engine
clockwise.cpp
Go to the documentation of this file.
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"
14#include "include/core/SkRect.h"
16#include "include/core/SkSize.h"
20#include "include/gpu/GrTypes.h"
24#include "src/gpu/KeyBuilder.h"
52
53#include <memory>
54#include <utility>
55
56class GrAppliedClip;
58
59namespace {
60
61static constexpr GrGeometryProcessor::Attribute gVertex =
63
64////////////////////////////////////////////////////////////////////////////////////////////////////
65// SkSL code.
66
67class ClockwiseTestProcessor : public GrGeometryProcessor {
68public:
69 static GrGeometryProcessor* Make(SkArenaAlloc* arena, bool readSkFragCoord) {
70 return arena->make([&](void* ptr) {
71 return new (ptr) ClockwiseTestProcessor(readSkFragCoord);
72 });
73 }
74
75 const char* name() const final { return "ClockwiseTestProcessor"; }
76
77 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
83 bool readSkFragCoord() const { return fReadSkFragCoord; }
84
85private:
86 ClockwiseTestProcessor(bool readSkFragCoord)
87 : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
88 , fReadSkFragCoord(readSkFragCoord) {
89 this->setVertexAttributesWithImplicitOffsets(&gVertex, 1);
90 }
91
92 const bool fReadSkFragCoord;
93
95};
96
97std::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
129class ClockwiseTestOp : public GrDrawOp {
130public:
132
133 static GrOp::Owner Make(GrRecordingContext* context,
134 bool readSkFragCoord, int y = 0) {
135 return GrOp::Make<ClockwiseTestOp>(context, readSkFragCoord, y);
136 }
137
138private:
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
146 const char* name() const override { return "ClockwiseTestOp"; }
147 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
148 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
150 }
151
152 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,
166 renderPassXferBarriers, colorLoadOp);
167 }
168
169 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
180 void onPrePrepare(GrRecordingContext* context,
181 const GrSurfaceProxyView& writeView,
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
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),
212 }
213
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
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
249namespace 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 */
256class ClockwiseGM : public GpuGM {
257 SkString getName() const override { return SkString("clockwise"); }
258 SkISize getISize() override { return {300, 200}; }
259 DrawResult onDraw(GrRecordingContext*, SkCanvas*, SkString* errorMsg) override;
260};
261
262DrawResult ClockwiseGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
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,
281 {100, 200},
283 /*label=*/{},
284 /* sampleCnt= */ 1,
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(),
299 {0, 0, 100, 200},
300 {100, 0, 200, 200},
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,
312 {100, 200},
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(),
325 {0, 0, 100, 200},
326 {200, 0, 300, 200},
328 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
329 SkMatrix::I(),
330 nullptr);
331 }
332
333 return DrawResult::kOk;
334}
335
336////////////////////////////////////////////////////////////////////////////////////////////////////
337
338DEF_GM( return new ClockwiseGM(); )
339
340} // namespace skiagm
#define DEFINE_OP_CLASS_ID
Definition: GrOp.h:64
GrClampType
Definition: GrTypesPriv.h:228
GrColorType
Definition: GrTypesPriv.h:540
@ kStatic_GrAccessPattern
Definition: GrTypesPriv.h:428
GrLoadOp
Definition: GrTypesPriv.h:155
@ kFloat2_GrVertexAttribType
Definition: GrTypesPriv.h:314
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
GrXferBarrierFlags
@ kPlus
r = min(s + d, 1)
@ kSrcOver
r = s + (1-sa)*d
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
Definition: SkColorData.h:378
constexpr SkPMColor4f SK_PMColor4fBLACK
Definition: SkColorData.h:379
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< const GrBuffer > fVertexBuffer
Definition: GrCaps.h:57
GrLoadOp colorLoadOp() const final
const GrDstProxyView & dstProxyView() const final
GrXferBarrierFlags renderPassBarriers() const final
SkArenaAlloc * allocator() override
void bindBuffers(sk_sp< const GrBuffer > indexBuffer, sk_sp< const GrBuffer > instanceBuffer, sk_sp< const GrBuffer > vertexBuffer, GrPrimitiveRestart primitiveRestart=GrPrimitiveRestart::kNo)
const GrSurfaceProxyView & writeView() const final
GrResourceProvider * resourceProvider() const final
GrAppliedClip detachAppliedClip() final
const GrCaps & caps() const final
void bindPipeline(const GrProgramInfo &programInfo, const SkRect &drawBounds)
void draw(int vertexCount, int baseVertex)
bool usesMSAASurface() const final
std::unique_ptr< GrOp > Owner
Definition: GrOp.h:72
static constexpr Analysis EmptySetAnalysis()
sk_sp< GrGpuBuffer > createBuffer(size_t size, GrGpuBufferType, GrAccessPattern, ZeroInit)
GrRenderTargetProxy * asRenderTargetProxy() const
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
static bool b
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
double y
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
@ kNone
Definition: layer.h:53
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
SurfaceDrawContext * TopDeviceSurfaceDrawContext(const SkCanvas *canvas)
Definition: GrCanvas.cpp:20
DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {})) DEF_GM(return F(C(clipbox)
DrawResult
Definition: gm.h:104
Definition: SkSize.h:16
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659