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&) override {} |
19 | |
20 | void onEmitCode(EmitArgs&, GrGPArgs*) override; |
21 | |
22 | const std::unique_ptr<Shader> fShader; |
23 | }; |
24 | |
25 | void GrSampleMaskProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { |
26 | const GrSampleMaskProcessor& proc = args.fGP.cast<GrSampleMaskProcessor>(); |
27 | GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
28 | GrGLSLVertexBuilder* v = args.fVertBuilder; |
29 | int numInputPoints = proc.numInputPoints(); |
30 | int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3; |
31 | |
32 | varyingHandler->emitAttributes(proc); |
33 | SkASSERT(!*args.fFPCoordTransformHandler); |
34 | |
35 | if (PrimitiveType::kTriangles == proc.fPrimitiveType) { |
36 | SkASSERT(!proc.hasInstanceAttributes()); // Triangles are drawn with vertex arrays. |
37 | gpArgs->fPositionVar = proc.fInputAttribs.front().asShaderVar(); |
38 | } else { |
39 | SkASSERT(!proc.hasVertexAttributes()); // Curves are drawn with instanced rendering. |
40 | |
41 | // Shaders expect a global "bloat" variable when calculating gradients. |
42 | v->defineConstant("half" , "bloat" , ".5" ); |
43 | |
44 | const char* swizzle = (4 == numInputPoints || proc.hasInputWeight()) ? "xyzw" : "xyz" ; |
45 | v->codeAppendf("float%ix2 pts = transpose(float2x%i(X.%s, Y.%s));" , |
46 | inputWidth, inputWidth, swizzle, swizzle); |
47 | |
48 | const char* hullPts = "pts" ; |
49 | fShader->emitSetupCode(v, "pts" , &hullPts); |
50 | v->codeAppendf("float2 vertexpos = %s[sk_VertexID ^ (sk_VertexID >> 1)];" , hullPts); |
51 | gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos" ); |
52 | |
53 | fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, |
54 | &AccessCodeString(v), "vertexpos" , nullptr, nullptr, nullptr); |
55 | } |
56 | |
57 | // Fragment shader. |
58 | fShader->emitSampleMaskCode(args.fFragBuilder); |
59 | } |
60 | |
61 | void GrSampleMaskProcessor::reset(PrimitiveType primitiveType, int subpassIdx, |
62 | GrResourceProvider* rp) { |
63 | SkASSERT(subpassIdx == 0); |
64 | fPrimitiveType = primitiveType; // This will affect the return values for numInputPoints, etc. |
65 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
66 | |
67 | this->resetCustomFeatures(); |
68 | fInputAttribs.reset(); |
69 | |
70 | switch (fPrimitiveType) { |
71 | case PrimitiveType::kTriangles: |
72 | case PrimitiveType::kWeightedTriangles: |
73 | fInputAttribs.emplace_back("point" , kFloat2_GrVertexAttribType, kFloat2_GrSLType); |
74 | this->setVertexAttributes(fInputAttribs.begin(), 1); |
75 | this->setInstanceAttributes(nullptr, 0); |
76 | break; |
77 | case PrimitiveType::kQuadratics: |
78 | case PrimitiveType::kCubics: |
79 | case PrimitiveType::kConics: { |
80 | auto instanceAttribType = (PrimitiveType::kQuadratics == fPrimitiveType) |
81 | ? kFloat3_GrVertexAttribType : kFloat4_GrVertexAttribType; |
82 | auto shaderVarType = (PrimitiveType::kQuadratics == fPrimitiveType) |
83 | ? kFloat3_GrSLType : kFloat4_GrSLType; |
84 | fInputAttribs.emplace_back("X" , instanceAttribType, shaderVarType); |
85 | fInputAttribs.emplace_back("Y" , instanceAttribType, shaderVarType); |
86 | this->setVertexAttributes(nullptr, 0); |
87 | this->setInstanceAttributes(fInputAttribs.begin(), fInputAttribs.count()); |
88 | this->setWillUseCustomFeature(CustomFeatures::kSampleLocations); |
89 | break; |
90 | } |
91 | } |
92 | } |
93 | |
94 | GrPrimitiveType GrSampleMaskProcessor::primType() const { |
95 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
96 | |
97 | switch (fPrimitiveType) { |
98 | case PrimitiveType::kTriangles: |
99 | case PrimitiveType::kWeightedTriangles: |
100 | return GrPrimitiveType::kTriangles; |
101 | case PrimitiveType::kQuadratics: |
102 | case PrimitiveType::kCubics: |
103 | case PrimitiveType::kConics: |
104 | return GrPrimitiveType::kTriangleStrip; |
105 | default: |
106 | return GrPrimitiveType::kTriangleStrip; |
107 | } |
108 | } |
109 | |
110 | void GrSampleMaskProcessor::bindBuffers(GrOpsRenderPass* renderPass, |
111 | sk_sp<const GrBuffer> instanceBuffer) const { |
112 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
113 | |
114 | switch (fPrimitiveType) { |
115 | case PrimitiveType::kTriangles: |
116 | case PrimitiveType::kWeightedTriangles: { |
117 | renderPass->bindBuffers(nullptr, nullptr, std::move(instanceBuffer)); |
118 | break; |
119 | } |
120 | case PrimitiveType::kQuadratics: |
121 | case PrimitiveType::kCubics: |
122 | case PrimitiveType::kConics: { |
123 | renderPass->bindBuffers(nullptr, std::move(instanceBuffer), nullptr); |
124 | break; |
125 | } |
126 | } |
127 | } |
128 | |
129 | void GrSampleMaskProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount, |
130 | int baseInstance) const { |
131 | SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType); |
132 | |
133 | switch (fPrimitiveType) { |
134 | case PrimitiveType::kTriangles: |
135 | case PrimitiveType::kWeightedTriangles: { |
136 | renderPass->draw(instanceCount * 3, baseInstance * 3); |
137 | break; |
138 | } |
139 | case PrimitiveType::kQuadratics: |
140 | case PrimitiveType::kCubics: |
141 | case PrimitiveType::kConics: { |
142 | renderPass->drawInstanced(instanceCount, baseInstance, 4, 0); |
143 | break; |
144 | } |
145 | } |
146 | } |
147 | |
148 | GrGLSLPrimitiveProcessor* GrSampleMaskProcessor::onCreateGLSLInstance( |
149 | std::unique_ptr<Shader> shader) const { |
150 | return new Impl(std::move(shader)); |
151 | } |
152 | |