blob: 7769c7e9e8bd14890706353f0d8c919f16a9f60a [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
Brian Osmand4c29702018-09-14 16:16:55 -040025static constexpr GrGeometryProcessor::Attribute gVertex =
26 {"vertex", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
Chris Dalton49d14e92018-07-27 12:38:35 -060027
28/**
29 * This is a GPU-backend specific test. It ensures that SkSL properly identifies clockwise-winding
30 * triangles (sk_Clockwise), in terms of to Skia device space, in all backends and with all render
31 * target origins. We draw clockwise triangles green and counter-clockwise red.
32 */
33class ClockwiseGM : public GM {
34private:
35 SkString onShortName() final { return SkString("clockwise"); }
36 SkISize onISize() override { return SkISize::Make(300, 200); }
37 void onDraw(SkCanvas*) override;
38};
39
40////////////////////////////////////////////////////////////////////////////////////////////////////
41// SkSL code.
42
43class ClockwiseTestProcessor : public GrGeometryProcessor {
44public:
45 ClockwiseTestProcessor(bool readSkFragCoord)
46 : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
47 , fReadSkFragCoord(readSkFragCoord) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -050048 this->setVertexAttributes(&gVertex, 1);
Chris Dalton49d14e92018-07-27 12:38:35 -060049 }
50 const char* name() const override { return "ClockwiseTestProcessor"; }
51 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
52 b->add32(fReadSkFragCoord);
53 }
54 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
55
56private:
Chris Dalton49d14e92018-07-27 12:38:35 -060057 const bool fReadSkFragCoord;
58
59 friend class GLSLClockwiseTestProcessor;
60};
61
62class GLSLClockwiseTestProcessor : public GrGLSLGeometryProcessor {
63 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
64 FPCoordTransformIter&& transformIter) override {}
65
66 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
67 const ClockwiseTestProcessor& proc = args.fGP.cast<ClockwiseTestProcessor>();
68 args.fVaryingHandler->emitAttributes(proc);
69 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
70 args.fFragBuilder->codeAppendf(
71 "%s = sk_Clockwise ? half4(0,1,0,1) : half4(1,0,0,1);", args.fOutputColor);
72 if (!proc.fReadSkFragCoord) {
73 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
74 } else {
75 // Verify layout(origin_upper_left) on gl_FragCoord does not affect gl_FrontFacing.
76 args.fFragBuilder->codeAppendf("%s = half4(min(sk_FragCoord.y, 1));",
77 args.fOutputCoverage);
78 }
79 }
80};
81
82GrGLSLPrimitiveProcessor* ClockwiseTestProcessor::createGLSLInstance(
83 const GrShaderCaps&) const {
84 return new GLSLClockwiseTestProcessor;
85}
86
87////////////////////////////////////////////////////////////////////////////////////////////////////
88// Draw Op.
89
90class ClockwiseTestOp : public GrDrawOp {
91public:
92 DEFINE_OP_CLASS_ID
93
94 static std::unique_ptr<GrDrawOp> Make(GrContext* context, bool readSkFragCoord, int y = 0) {
95 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
96 return pool->allocate<ClockwiseTestOp>(readSkFragCoord, y);
97 }
98
99private:
100 ClockwiseTestOp(bool readSkFragCoord, float y)
101 : GrDrawOp(ClassID()), fReadSkFragCoord(readSkFragCoord), fY(y) {
102 this->setBounds(SkRect::MakeIWH(300, 100), HasAABloat::kNo, IsZeroArea::kNo);
103 }
104
105 const char* name() const override { return "ClockwiseTestOp"; }
106 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
107 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
108 return RequiresDstTexture::kNo;
109 }
Chris Dalton49d14e92018-07-27 12:38:35 -0600110 void onPrepare(GrOpFlushState*) override {}
Brian Salomon588cec72018-11-14 13:56:37 -0500111 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Chris Dalton49d14e92018-07-27 12:38:35 -0600112 SkPoint vertices[4] = {
113 {100, fY},
114 {0, fY+100},
115 {0, fY},
116 {100, fY+100},
117 };
118 sk_sp<GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer(
119 sizeof(vertices), kVertex_GrBufferType, kStatic_GrAccessPattern,
Chris Daltond004e0b2018-09-27 09:28:03 -0600120 GrResourceProvider::Flags::kNone, vertices));
Chris Dalton79f99f72018-07-27 14:15:10 -0600121 if (!vertexBuffer) {
122 return;
123 }
Chris Dalton916c4982018-08-15 00:53:25 -0600124 GrPipeline pipeline(flushState->drawOpArgs().fProxy, GrScissorTest::kDisabled,
Chris Dalton49d14e92018-07-27 12:38:35 -0600125 SkBlendMode::kPlus);
126 GrMesh mesh(GrPrimitiveType::kTriangleStrip);
127 mesh.setNonIndexedNonInstanced(4);
128 mesh.setVertexData(vertexBuffer.get());
129 flushState->rtCommandBuffer()->draw(ClockwiseTestProcessor(fReadSkFragCoord), pipeline,
130 nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100));
131 }
132
133 const bool fReadSkFragCoord;
134 const float fY;
135
136 friend class ::GrOpMemoryPool; // for ctor
137};
138
139////////////////////////////////////////////////////////////////////////////////////////////////////
140// Test.
141
142void ClockwiseGM::onDraw(SkCanvas* canvas) {
143 GrContext* ctx = canvas->getGrContext();
144 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
145 if (!ctx || !rtc) {
146 DrawGpuOnlyMessage(canvas);
147 return;
148 }
149
Brian Osman9a9baae2018-11-05 15:06:26 -0500150 rtc->clear(nullptr, { 0, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600151
152 // Draw the test directly to the frame buffer.
153 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
154 rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
155
156 // Draw the test to an off-screen, top-down render target.
157 if (auto topLeftRTC = ctx->contextPriv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500158 rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
159 rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
160 kTopLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
Brian Osman9a9baae2018-11-05 15:06:26 -0500161 topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
162 GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600163 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
164 topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
165 rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
Brian Osman3d139a42018-11-19 10:42:10 -0500166 GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200},
Brian Salomon2213ee92018-10-02 10:44:21 -0400167 {100, 0, 200, 200}, GrQuadAAFlags::kNone,
Chris Dalton49d14e92018-07-27 12:38:35 -0600168 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3d139a42018-11-19 10:42:10 -0500169 nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600170 }
171
172 // Draw the test to an off-screen, bottom-up render target.
173 if (auto topLeftRTC = ctx->contextPriv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500174 rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
175 rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
176 kBottomLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
Brian Osman9a9baae2018-11-05 15:06:26 -0500177 topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
178 GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton49d14e92018-07-27 12:38:35 -0600179 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()),
Brian Osman3d139a42018-11-19 10:42:10 -0500182 GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200},
Brian Salomon2213ee92018-10-02 10:44:21 -0400183 {200, 0, 300, 200}, GrQuadAAFlags::kNone,
Chris Dalton49d14e92018-07-27 12:38:35 -0600184 SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
Brian Osman3d139a42018-11-19 10:42:10 -0500185 nullptr);
Chris Dalton49d14e92018-07-27 12:38:35 -0600186 }
187}
188
189////////////////////////////////////////////////////////////////////////////////////////////////////
190
191DEF_GM( return new ClockwiseGM(); )
192
193}