blob: 7b2dbccede4b0efb66ba683be7ac3fb0d1d48255 [file] [log] [blame]
Chris Dalton49d14e92018-07-27 12:38:35 -06001/*
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.h"
9
10#include "GrClip.h"
11#include "GrContext.h"
12#include "GrGpuCommandBuffer.h"
13#include "GrMemoryPool.h"
14#include "GrOpFlushState.h"
15#include "GrRenderTargetContext.h"
16#include "GrRenderTargetContextPriv.h"
17#include "GrRenderTarget.h"
18#include "glsl/GrGLSLFragmentShaderBuilder.h"
19#include "glsl/GrGLSLGeometryProcessor.h"
20#include "glsl/GrGLSLVarying.h"
21#include "glsl/GrGLSLVertexGeoBuilder.h"
22
23namespace skiagm {
24
25static constexpr GrGeometryProcessor::Attribute gVertex{"vertex", kFloat2_GrVertexAttribType};
26
27/**
28 * This is a GPU-backend specific test. It ensures that SkSL properly identifies clockwise-winding
29 * triangles (sk_Clockwise), in terms of to Skia device space, in all backends and with all render
30 * target origins. We draw clockwise triangles green and counter-clockwise red.
31 */
32class ClockwiseGM : public GM {
33private:
34 SkString onShortName() final { return SkString("clockwise"); }
35 SkISize onISize() override { return SkISize::Make(300, 200); }
36 void onDraw(SkCanvas*) override;
37};
38
39////////////////////////////////////////////////////////////////////////////////////////////////////
40// SkSL code.
41
42class ClockwiseTestProcessor : public GrGeometryProcessor {
43public:
44 ClockwiseTestProcessor(bool readSkFragCoord)
45 : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
46 , fReadSkFragCoord(readSkFragCoord) {
47 this->setVertexAttributeCnt(1);
48 }
49 const char* name() const override { return "ClockwiseTestProcessor"; }
50 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
51 b->add32(fReadSkFragCoord);
52 }
53 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
54
55private:
56 const Attribute& onVertexAttribute(int i) const override { return gVertex; }
57
58 const bool fReadSkFragCoord;
59
60 friend class GLSLClockwiseTestProcessor;
61};
62
63class GLSLClockwiseTestProcessor : public GrGLSLGeometryProcessor {
64 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
65 FPCoordTransformIter&& transformIter) override {}
66
67 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
68 const ClockwiseTestProcessor& proc = args.fGP.cast<ClockwiseTestProcessor>();
69 args.fVaryingHandler->emitAttributes(proc);
70 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
71 args.fFragBuilder->codeAppendf(
72 "%s = sk_Clockwise ? half4(0,1,0,1) : half4(1,0,0,1);", args.fOutputColor);
73 if (!proc.fReadSkFragCoord) {
74 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
75 } else {
76 // Verify layout(origin_upper_left) on gl_FragCoord does not affect gl_FrontFacing.
77 args.fFragBuilder->codeAppendf("%s = half4(min(sk_FragCoord.y, 1));",
78 args.fOutputCoverage);
79 }
80 }
81};
82
83GrGLSLPrimitiveProcessor* ClockwiseTestProcessor::createGLSLInstance(
84 const GrShaderCaps&) const {
85 return new GLSLClockwiseTestProcessor;
86}
87
88////////////////////////////////////////////////////////////////////////////////////////////////////
89// Draw Op.
90
91class ClockwiseTestOp : public GrDrawOp {
92public:
93 DEFINE_OP_CLASS_ID
94
95 static std::unique_ptr<GrDrawOp> Make(GrContext* context, bool readSkFragCoord, int y = 0) {
96 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
97 return pool->allocate<ClockwiseTestOp>(readSkFragCoord, y);
98 }
99
100private:
101 ClockwiseTestOp(bool readSkFragCoord, float y)
102 : GrDrawOp(ClassID()), fReadSkFragCoord(readSkFragCoord), fY(y) {
103 this->setBounds(SkRect::MakeIWH(300, 100), HasAABloat::kNo, IsZeroArea::kNo);
104 }
105
106 const char* name() const override { return "ClockwiseTestOp"; }
107 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
108 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
109 return RequiresDstTexture::kNo;
110 }
Chris Dalton49d14e92018-07-27 12:38:35 -0600111 void onPrepare(GrOpFlushState*) override {}
112 void onExecute(GrOpFlushState* flushState) override {
113 SkPoint vertices[4] = {
114 {100, fY},
115 {0, fY+100},
116 {0, fY},
117 {100, fY+100},
118 };
119 sk_sp<GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer(
120 sizeof(vertices), kVertex_GrBufferType, kStatic_GrAccessPattern,
121 GrResourceProvider::kNone_Flag, vertices));
Chris Dalton79f99f72018-07-27 14:15:10 -0600122 if (!vertexBuffer) {
123 return;
124 }
Chris Dalton916c4982018-08-15 00:53:25 -0600125 GrPipeline pipeline(flushState->drawOpArgs().fProxy, GrScissorTest::kDisabled,
Chris Dalton49d14e92018-07-27 12:38:35 -0600126 SkBlendMode::kPlus);
127 GrMesh mesh(GrPrimitiveType::kTriangleStrip);
128 mesh.setNonIndexedNonInstanced(4);
129 mesh.setVertexData(vertexBuffer.get());
130 flushState->rtCommandBuffer()->draw(ClockwiseTestProcessor(fReadSkFragCoord), pipeline,
131 nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100));
132 }
133
134 const bool fReadSkFragCoord;
135 const float fY;
136
137 friend class ::GrOpMemoryPool; // for ctor
138};
139
140////////////////////////////////////////////////////////////////////////////////////////////////////
141// Test.
142
143void ClockwiseGM::onDraw(SkCanvas* canvas) {
144 GrContext* ctx = canvas->getGrContext();
145 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
146 if (!ctx || !rtc) {
147 DrawGpuOnlyMessage(canvas);
148 return;
149 }
150
151 rtc->clear(nullptr, GrColorPackRGBA(0,0,0,255),
152 GrRenderTargetContext::CanClearFullscreen::kYes);
153
154 // Draw the test directly to the frame buffer.
155 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
156 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
157
158 // Draw the test to an off-screen, top-down render target.
159 if (auto topLeftRTC = ctx->contextPriv().makeDeferredRenderTargetContext(
Chris Dalton79f99f72018-07-27 14:15:10 -0600160 SkBackingFit::kExact, 100, 200, rtc->asSurfaceProxy()->config(),
Chris Dalton49d14e92018-07-27 12:38:35 -0600161 nullptr, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, nullptr,
162 SkBudgeted::kYes)) {
163 topLeftRTC->clear(nullptr, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
164 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
165 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
166 rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
167 GrSamplerState::Filter::kNearest, 0xffffffff, {0,0,100,200},
168 {100,0,200,200}, GrAA::kNo,
169 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3ebd3542018-07-30 14:36:53 -0400170 nullptr, nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600171 }
172
173 // Draw the test to an off-screen, bottom-up render target.
174 if (auto topLeftRTC = ctx->contextPriv().makeDeferredRenderTargetContext(
Chris Dalton79f99f72018-07-27 14:15:10 -0600175 SkBackingFit::kExact, 100, 200, rtc->asSurfaceProxy()->config(),
Chris Dalton49d14e92018-07-27 12:38:35 -0600176 nullptr, 1, GrMipMapped::kNo, kBottomLeft_GrSurfaceOrigin, nullptr,
177 SkBudgeted::kYes)) {
178 topLeftRTC->clear(nullptr, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
179 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
180 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
181 rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
182 GrSamplerState::Filter::kNearest, 0xffffffff, {0,0,100,200},
183 {200,0,300,200}, GrAA::kNo,
184 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3ebd3542018-07-30 14:36:53 -0400185 nullptr, nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600186 }
187}
188
189////////////////////////////////////////////////////////////////////////////////////////////////////
190
191DEF_GM( return new ClockwiseGM(); )
192
193}