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/GrOpsRenderPass.h" |
11 | #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
12 | |
13 | class GrSampleMaskProcessor::Impl : public GrGLSLGeometryProcessor { |
14 | public: |
15 | Impl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {} |
16 | |
17 | private: |
18 | void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&, |
19 | const CoordTransformRange&) override {} |
20 | |
21 | void onEmitCode(EmitArgs&, GrGPArgs*) override; |
22 | |
23 | const std::unique_ptr<Shader> fShader; |
24 | }; |
25 | |
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); |
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 | |
62 | void GrSampleMaskProcessor::reset(PrimitiveType primitiveType, int subpassIdx, |
63 | GrResourceProvider* rp) { |
64 | SkASSERT(subpassIdx == 0); |
65 | fPrimitiveType = primitiveType; // This will affect the return values for numInputPoints, etc. |
66 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
67 | |
68 | this->resetCustomFeatures(); |
69 | fInputAttribs.reset(); |
70 | |
71 | switch (fPrimitiveType) { |
72 | case PrimitiveType::kTriangles: |
73 | case PrimitiveType::kWeightedTriangles: |
74 | fInputAttribs.emplace_back("point" , kFloat2_GrVertexAttribType, kFloat2_GrSLType); |
75 | this->setVertexAttributes(fInputAttribs.begin(), 1); |
76 | this->setInstanceAttributes(nullptr, 0); |
77 | break; |
78 | case PrimitiveType::kQuadratics: |
79 | case PrimitiveType::kCubics: |
80 | case PrimitiveType::kConics: { |
81 | auto instanceAttribType = (PrimitiveType::kQuadratics == fPrimitiveType) |
82 | ? kFloat3_GrVertexAttribType : kFloat4_GrVertexAttribType; |
83 | auto shaderVarType = (PrimitiveType::kQuadratics == fPrimitiveType) |
84 | ? kFloat3_GrSLType : kFloat4_GrSLType; |
85 | fInputAttribs.emplace_back("X" , instanceAttribType, shaderVarType); |
86 | fInputAttribs.emplace_back("Y" , instanceAttribType, shaderVarType); |
87 | this->setVertexAttributes(nullptr, 0); |
88 | this->setInstanceAttributes(fInputAttribs.begin(), fInputAttribs.count()); |
89 | this->setWillUseCustomFeature(CustomFeatures::kSampleLocations); |
90 | break; |
91 | } |
92 | } |
93 | } |
94 | |
95 | GrPrimitiveType GrSampleMaskProcessor::primType() const { |
96 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
97 | |
98 | switch (fPrimitiveType) { |
99 | case PrimitiveType::kTriangles: |
100 | case PrimitiveType::kWeightedTriangles: |
101 | return GrPrimitiveType::kTriangles; |
102 | case PrimitiveType::kQuadratics: |
103 | case PrimitiveType::kCubics: |
104 | case PrimitiveType::kConics: |
105 | return GrPrimitiveType::kTriangleStrip; |
106 | default: |
107 | return GrPrimitiveType::kTriangleStrip; |
108 | } |
109 | } |
110 | |
111 | void GrSampleMaskProcessor::bindBuffers(GrOpsRenderPass* renderPass, |
112 | const GrBuffer* instanceBuffer) const { |
113 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
114 | |
115 | switch (fPrimitiveType) { |
116 | case PrimitiveType::kTriangles: |
117 | case PrimitiveType::kWeightedTriangles: { |
118 | renderPass->bindBuffers(nullptr, nullptr, instanceBuffer); |
119 | break; |
120 | } |
121 | case PrimitiveType::kQuadratics: |
122 | case PrimitiveType::kCubics: |
123 | case PrimitiveType::kConics: { |
124 | renderPass->bindBuffers(nullptr, instanceBuffer, nullptr); |
125 | break; |
126 | } |
127 | } |
128 | } |
129 | |
130 | void GrSampleMaskProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount, |
131 | int baseInstance) const { |
132 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
133 | |
134 | switch (fPrimitiveType) { |
135 | case PrimitiveType::kTriangles: |
136 | case PrimitiveType::kWeightedTriangles: { |
137 | renderPass->draw(instanceCount * 3, baseInstance * 3); |
138 | break; |
139 | } |
140 | case PrimitiveType::kQuadratics: |
141 | case PrimitiveType::kCubics: |
142 | case PrimitiveType::kConics: { |
143 | renderPass->drawInstanced(instanceCount, baseInstance, 4, 0); |
144 | break; |
145 | } |
146 | } |
147 | } |
148 | |
149 | GrGLSLPrimitiveProcessor* GrSampleMaskProcessor::onCreateGLSLInstance( |
150 | std::unique_ptr<Shader> shader) const { |
151 | return new Impl(std::move(shader)); |
152 | } |
153 | |