1 /*
2  * Copyright 2019 Google LLC.
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 "src/gpu/ccpr/GrSampleMaskProcessor.h"
9 
10 #include "src/gpu/GrMesh.h"
11 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
12 
13 class GrSampleMaskProcessor::Impl : public GrGLSLGeometryProcessor {
14 public:
Impl(std::unique_ptr<Shader> shader)15     Impl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
16 
17 private:
setData(const GrGLSLProgramDataManager &,const GrPrimitiveProcessor &,FPCoordTransformIter &&)18     void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
19                  FPCoordTransformIter&&) override {}
20 
21     void onEmitCode(EmitArgs&, GrGPArgs*) override;
22 
23     const std::unique_ptr<Shader> fShader;
24 };
25 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)26 void GrSampleMaskProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
27     const GrSampleMaskProcessor& proc = args.fGP.cast<GrSampleMaskProcessor>();
28     GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
29     GrGLSLVertexBuilder* v = args.fVertBuilder;
30     int numInputPoints = proc.numInputPoints();
31     int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
32 
33     varyingHandler->emitAttributes(proc);
34     SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
35 
36     if (PrimitiveType::kTriangles == proc.fPrimitiveType) {
37         SkASSERT(!proc.hasInstanceAttributes());  // Triangles are drawn with vertex arrays.
38         gpArgs->fPositionVar = proc.fInputAttribs.front().asShaderVar();
39     } else {
40         SkASSERT(!proc.hasVertexAttributes());  // Curves are drawn with instanced rendering.
41 
42         // Shaders expect a global "bloat" variable when calculating gradients.
43         v->defineConstant("half", "bloat", ".5");
44 
45         const char* swizzle = (4 == numInputPoints || proc.hasInputWeight()) ? "xyzw" : "xyz";
46         v->codeAppendf("float%ix2 pts = transpose(float2x%i(X.%s, Y.%s));",
47                        inputWidth, inputWidth, swizzle, swizzle);
48 
49         const char* hullPts = "pts";
50         fShader->emitSetupCode(v, "pts", &hullPts);
51         v->codeAppendf("float2 vertexpos = %s[sk_VertexID ^ (sk_VertexID >> 1)];", hullPts);
52         gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
53 
54         fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag,
55                               &AccessCodeString(v), "vertexpos", nullptr, nullptr, nullptr);
56     }
57 
58     // Fragment shader.
59     fShader->emitSampleMaskCode(args.fFragBuilder);
60 }
61 
reset(PrimitiveType primitiveType,GrResourceProvider * rp)62 void GrSampleMaskProcessor::reset(PrimitiveType primitiveType, GrResourceProvider* rp) {
63     fPrimitiveType = primitiveType;  // This will affect the return values for numInputPoints, etc.
64     SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
65 
66     this->resetCustomFeatures();
67     fInputAttribs.reset();
68 
69     switch (fPrimitiveType) {
70         case PrimitiveType::kTriangles:
71         case PrimitiveType::kWeightedTriangles:
72             fInputAttribs.emplace_back("point", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
73             this->setVertexAttributes(fInputAttribs.begin(), 1);
74             this->setInstanceAttributes(nullptr, 0);
75             break;
76         case PrimitiveType::kQuadratics:
77         case PrimitiveType::kCubics:
78         case PrimitiveType::kConics: {
79             auto instanceAttribType = (PrimitiveType::kQuadratics == fPrimitiveType)
80                     ? kFloat3_GrVertexAttribType : kFloat4_GrVertexAttribType;
81             auto shaderVarType = (PrimitiveType::kQuadratics == fPrimitiveType)
82                     ? kFloat3_GrSLType : kFloat4_GrSLType;
83             fInputAttribs.emplace_back("X", instanceAttribType, shaderVarType);
84             fInputAttribs.emplace_back("Y", instanceAttribType, shaderVarType);
85             this->setVertexAttributes(nullptr, 0);
86             this->setInstanceAttributes(fInputAttribs.begin(), fInputAttribs.count());
87             this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
88             break;
89         }
90     }
91 }
92 
appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer,int instanceCount,int baseInstance,SkTArray<GrMesh> * out) const93 void GrSampleMaskProcessor::appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
94                                        int baseInstance, SkTArray<GrMesh>* out) const {
95     SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
96 
97     switch (fPrimitiveType) {
98         case PrimitiveType::kTriangles:
99         case PrimitiveType::kWeightedTriangles: {
100             GrMesh& mesh = out->emplace_back(GrPrimitiveType::kTriangles);
101             mesh.setNonIndexedNonInstanced(instanceCount * 3);
102             mesh.setVertexData(std::move(instanceBuffer), baseInstance * 3);
103             break;
104         }
105         case PrimitiveType::kQuadratics:
106         case PrimitiveType::kCubics:
107         case PrimitiveType::kConics: {
108             GrMesh& mesh = out->emplace_back(GrPrimitiveType::kTriangleStrip);
109             mesh.setInstanced(std::move(instanceBuffer), instanceCount, baseInstance, 4);
110             break;
111         }
112     }
113 }
114 
onCreateGLSLInstance(std::unique_ptr<Shader> shader) const115 GrGLSLPrimitiveProcessor* GrSampleMaskProcessor::onCreateGLSLInstance(
116         std::unique_ptr<Shader> shader) const {
117     return new Impl(std::move(shader));
118 }
119