OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2015 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 "SkMatrix.h" | |
9 #include "SkPoint.h" | |
10 #include "SkString.h" | |
11 | |
12 #if SK_SUPPORT_GPU | |
13 #include "GLBench.h" | |
14 #include "gl/GrGLGLSL.h" | |
15 #include "gl/GrGLInterface.h" | |
16 #include "gl/GrGLShaderVar.h" | |
17 #include "gl/GrGLUtil.h" | |
18 #include "glsl/GrGLSLCaps.h" | |
19 | |
20 #include <stdio.h> | |
21 | |
22 /** | |
23 * This is a GL benchmark for comparing the performance of using vec4 or float f or coverage in GLSL. | |
24 * The generated shader code from this bench will draw several overlapping circl es, one in each | |
25 * stage, to simulate coverage calculations. The number of circles (i.e. the nu mber of stages) can | |
26 * be set as a parameter. | |
27 */ | |
28 | |
29 class GLVec4ScalarBench : public GLBench { | |
30 public: | |
31 /* | |
32 * Use float or vec4 as GLSL data type for the output coverage | |
33 */ | |
34 enum CoverageSetup { | |
35 kUseScalar_CoverageSetup, | |
36 kUseVec4_CoverageSetup, | |
37 }; | |
38 | |
39 /* | |
40 * numStages determines the number of shader stages before the XP, | |
41 * which consequently determines how many circles are drawn | |
42 */ | |
43 GLVec4ScalarBench(CoverageSetup coverageSetup, uint32_t numStages) | |
44 : fCoverageSetup(coverageSetup) | |
45 , fNumStages(numStages) | |
46 , fVboId(0) | |
47 , fProgram(0) | |
48 , fVaoId(0) { | |
49 fName = NumStagesSetupToStr(coverageSetup, numStages); | |
50 } | |
51 | |
52 protected: | |
53 const char* onGetName() override { | |
54 return fName.c_str(); | |
55 } | |
56 | |
57 void setup(const GrGLContext*) override; | |
58 void glDraw(const int loops, const GrGLContext*) override; | |
59 void teardown(const GrGLInterface*) override; | |
60 | |
61 private: | |
62 void setupSingleVbo(const GrGLInterface*, const SkMatrix*); | |
63 GrGLuint setupShader(const GrGLContext*); | |
64 | |
65 | |
66 static SkString NumStagesSetupToStr(CoverageSetup coverageSetup, uint32_t nu mStages) { | |
67 SkString name("GLVec4ScalarBench"); | |
68 switch (coverageSetup) { | |
69 default: | |
70 case kUseScalar_CoverageSetup: | |
71 name.appendf("_scalar_%u_stage", numStages); | |
72 break; | |
73 case kUseVec4_CoverageSetup: | |
74 name.appendf("_vec4_%u_stage", numStages); | |
75 break; | |
76 } | |
77 return name; | |
78 } | |
79 | |
80 static const GrGLuint kScreenWidth = 800; | |
81 static const GrGLuint kScreenHeight = 600; | |
82 static const uint32_t kNumTriPerDraw = 512; | |
83 static const uint32_t kVerticesPerTri = 3; | |
84 | |
85 SkString fName; | |
86 CoverageSetup fCoverageSetup; | |
87 uint32_t fNumStages; | |
88 GrGLuint fVboId; | |
89 GrGLuint fProgram; | |
90 GrGLuint fVaoId; | |
91 GrGLuint fFboTextureId; | |
92 }; | |
93 | |
94 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
95 | |
96 GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) { | |
97 const char* version = GrGLGetGLSLVersionDecl(*ctx); | |
98 | |
99 // this shader draws fNumStages overlapping circles of increasing opacity (c overage) and | |
100 // decreasing size, with the center of each subsequent circle closer to the bottom-right | |
101 // corner of the screen than the previous circle. | |
102 | |
103 // set up vertex shader; this is a trivial vertex shader that passes through position and color | |
104 GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribu te_TypeModifier); | |
105 GrGLShaderVar oPosition("o_position", kVec2f_GrSLType, GrShaderVar::kVarying Out_TypeModifier); | |
106 GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_Typ eModifier); | |
107 GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_Ty peModifier); | |
108 | |
109 SkString vshaderTxt(version); | |
110 aPosition.appendDecl(*ctx, &vshaderTxt); | |
111 vshaderTxt.append(";\n"); | |
112 aColor.appendDecl(*ctx, &vshaderTxt); | |
113 vshaderTxt.append(";\n"); | |
114 oPosition.appendDecl(*ctx, &vshaderTxt); | |
115 vshaderTxt.append(";\n"); | |
116 oColor.appendDecl(*ctx, &vshaderTxt); | |
117 vshaderTxt.append(";\n"); | |
118 | |
119 vshaderTxt.append( | |
120 "void main()\n" | |
121 "{\n" | |
122 " gl_Position = vec4(a_position, 0.f, 1.f);\n" | |
123 " o_position = a_position;\n" | |
124 " o_color = a_color;\n" | |
125 "}\n"); | |
126 | |
127 const GrGLInterface* gl = ctx->interface(); | |
128 | |
129 // set up fragment shader; this fragment shader will have fNumStages coverag e stages plus an | |
130 // XP stage at the end. Each coverage stage computes the pixel's distance f rom some hard- | |
131 // coded center and compare that to some hard-coded circle radius to compute a coverage. | |
132 // Then, this coverage is mixed with the coverage from the previous stage an d passed to the | |
133 // next stage. | |
134 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_T ypeModifier); | |
135 SkString fshaderTxt(version); | |
136 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->f Standard, | |
137 &fshaderTxt); | |
138 oPosition.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); | |
139 oPosition.appendDecl(*ctx, &fshaderTxt); | |
140 fshaderTxt.append(";\n"); | |
141 oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); | |
142 oColor.appendDecl(*ctx, &fshaderTxt); | |
143 fshaderTxt.append(";\n"); | |
144 | |
145 const char* fsOutName; | |
146 if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { | |
147 oFragColor.appendDecl(*ctx, &fshaderTxt); | |
148 fshaderTxt.append(";\n"); | |
149 fsOutName = oFragColor.c_str(); | |
150 } else { | |
151 fsOutName = "gl_FragColor"; | |
152 } | |
153 | |
154 switch (fCoverageSetup) { | |
tomhudson
2015/07/13 16:00:13
These two cases are identical *except for* two poi
| |
155 default: | |
156 case kUseVec4_CoverageSetup: | |
157 fshaderTxt.appendf( | |
158 "void main()\n" | |
159 "{\n" | |
160 " vec4 outputColor;\n" | |
161 " vec4 outputCoverage;\n" | |
162 " outputColor = vec4(%s, 1.0);\n" | |
163 " outputCoverage = vec4(1.0);\n", | |
164 oColor.getName().c_str()); | |
165 break; | |
166 case kUseScalar_CoverageSetup: | |
167 fshaderTxt.appendf( | |
168 "void main()\n" | |
169 "{\n" | |
170 " vec4 outputColor;\n" | |
171 " float outputCoverage;\n" | |
172 " outputColor = vec4(%s, 1.0);\n" | |
173 " outputCoverage = 1.0;\n", | |
174 oColor.getName().c_str()); | |
175 break; | |
176 } | |
177 float radius = 1.0f; | |
178 for (uint32_t i = 0; i < fNumStages; i++) { | |
179 float centerX = 1.0f - radius; | |
180 float centerY = 1.0f - radius; | |
181 switch (fCoverageSetup) { | |
tomhudson
2015/07/13 16:00:13
As above, can we merge most of the text of these t
| |
182 default: | |
183 case kUseVec4_CoverageSetup: | |
184 fshaderTxt.appendf( | |
185 " {\n" | |
186 " float d = length(%s - vec2(%f, %f));\n" | |
187 " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n" | |
188 " outputCoverage = 0.5 * outputCoverage + 0.5 * v ec4(edgeAlpha);\n" | |
189 " }\n", | |
190 oPosition.getName().c_str(), | |
191 centerX, centerY, | |
192 radius | |
193 ); | |
194 break; | |
195 case kUseScalar_CoverageSetup: | |
196 fshaderTxt.appendf( | |
197 " {\n" | |
198 " float d = length(%s - vec2(%f, %f));\n" | |
199 " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n" | |
200 " outputCoverage = 0.5 * outputCoverage + 0.5 * e dgeAlpha;\n" | |
201 " }\n", | |
202 oPosition.getName().c_str(), | |
203 centerX, centerY, | |
204 radius | |
205 ); | |
206 break; | |
207 } | |
208 radius *= 0.8f; | |
209 } | |
210 fshaderTxt.appendf( | |
211 " {\n" | |
212 " %s = outputColor * outputCoverage;\n" | |
213 " }\n" | |
214 "}\n", | |
215 fsOutName); | |
216 | |
217 return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str()); | |
218 } | |
219 | |
220 template<typename Func> | |
221 static void setup_matrices(int numQuads, Func f) { | |
222 // We draw a really small triangle so we are not fill rate limited | |
223 for (int i = 0 ; i < numQuads; i++) { | |
224 SkMatrix m = SkMatrix::I(); | |
225 m.setScale(0.01f, 0.01f); | |
226 f(m); | |
227 } | |
228 } | |
229 | |
230 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
231 | |
232 struct Vertex { | |
233 SkPoint fPositions; | |
234 GrGLfloat fColors[3]; | |
235 }; | |
236 | |
237 void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix* viewMatrices) { | |
238 // triangles drawn will alternate between the top-right half of the screen a nd the bottom-left | |
239 // half of the screen | |
240 Vertex vertices[kVerticesPerTri * kNumTriPerDraw]; | |
241 for (uint32_t i = 0; i < kNumTriPerDraw; i++) { | |
242 Vertex* v = &vertices[i * kVerticesPerTri]; | |
243 if (i % 2 == 0) { | |
244 v[0].fPositions.set(-1.0f, -1.0f); | |
245 v[1].fPositions.set( 1.0f, -1.0f); | |
246 v[2].fPositions.set( 1.0f, 1.0f); | |
247 } else { | |
248 v[0].fPositions.set(-1.0f, -1.0f); | |
249 v[1].fPositions.set( 1.0f, 1.0f); | |
250 v[2].fPositions.set( -1.0f, 1.0f); | |
251 } | |
252 SkPoint* position = reinterpret_cast<SkPoint*>(v); | |
253 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesP erTri); | |
254 | |
255 GrGLfloat color[3] = {1.0f, 0.0f, 1.0f}; | |
256 for (uint32_t j = 0; j < kVerticesPerTri; j++) { | |
257 v->fColors[0] = color[0]; | |
258 v->fColors[1] = color[1]; | |
259 v->fColors[2] = color[2]; | |
260 v++; | |
261 } | |
262 } | |
263 | |
264 GR_GL_CALL(gl, GenBuffers(1, &fVboId)); | |
265 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId)); | |
266 GR_GL_CALL(gl, EnableVertexAttribArray(0)); | |
267 GR_GL_CALL(gl, EnableVertexAttribArray(1)); | |
268 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve rtex), | |
269 (GrGLvoid*)0)); | |
270 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve rtex), | |
271 (GrGLvoid*)(sizeof(SkPoint)))); | |
272 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR _GL_STATIC_DRAW)); | |
273 } | |
274 | |
275 void GLVec4ScalarBench::setup(const GrGLContext* ctx) { | |
276 const GrGLInterface* gl = ctx->interface(); | |
277 fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); | |
278 | |
279 fProgram = this->setupShader(ctx); | |
280 | |
281 GR_GL_CALL(gl, GenVertexArrays(1, &fVaoId)); | |
282 GR_GL_CALL(gl, BindVertexArray(fVaoId)); | |
283 | |
284 int index = 0; | |
285 SkMatrix viewMatrices[kNumTriPerDraw]; | |
286 setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { | |
287 viewMatrices[index++] = m; | |
288 }); | |
289 this->setupSingleVbo(gl, viewMatrices); | |
290 | |
291 GR_GL_CALL(gl, UseProgram(fProgram)); | |
292 GR_GL_CALL(gl, BindVertexArray(fVaoId)); | |
293 } | |
294 | |
295 void GLVec4ScalarBench::glDraw(const int loops, const GrGLContext* ctx) { | |
296 const GrGLInterface* gl = ctx->interface(); | |
297 | |
298 for (int i = 0; i < loops; i++) { | |
299 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriP erDraw)); | |
300 } | |
301 | |
302 | |
303 #if 0 | |
304 SkString filename("out"); | |
305 filename.appendf("_%s.png", this->getName()); | |
306 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); | |
307 #endif | |
308 } | |
309 | |
310 void GLVec4ScalarBench::teardown(const GrGLInterface* gl) { | |
311 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); | |
312 GR_GL_CALL(gl, BindVertexArray(0)); | |
313 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); | |
314 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); | |
315 GR_GL_CALL(gl, DeleteTextures(1, &fFboTextureId)); | |
316 GR_GL_CALL(gl, DeleteProgram(fProgram)); | |
317 GR_GL_CALL(gl, DeleteBuffers(1, &fVboId)); | |
318 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVaoId)); | |
319 } | |
320 | |
321 /////////////////////////////////////////////////////////////////////////////// | |
322 | |
323 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe tup, 1) ) | |
324 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu p, 1) ) | |
325 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe tup, 2) ) | |
326 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu p, 2) ) | |
327 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe tup, 4) ) | |
328 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu p, 4) ) | |
329 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe tup, 6) ) | |
330 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu p, 6) ) | |
331 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe tup, 8) ) | |
332 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu p, 8) ) | |
333 | |
334 #endif | |
OLD | NEW |