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.0, 1.0);\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 | |
155 fshaderTxt.appendf( | |
156 "void main()\n" | |
157 "{\n" | |
158 " vec4 outputColor;\n" | |
159 " %s outputCoverage;\n" | |
160 " outputColor = vec4(%s, 1.0);\n" | |
161 " outputCoverage = %s;\n", | |
162 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4" : "float", | |
163 oColor.getName().c_str(), | |
164 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(1.0)" : "1.0" | |
165 ); | |
166 | |
167 float radius = 1.0f; | |
168 for (uint32_t i = 0; i < fNumStages; i++) { | |
169 float centerX = 1.0f - radius; | |
170 float centerY = 1.0f - radius; | |
171 fshaderTxt.appendf( | |
172 " {\n" | |
173 " float d = length(%s - vec2(%f, %f));\n" | |
174 " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n" | |
175 " outputCoverage = 0.5 * outputCoverage + 0.5 * %s;\n" | |
176 " }\n", | |
177 oPosition.getName().c_str(), centerX, centerY, | |
178 radius, | |
179 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(edgeAlpha)" : "edge
Alpha" | |
180 ); | |
181 radius *= 0.8f; | |
182 } | |
183 fshaderTxt.appendf( | |
184 " {\n" | |
185 " %s = outputColor * outputCoverage;\n" | |
186 " }\n" | |
187 "}\n", | |
188 fsOutName); | |
189 | |
190 return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str()); | |
191 } | |
192 | |
193 template<typename Func> | |
194 static void setup_matrices(int numQuads, Func f) { | |
195 // We draw a really small triangle so we are not fill rate limited | |
196 for (int i = 0 ; i < numQuads; i++) { | |
197 SkMatrix m = SkMatrix::I(); | |
198 m.setScale(0.01f, 0.01f); | |
199 f(m); | |
200 } | |
201 } | |
202 | |
203 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
204 | |
205 struct Vertex { | |
206 SkPoint fPositions; | |
207 GrGLfloat fColors[3]; | |
208 }; | |
209 | |
210 void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix*
viewMatrices) { | |
211 // triangles drawn will alternate between the top-right half of the screen a
nd the bottom-left | |
212 // half of the screen | |
213 Vertex vertices[kVerticesPerTri * kNumTriPerDraw]; | |
214 for (uint32_t i = 0; i < kNumTriPerDraw; i++) { | |
215 Vertex* v = &vertices[i * kVerticesPerTri]; | |
216 if (i % 2 == 0) { | |
217 v[0].fPositions.set(-1.0f, -1.0f); | |
218 v[1].fPositions.set( 1.0f, -1.0f); | |
219 v[2].fPositions.set( 1.0f, 1.0f); | |
220 } else { | |
221 v[0].fPositions.set(-1.0f, -1.0f); | |
222 v[1].fPositions.set( 1.0f, 1.0f); | |
223 v[2].fPositions.set( -1.0f, 1.0f); | |
224 } | |
225 SkPoint* position = reinterpret_cast<SkPoint*>(v); | |
226 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesP
erTri); | |
227 | |
228 GrGLfloat color[3] = {1.0f, 0.0f, 1.0f}; | |
229 for (uint32_t j = 0; j < kVerticesPerTri; j++) { | |
230 v->fColors[0] = color[0]; | |
231 v->fColors[1] = color[1]; | |
232 v->fColors[2] = color[2]; | |
233 v++; | |
234 } | |
235 } | |
236 | |
237 GR_GL_CALL(gl, GenBuffers(1, &fVboId)); | |
238 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId)); | |
239 GR_GL_CALL(gl, EnableVertexAttribArray(0)); | |
240 GR_GL_CALL(gl, EnableVertexAttribArray(1)); | |
241 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), | |
242 (GrGLvoid*)0)); | |
243 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), | |
244 (GrGLvoid*)(sizeof(SkPoint)))); | |
245 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR
_GL_STATIC_DRAW)); | |
246 } | |
247 | |
248 void GLVec4ScalarBench::setup(const GrGLContext* ctx) { | |
249 const GrGLInterface* gl = ctx->interface(); | |
250 if (!gl) { | |
251 SkFAIL("GL interface is null in setup()\n"); | |
252 } | |
253 fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); | |
254 | |
255 fProgram = this->setupShader(ctx); | |
256 | |
257 GR_GL_CALL(gl, GenVertexArrays(1, &fVaoId)); | |
258 GR_GL_CALL(gl, BindVertexArray(fVaoId)); | |
259 | |
260 int index = 0; | |
261 SkMatrix viewMatrices[kNumTriPerDraw]; | |
262 setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { | |
263 viewMatrices[index++] = m; | |
264 }); | |
265 this->setupSingleVbo(gl, viewMatrices); | |
266 | |
267 GR_GL_CALL(gl, UseProgram(fProgram)); | |
268 GR_GL_CALL(gl, BindVertexArray(fVaoId)); | |
269 } | |
270 | |
271 void GLVec4ScalarBench::glDraw(const int loops, const GrGLContext* ctx) { | |
272 const GrGLInterface* gl = ctx->interface(); | |
273 | |
274 for (int i = 0; i < loops; i++) { | |
275 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriP
erDraw)); | |
276 } | |
277 | |
278 // using -w when running nanobench will not produce correct images; | |
279 // changing this to #if 1 will write the correct images to the Skia folder. | |
280 #if 0 | |
281 SkString filename("out"); | |
282 filename.appendf("_%s.png", this->getName()); | |
283 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); | |
284 #endif | |
285 } | |
286 | |
287 void GLVec4ScalarBench::teardown(const GrGLInterface* gl) { | |
288 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); | |
289 GR_GL_CALL(gl, BindVertexArray(0)); | |
290 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); | |
291 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); | |
292 GR_GL_CALL(gl, DeleteTextures(1, &fFboTextureId)); | |
293 GR_GL_CALL(gl, DeleteProgram(fProgram)); | |
294 GR_GL_CALL(gl, DeleteBuffers(1, &fVboId)); | |
295 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVaoId)); | |
296 } | |
297 | |
298 /////////////////////////////////////////////////////////////////////////////// | |
299 | |
300 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 1) ) | |
301 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 1) ) | |
302 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 2) ) | |
303 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 2) ) | |
304 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 4) ) | |
305 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 4) ) | |
306 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 6) ) | |
307 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 6) ) | |
308 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 8) ) | |
309 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 8) ) | |
310 | |
311 #endif | |
OLD | NEW |