blob: 6adc688c373825642ccb50aa90ec8b413bfa50e0 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/gpu/GrContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040020#include "include/gpu/GrSamplerState.h"
21#include "include/gpu/GrTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "include/private/GrRecordingContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040023#include "include/private/GrSurfaceProxy.h"
24#include "include/private/GrTextureProxy.h"
25#include "include/private/GrTypesPriv.h"
26#include "include/private/SkColorData.h"
27#include "src/gpu/GrBuffer.h"
28#include "src/gpu/GrCaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/gpu/GrClip.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040030#include "src/gpu/GrColorSpaceXform.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "src/gpu/GrContextPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040032#include "src/gpu/GrGeometryProcessor.h"
33#include "src/gpu/GrGpuBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050034#include "src/gpu/GrGpuCommandBuffer.h"
35#include "src/gpu/GrMemoryPool.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040036#include "src/gpu/GrMesh.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/gpu/GrOpFlushState.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040038#include "src/gpu/GrPipeline.h"
39#include "src/gpu/GrPrimitiveProcessor.h"
40#include "src/gpu/GrProcessor.h"
41#include "src/gpu/GrProcessorSet.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050042#include "src/gpu/GrRecordingContextPriv.h"
43#include "src/gpu/GrRenderTargetContext.h"
44#include "src/gpu/GrRenderTargetContextPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040045#include "src/gpu/GrResourceProvider.h"
46#include "src/gpu/GrShaderCaps.h"
47#include "src/gpu/GrShaderVar.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050048#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
49#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040050#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050051#include "src/gpu/glsl/GrGLSLVarying.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040052#include "src/gpu/ops/GrDrawOp.h"
53#include "src/gpu/ops/GrOp.h"
54
55#include <memory>
56#include <utility>
57
58class GrAppliedClip;
59class GrGLSLProgramDataManager;
Chris Dalton49d14e92018-07-27 12:38:35 -060060
61namespace skiagm {
62
Brian Osmand4c29702018-09-14 16:16:55 -040063static constexpr GrGeometryProcessor::Attribute gVertex =
64 {"vertex", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
Chris Dalton49d14e92018-07-27 12:38:35 -060065
66/**
67 * This is a GPU-backend specific test. It ensures that SkSL properly identifies clockwise-winding
68 * triangles (sk_Clockwise), in terms of to Skia device space, in all backends and with all render
69 * target origins. We draw clockwise triangles green and counter-clockwise red.
70 */
Chris Dalton3a778372019-02-07 15:23:36 -070071class ClockwiseGM : public GpuGM {
Chris Dalton49d14e92018-07-27 12:38:35 -060072private:
73 SkString onShortName() final { return SkString("clockwise"); }
74 SkISize onISize() override { return SkISize::Make(300, 200); }
Chris Dalton3a778372019-02-07 15:23:36 -070075 void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) override;
Chris Dalton49d14e92018-07-27 12:38:35 -060076};
77
78////////////////////////////////////////////////////////////////////////////////////////////////////
79// SkSL code.
80
81class ClockwiseTestProcessor : public GrGeometryProcessor {
82public:
83 ClockwiseTestProcessor(bool readSkFragCoord)
84 : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
85 , fReadSkFragCoord(readSkFragCoord) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -050086 this->setVertexAttributes(&gVertex, 1);
Chris Dalton49d14e92018-07-27 12:38:35 -060087 }
88 const char* name() const override { return "ClockwiseTestProcessor"; }
89 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
90 b->add32(fReadSkFragCoord);
91 }
92 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
93
94private:
Chris Dalton49d14e92018-07-27 12:38:35 -060095 const bool fReadSkFragCoord;
96
97 friend class GLSLClockwiseTestProcessor;
98};
99
100class GLSLClockwiseTestProcessor : public GrGLSLGeometryProcessor {
101 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
102 FPCoordTransformIter&& transformIter) override {}
103
104 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
105 const ClockwiseTestProcessor& proc = args.fGP.cast<ClockwiseTestProcessor>();
106 args.fVaryingHandler->emitAttributes(proc);
107 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
108 args.fFragBuilder->codeAppendf(
109 "%s = sk_Clockwise ? half4(0,1,0,1) : half4(1,0,0,1);", args.fOutputColor);
110 if (!proc.fReadSkFragCoord) {
111 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
112 } else {
113 // Verify layout(origin_upper_left) on gl_FragCoord does not affect gl_FrontFacing.
Ethan Nicholase1f55022019-02-05 17:17:40 -0500114 args.fFragBuilder->codeAppendf("%s = half4(min(half(sk_FragCoord.y), 1));",
Chris Dalton49d14e92018-07-27 12:38:35 -0600115 args.fOutputCoverage);
116 }
117 }
118};
119
120GrGLSLPrimitiveProcessor* ClockwiseTestProcessor::createGLSLInstance(
121 const GrShaderCaps&) const {
122 return new GLSLClockwiseTestProcessor;
123}
124
125////////////////////////////////////////////////////////////////////////////////////////////////////
126// Draw Op.
127
128class ClockwiseTestOp : public GrDrawOp {
129public:
130 DEFINE_OP_CLASS_ID
131
Robert Phillipsbe9aff22019-02-15 11:33:22 -0500132 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
133 bool readSkFragCoord, int y = 0) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500134 GrOpMemoryPool* pool = context->priv().opMemoryPool();
Chris Dalton49d14e92018-07-27 12:38:35 -0600135 return pool->allocate<ClockwiseTestOp>(readSkFragCoord, y);
136 }
137
138private:
139 ClockwiseTestOp(bool readSkFragCoord, float y)
140 : GrDrawOp(ClassID()), fReadSkFragCoord(readSkFragCoord), fY(y) {
141 this->setBounds(SkRect::MakeIWH(300, 100), HasAABloat::kNo, IsZeroArea::kNo);
142 }
143
144 const char* name() const override { return "ClockwiseTestOp"; }
145 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
Brian Osman5ced0bf2019-03-15 10:15:29 -0400146 GrProcessorSet::Analysis finalize(
147 const GrCaps&, const GrAppliedClip*, GrFSAAType, GrClampType) override {
Chris Dalton4b62aed2019-01-15 11:53:00 -0700148 return GrProcessorSet::EmptySetAnalysis();
Chris Dalton49d14e92018-07-27 12:38:35 -0600149 }
Chris Dalton49d14e92018-07-27 12:38:35 -0600150 void onPrepare(GrOpFlushState*) override {}
Brian Salomon588cec72018-11-14 13:56:37 -0500151 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Chris Dalton49d14e92018-07-27 12:38:35 -0600152 SkPoint vertices[4] = {
153 {100, fY},
154 {0, fY+100},
155 {0, fY},
156 {100, fY+100},
157 };
Brian Salomon12d22642019-01-29 14:38:50 -0500158 sk_sp<const GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer(
Brian Salomondbf70722019-02-07 11:31:24 -0500159 sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices));
Chris Dalton79f99f72018-07-27 14:15:10 -0600160 if (!vertexBuffer) {
161 return;
162 }
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500163 GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus);
Chris Dalton49d14e92018-07-27 12:38:35 -0600164 GrMesh mesh(GrPrimitiveType::kTriangleStrip);
165 mesh.setNonIndexedNonInstanced(4);
Brian Salomon12d22642019-01-29 14:38:50 -0500166 mesh.setVertexData(std::move(vertexBuffer));
Chris Dalton49d14e92018-07-27 12:38:35 -0600167 flushState->rtCommandBuffer()->draw(ClockwiseTestProcessor(fReadSkFragCoord), pipeline,
168 nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100));
169 }
170
171 const bool fReadSkFragCoord;
172 const float fY;
173
174 friend class ::GrOpMemoryPool; // for ctor
175};
176
177////////////////////////////////////////////////////////////////////////////////////////////////////
178// Test.
179
Chris Dalton3a778372019-02-07 15:23:36 -0700180void ClockwiseGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas) {
Brian Osman9a9baae2018-11-05 15:06:26 -0500181 rtc->clear(nullptr, { 0, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600182
183 // Draw the test directly to the frame buffer.
184 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
185 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
186
187 // Draw the test to an off-screen, top-down render target.
Robert Phillips9da87e02019-02-04 13:26:26 -0500188 if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500189 rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
190 rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
191 kTopLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
Brian Osman9a9baae2018-11-05 15:06:26 -0500192 topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
193 GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600194 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
195 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
196 rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500197 GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
198 SK_PMColor4fWHITE, {0, 0, 100, 200},
Michael Ludwig136f45a2019-02-19 11:44:41 -0500199 {100, 0, 200, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
Chris Dalton49d14e92018-07-27 12:38:35 -0600200 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3d139a42018-11-19 10:42:10 -0500201 nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600202 }
203
204 // Draw the test to an off-screen, bottom-up render target.
Robert Phillips9da87e02019-02-04 13:26:26 -0500205 if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500206 rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
207 rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
208 kBottomLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
Brian Osman9a9baae2018-11-05 15:06:26 -0500209 topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
210 GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600211 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
212 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
213 rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500214 GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
215 SK_PMColor4fWHITE, {0, 0, 100, 200},
Michael Ludwig136f45a2019-02-19 11:44:41 -0500216 {200, 0, 300, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
Chris Dalton49d14e92018-07-27 12:38:35 -0600217 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3d139a42018-11-19 10:42:10 -0500218 nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600219 }
220}
221
222////////////////////////////////////////////////////////////////////////////////////////////////////
223
224DEF_GM( return new ClockwiseGM(); )
225
226}