| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 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.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 |  | 
 | 23 | namespace skiagm { | 
 | 24 |  | 
| Brian Osman | d4c2970 | 2018-09-14 16:16:55 -0400 | [diff] [blame] | 25 | static constexpr GrGeometryProcessor::Attribute gVertex = | 
 | 26 |         {"vertex", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 27 |  | 
 | 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 |  */ | 
| Chris Dalton | 3a77837 | 2019-02-07 15:23:36 -0700 | [diff] [blame] | 33 | class ClockwiseGM : public GpuGM { | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 34 | private: | 
 | 35 |     SkString onShortName() final { return SkString("clockwise"); } | 
 | 36 |     SkISize onISize() override { return SkISize::Make(300, 200); } | 
| Chris Dalton | 3a77837 | 2019-02-07 15:23:36 -0700 | [diff] [blame] | 37 |     void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) override; | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 38 | }; | 
 | 39 |  | 
 | 40 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 
 | 41 | // SkSL code. | 
 | 42 |  | 
 | 43 | class ClockwiseTestProcessor : public GrGeometryProcessor { | 
 | 44 | public: | 
 | 45 |     ClockwiseTestProcessor(bool readSkFragCoord) | 
 | 46 |             : GrGeometryProcessor(kClockwiseTestProcessor_ClassID) | 
 | 47 |             , fReadSkFragCoord(readSkFragCoord) { | 
| Brian Osman | f04fb3c | 2018-11-12 15:34:00 -0500 | [diff] [blame] | 48 |         this->setVertexAttributes(&gVertex, 1); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 49 |     } | 
 | 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 |  | 
 | 56 | private: | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 57 |     const bool fReadSkFragCoord; | 
 | 58 |  | 
 | 59 |     friend class GLSLClockwiseTestProcessor; | 
 | 60 | }; | 
 | 61 |  | 
 | 62 | class 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. | 
| Ethan Nicholas | e1f5502 | 2019-02-05 17:17:40 -0500 | [diff] [blame] | 76 |             args.fFragBuilder->codeAppendf("%s = half4(min(half(sk_FragCoord.y), 1));", | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 77 |                                            args.fOutputCoverage); | 
 | 78 |         } | 
 | 79 |     } | 
 | 80 | }; | 
 | 81 |  | 
 | 82 | GrGLSLPrimitiveProcessor* ClockwiseTestProcessor::createGLSLInstance( | 
 | 83 |         const GrShaderCaps&) const { | 
 | 84 |     return new GLSLClockwiseTestProcessor; | 
 | 85 | } | 
 | 86 |  | 
 | 87 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 
 | 88 | // Draw Op. | 
 | 89 |  | 
 | 90 | class ClockwiseTestOp : public GrDrawOp { | 
 | 91 | public: | 
 | 92 |     DEFINE_OP_CLASS_ID | 
 | 93 |  | 
 | 94 |     static std::unique_ptr<GrDrawOp> Make(GrContext* context, bool readSkFragCoord, int y = 0) { | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 95 |         GrOpMemoryPool* pool = context->priv().opMemoryPool(); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 96 |         return pool->allocate<ClockwiseTestOp>(readSkFragCoord, y); | 
 | 97 |     } | 
 | 98 |  | 
 | 99 | private: | 
 | 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; } | 
| Chris Dalton | 4b62aed | 2019-01-15 11:53:00 -0700 | [diff] [blame] | 107 |     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*) override { | 
 | 108 |         return GrProcessorSet::EmptySetAnalysis(); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 109 |     } | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 110 |     void onPrepare(GrOpFlushState*) override {} | 
| Brian Salomon | 588cec7 | 2018-11-14 13:56:37 -0500 | [diff] [blame] | 111 |     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 112 |         SkPoint vertices[4] = { | 
 | 113 |             {100, fY}, | 
 | 114 |             {0, fY+100}, | 
 | 115 |             {0, fY}, | 
 | 116 |             {100, fY+100}, | 
 | 117 |         }; | 
| Brian Salomon | 12d2264 | 2019-01-29 14:38:50 -0500 | [diff] [blame] | 118 |         sk_sp<const GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer( | 
| Brian Salomon | dbf7072 | 2019-02-07 11:31:24 -0500 | [diff] [blame] | 119 |                 sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices)); | 
| Chris Dalton | 79f99f7 | 2018-07-27 14:15:10 -0600 | [diff] [blame] | 120 |         if (!vertexBuffer) { | 
 | 121 |             return; | 
 | 122 |         } | 
| Robert Phillips | d0fe875 | 2019-01-31 14:13:59 -0500 | [diff] [blame] | 123 |         GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 124 |         GrMesh mesh(GrPrimitiveType::kTriangleStrip); | 
 | 125 |         mesh.setNonIndexedNonInstanced(4); | 
| Brian Salomon | 12d2264 | 2019-01-29 14:38:50 -0500 | [diff] [blame] | 126 |         mesh.setVertexData(std::move(vertexBuffer)); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 127 |         flushState->rtCommandBuffer()->draw(ClockwiseTestProcessor(fReadSkFragCoord), pipeline, | 
 | 128 |                                             nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100)); | 
 | 129 |     } | 
 | 130 |  | 
 | 131 |     const bool fReadSkFragCoord; | 
 | 132 |     const float fY; | 
 | 133 |  | 
 | 134 |     friend class ::GrOpMemoryPool; // for ctor | 
 | 135 | }; | 
 | 136 |  | 
 | 137 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 
 | 138 | // Test. | 
 | 139 |  | 
| Chris Dalton | 3a77837 | 2019-02-07 15:23:36 -0700 | [diff] [blame] | 140 | void ClockwiseGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas) { | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 141 |     rtc->clear(nullptr, { 0, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 142 |  | 
 | 143 |     // Draw the test directly to the frame buffer. | 
 | 144 |     rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0)); | 
 | 145 |     rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100)); | 
 | 146 |  | 
 | 147 |     // Draw the test to an off-screen, top-down render target. | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 148 |     if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext( | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 149 |             rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200, | 
 | 150 |             rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo, | 
 | 151 |             kTopLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) { | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 152 |         topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT, | 
 | 153 |                           GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 154 |         topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0)); | 
 | 155 |         topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100)); | 
 | 156 |         rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()), | 
| Brian Osman | 3d139a4 | 2018-11-19 10:42:10 -0500 | [diff] [blame] | 157 |                          GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200}, | 
| Brian Salomon | 2213ee9 | 2018-10-02 10:44:21 -0400 | [diff] [blame] | 158 |                          {100, 0, 200, 200}, GrQuadAAFlags::kNone, | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 159 |                          SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(), | 
| Brian Osman | 3d139a4 | 2018-11-19 10:42:10 -0500 | [diff] [blame] | 160 |                          nullptr); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 161 |     } | 
 | 162 |  | 
 | 163 |     // Draw the test to an off-screen, bottom-up render target. | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 164 |     if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext( | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 165 |             rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200, | 
 | 166 |             rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo, | 
 | 167 |             kBottomLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) { | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 168 |         topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT, | 
 | 169 |                           GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 170 |         topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0)); | 
 | 171 |         topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100)); | 
 | 172 |         rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()), | 
| Brian Osman | 3d139a4 | 2018-11-19 10:42:10 -0500 | [diff] [blame] | 173 |                          GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200}, | 
| Brian Salomon | 2213ee9 | 2018-10-02 10:44:21 -0400 | [diff] [blame] | 174 |                          {200, 0, 300, 200}, GrQuadAAFlags::kNone, | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 175 |                          SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(), | 
| Brian Osman | 3d139a4 | 2018-11-19 10:42:10 -0500 | [diff] [blame] | 176 |                          nullptr); | 
| Chris Dalton | 49d14e9 | 2018-07-27 12:38:35 -0600 | [diff] [blame] | 177 |     } | 
 | 178 | } | 
 | 179 |  | 
 | 180 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 
 | 181 |  | 
 | 182 | DEF_GM( return new ClockwiseGM(); ) | 
 | 183 |  | 
 | 184 | } |