blob: 5cb4c069ab4795edef759b24b1129473ebbd0f45 [file] [log] [blame]
joshualitt6cd70ff2015-06-26 14:20:41 -07001/*
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 "Benchmark.h"
9#include "SkCanvas.h"
10#include "SkImageEncoder.h"
joshualitt74a07db2015-07-01 12:39:07 -070011
joshualitt6cd70ff2015-06-26 14:20:41 -070012#if SK_SUPPORT_GPU
joshualitt74a07db2015-07-01 12:39:07 -070013#include "GLBench.h"
joshualitt6cd70ff2015-06-26 14:20:41 -070014#include "gl/GrGLGLSL.h"
15#include "gl/GrGLInterface.h"
16#include "gl/GrGLShaderVar.h"
17#include "gl/GrGLUtil.h"
18#include "glsl/GrGLSLCaps.h"
joshualitt6cd70ff2015-06-26 14:20:41 -070019
20/*
21 * This is a native GL benchmark for instanced arrays vs vertex buffer objects. To benchmark this
22 * functionality, we draw n * kDrawMultipier triangles per run. If this number is less than
23 * kNumTri then we do a single draw, either with instances, or drawArrays. Otherwise we do
24 * multiple draws.
25 *
26 * Additionally, there is a divisor, which if > 0 will act as a multiplier for the number of draws
27 * issued.
28 */
joshualitte784db42015-06-29 06:58:06 -070029
joshualitt74a07db2015-07-01 12:39:07 -070030class GLCpuPosInstancedArraysBench : public GLBench {
joshualitt6cd70ff2015-06-26 14:20:41 -070031public:
32 /*
33 * Clients can decide to use either:
34 * kUseOne_VboSetup - one vertex buffer with colors and positions interleaved
35 * kUseTwo_VboSetup - two vertex buffers, one for colors, one for positions
36 * kUseInstance_VboSetup - two vertex buffers, one with per vertex indices, one with per
37 * instance colors
38 */
39 enum VboSetup {
40 kUseOne_VboSetup,
41 kUseTwo_VboSetup,
42 kUseInstance_VboSetup,
43 };
44
45 /*
46 * drawDiv will act as a multiplier for the number of draws we issue if > 0. ie, 2 will issue
47 * 2x as many draws, 4 will issue 4x as many draws etc. There is a limit however, which is
48 * kDrawMultipier.
49 */
50 GLCpuPosInstancedArraysBench(VboSetup vboSetup, int32_t drawDiv)
51 : fVboSetup(vboSetup)
joshualitte784db42015-06-29 06:58:06 -070052 , fDrawDiv(drawDiv)
53 , fProgram(0)
54 , fVAO(0) {
joshualitt6cd70ff2015-06-26 14:20:41 -070055 fName = VboSetupToStr(vboSetup, fDrawDiv);
56 }
57
58protected:
59 const char* onGetName() override {
60 return fName.c_str();
61 }
62
joshualitt74a07db2015-07-01 12:39:07 -070063 const GrGLContext* onGetGLContext(const GrGLContext*) override;
joshualitt6cd70ff2015-06-26 14:20:41 -070064 void setup(const GrGLContext*) override;
joshualitt74a07db2015-07-01 12:39:07 -070065 void glDraw(const int loops, const GrGLContext*) override;
joshualitt6cd70ff2015-06-26 14:20:41 -070066 void teardown(const GrGLInterface*) override;
67
68private:
69 void setupInstanceVbo(const GrGLInterface*, const SkMatrix*);
70 void setupDoubleVbo(const GrGLInterface*, const SkMatrix*);
71 void setupSingleVbo(const GrGLInterface*, const SkMatrix*);
joshualitt74a07db2015-07-01 12:39:07 -070072 GrGLuint setupShader(const GrGLContext*);
joshualitt6cd70ff2015-06-26 14:20:41 -070073
74 static SkString VboSetupToStr(VboSetup vboSetup, uint32_t drawDiv) {
75 SkString name("GLInstancedArraysBench");
76 switch (vboSetup) {
77 default:
78 case kUseOne_VboSetup:
79 name.appendf("_one_%u", drawDiv);
80 break;
81 case kUseTwo_VboSetup:
82 name.appendf("_two_%u", drawDiv);
83 break;
84 case kUseInstance_VboSetup:
85 name.append("_instance");
86 break;
87 }
88 return name;
89 }
90
joshualitt74a07db2015-07-01 12:39:07 -070091 static const GrGLuint kScreenWidth = 800;
92 static const GrGLuint kScreenHeight = 600;
93 static const uint32_t kNumTri = 10000;
94 static const uint32_t kVerticesPerTri = 3;
95 static const uint32_t kDrawMultiplier = 512;
96
joshualitt6cd70ff2015-06-26 14:20:41 -070097 SkString fName;
98 VboSetup fVboSetup;
99 uint32_t fDrawDiv;
100 SkTArray<GrGLuint> fBuffers;
101 GrGLuint fProgram;
102 GrGLuint fVAO;
joshualitt74a07db2015-07-01 12:39:07 -0700103 GrGLuint fTexture;
joshualitt6cd70ff2015-06-26 14:20:41 -0700104};
105
joshualitt6cd70ff2015-06-26 14:20:41 -0700106///////////////////////////////////////////////////////////////////////////////////////////////////
107
joshualitt74a07db2015-07-01 12:39:07 -0700108GrGLuint GLCpuPosInstancedArraysBench::setupShader(const GrGLContext* ctx) {
joshualitt6cd70ff2015-06-26 14:20:41 -0700109 const char* version = GrGLGetGLSLVersionDecl(*ctx);
110
111 // setup vertex shader
112 GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
113 GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
114 GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier);
115
116 SkString vshaderTxt(version);
117 aPosition.appendDecl(*ctx, &vshaderTxt);
118 vshaderTxt.append(";\n");
119 aColor.appendDecl(*ctx, &vshaderTxt);
120 vshaderTxt.append(";\n");
121 oColor.appendDecl(*ctx, &vshaderTxt);
122 vshaderTxt.append(";\n");
123
124 vshaderTxt.append(
125 "void main()\n"
126 "{\n"
127 "gl_Position = vec4(a_position, 0.f, 1.f);\n"
128 "o_color = a_color;\n"
129 "}\n");
130
131 const GrGLInterface* gl = ctx->interface();
joshualitt6cd70ff2015-06-26 14:20:41 -0700132
133 // setup fragment shader
134 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
135 SkString fshaderTxt(version);
136 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->fStandard,
137 &fshaderTxt);
138 oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
139 oColor.appendDecl(*ctx, &fshaderTxt);
140 fshaderTxt.append(";\n");
141
142 const char* fsOutName;
143 if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) {
144 oFragColor.appendDecl(*ctx, &fshaderTxt);
145 fshaderTxt.append(";\n");
146 fsOutName = oFragColor.c_str();
147 } else {
148 fsOutName = "gl_FragColor";
149 }
150
151 fshaderTxt.appendf(
152 "void main()\n"
153 "{\n"
154 "%s = vec4(o_color, 1.0f);\n"
155 "}\n", fsOutName);
156
joshualitt74a07db2015-07-01 12:39:07 -0700157 return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str());
joshualitt6cd70ff2015-06-26 14:20:41 -0700158}
159
160template<typename Func>
161static void setup_matrices(int numQuads, Func f) {
joshualitt6cd70ff2015-06-26 14:20:41 -0700162 // We draw a really small triangle so we are not fill rate limited
163 for (int i = 0 ; i < numQuads; i++) {
164 SkMatrix m = SkMatrix::I();
165 m.setScale(0.0001f, 0.0001f);
166 f(m);
167 }
168}
169
joshualitt6cd70ff2015-06-26 14:20:41 -0700170///////////////////////////////////////////////////////////////////////////////////////////////////
171
joshualitt74a07db2015-07-01 12:39:07 -0700172const GrGLContext* GLCpuPosInstancedArraysBench::onGetGLContext(const GrGLContext* ctx) {
173 // We only care about gpus with drawArraysInstanced support
174 if (!ctx->interface()->fFunctions.fDrawArraysInstanced) {
halcanary96fcdcc2015-08-27 07:41:13 -0700175 return nullptr;
joshualitt74a07db2015-07-01 12:39:07 -0700176 }
177 return ctx;
178}
179
joshualitt6cd70ff2015-06-26 14:20:41 -0700180void GLCpuPosInstancedArraysBench::setupInstanceVbo(const GrGLInterface* gl,
181 const SkMatrix* viewMatrices) {
182 // We draw all of the instances at a single place because we aren't allowed to have per vertex
183 // per instance attributes
184 SkPoint positions[kVerticesPerTri];
185 positions[0].set(-1.0f, -1.0f);
186 positions[1].set( 1.0f, -1.0f);
187 positions[2].set( 1.0f, 1.0f);
188 viewMatrices[0].mapPointsWithStride(positions, sizeof(SkPoint), kVerticesPerTri);
189
190 // setup colors so we can detect we are actually drawing instances(the last triangle will be
191 // a different color)
192 GrGLfloat colors[kVerticesPerTri * kNumTri];
193 for (uint32_t i = 0; i < kNumTri; i++) {
194 // set colors
195 uint32_t offset = i * kVerticesPerTri;
196 float color = i == kNumTri - 1 ? 1.0f : 0.0f;
197 colors[offset++] = color; colors[offset++] = 0.0f; colors[offset++] = 0.0f;
198 }
199
200 GrGLuint posVBO;
201 // setup position VBO
202 GR_GL_CALL(gl, GenBuffers(1, &posVBO));
203 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, posVBO));
204 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(positions), positions, GR_GL_STATIC_DRAW));
205 GR_GL_CALL(gl, EnableVertexAttribArray(0));
206 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 2 * sizeof(GrGLfloat),
207 (GrGLvoid*)0));
208
209 // setup color VBO
210 GrGLuint instanceVBO;
211 GR_GL_CALL(gl, GenBuffers(1, &instanceVBO));
212 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, instanceVBO));
213 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(colors), colors, GR_GL_STATIC_DRAW));
214 GR_GL_CALL(gl, EnableVertexAttribArray(1));
215 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 3 * sizeof(GrGLfloat),
216 (GrGLvoid*)0));
217 GR_GL_CALL(gl, VertexAttribDivisor(1, 1));
218 fBuffers.push_back(posVBO);
219 fBuffers.push_back(instanceVBO);
220}
221
222void GLCpuPosInstancedArraysBench::setupDoubleVbo(const GrGLInterface* gl,
223 const SkMatrix* viewMatrices) {
224 // Constants for our various shader programs
225 SkPoint positions[kVerticesPerTri * kNumTri];
226 GrGLfloat colors[kVerticesPerTri * kNumTri * 3];
227 for (uint32_t i = 0; i < kNumTri; i++) {
228 SkPoint* position = &positions[i * kVerticesPerTri];
229 position[0].set(-1.0f, -1.0f);
230 position[1].set( 1.0f, -1.0f);
231 position[2].set( 1.0f, 1.0f);
232 viewMatrices[i].mapPointsWithStride(position, sizeof(SkPoint), kVerticesPerTri);
233
234 // set colors
235 float color = i == kNumTri - 1 ? 1.0f : 0.0f;
236 uint32_t offset = i * kVerticesPerTri * 3;
237 for (uint32_t j = 0; j < kVerticesPerTri; j++) {
238 colors[offset++] = color; colors[offset++] = 0.0f; colors[offset++] = 0.0f;
239 }
240 }
241
242 GrGLuint posVBO, colorVBO;
243 // setup position VBO
244 GR_GL_CALL(gl, GenBuffers(1, &posVBO));
245 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, posVBO));
246 GR_GL_CALL(gl, EnableVertexAttribArray(0));
247 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 2 * sizeof(GrGLfloat),
248 (GrGLvoid*)0));
249 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(positions), positions, GR_GL_STATIC_DRAW));
250
251 // setup color VBO
252 GR_GL_CALL(gl, GenBuffers(1, &colorVBO));
253 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, colorVBO));
254 GR_GL_CALL(gl, EnableVertexAttribArray(1));
255 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 3 * sizeof(GrGLfloat),
256 (GrGLvoid*)0));
257 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(colors), colors, GR_GL_STATIC_DRAW));
258
259 fBuffers.push_back(posVBO);
260 fBuffers.push_back(colorVBO);
261}
262
263struct Vertex {
264 SkPoint fPositions;
265 GrGLfloat fColors[3];
266};
267
268void GLCpuPosInstancedArraysBench::setupSingleVbo(const GrGLInterface* gl,
269 const SkMatrix* viewMatrices) {
270 // Constants for our various shader programs
271 Vertex vertices[kVerticesPerTri * kNumTri];
272 for (uint32_t i = 0; i < kNumTri; i++) {
273 Vertex* v = &vertices[i * kVerticesPerTri];
274 v[0].fPositions.set(-1.0f, -1.0f);
275 v[1].fPositions.set( 1.0f, -1.0f);
276 v[2].fPositions.set( 1.0f, 1.0f);
277
278 SkPoint* position = reinterpret_cast<SkPoint*>(v);
279 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesPerTri);
280
281 // set colors
282 float color = i == kNumTri - 1 ? 1.0f : 0.0f;
283 for (uint32_t j = 0; j < kVerticesPerTri; j++) {
284 uint32_t offset = 0;
285 v->fColors[offset++] = color; v->fColors[offset++] = 0.0f; v->fColors[offset++] = 0.0f;
286 v++;
287 }
288 }
289
290 GrGLuint vbo;
291 // setup VBO
292 GR_GL_CALL(gl, GenBuffers(1, &vbo));
293 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, vbo));
294 GR_GL_CALL(gl, EnableVertexAttribArray(0));
295 GR_GL_CALL(gl, EnableVertexAttribArray(1));
296 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex),
297 (GrGLvoid*)0));
298 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex),
299 (GrGLvoid*)(sizeof(SkPoint))));
300 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR_GL_STATIC_DRAW));
301 fBuffers.push_back(vbo);
302}
303
304void GLCpuPosInstancedArraysBench::setup(const GrGLContext* ctx) {
305 const GrGLInterface* gl = ctx->interface();
joshualitt74a07db2015-07-01 12:39:07 -0700306 fTexture = SetupFramebuffer(gl, kScreenWidth, kScreenHeight);
joshualitt6cd70ff2015-06-26 14:20:41 -0700307
joshualitt74a07db2015-07-01 12:39:07 -0700308 fProgram = this->setupShader(ctx);
joshualitt6cd70ff2015-06-26 14:20:41 -0700309
310 // setup matrices
311 int index = 0;
312 SkMatrix viewMatrices[kNumTri];
313 setup_matrices(kNumTri, [&index, &viewMatrices](const SkMatrix& m) {
314 viewMatrices[index++] = m;
315 });
316
317 // setup VAO
318 GR_GL_CALL(gl, GenVertexArrays(1, &fVAO));
319 GR_GL_CALL(gl, BindVertexArray(fVAO));
320
321 switch (fVboSetup) {
322 case kUseOne_VboSetup:
323 this->setupSingleVbo(gl, viewMatrices);
324 break;
325 case kUseTwo_VboSetup:
326 this->setupDoubleVbo(gl, viewMatrices);
327 break;
328 case kUseInstance_VboSetup:
329 this->setupInstanceVbo(gl, viewMatrices);
330 break;
331 }
332
333 // clear screen
334 GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f));
335 GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT));
336
337 // set us up to draw
338 GR_GL_CALL(gl, UseProgram(fProgram));
339 GR_GL_CALL(gl, BindVertexArray(fVAO));
340}
341
joshualitt74a07db2015-07-01 12:39:07 -0700342void GLCpuPosInstancedArraysBench::glDraw(const int loops, const GrGLContext* ctx) {
joshualitt6cd70ff2015-06-26 14:20:41 -0700343 const GrGLInterface* gl = ctx->interface();
344
345 uint32_t maxTrianglesPerFlush = fDrawDiv == 0 ? kNumTri :
346 kDrawMultiplier / fDrawDiv;
347 uint32_t trianglesToDraw = loops * kDrawMultiplier;
348
349 if (kUseInstance_VboSetup == fVboSetup) {
350 while (trianglesToDraw > 0) {
351 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush);
352 GR_GL_CALL(gl, DrawArraysInstanced(GR_GL_TRIANGLES, 0, kVerticesPerTri, triangles));
353 trianglesToDraw -= triangles;
354 }
355 } else {
356 while (trianglesToDraw > 0) {
357 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush);
358 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * triangles));
359 trianglesToDraw -= triangles;
360 }
361 }
362
joshualitt74a07db2015-07-01 12:39:07 -0700363#if 0
joshualitt6cd70ff2015-06-26 14:20:41 -0700364 //const char* filename = "/data/local/tmp/out.png";
365 SkString filename("out");
366 filename.appendf("_%s.png", this->getName());
joshualitt74a07db2015-07-01 12:39:07 -0700367 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str());
joshualitt6cd70ff2015-06-26 14:20:41 -0700368#endif
369}
370
371void GLCpuPosInstancedArraysBench::teardown(const GrGLInterface* gl) {
joshualitt74a07db2015-07-01 12:39:07 -0700372 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0));
373 GR_GL_CALL(gl, BindVertexArray(0));
374 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0));
375 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0));
376 GR_GL_CALL(gl, DeleteTextures(1, &fTexture));
joshualitt6cd70ff2015-06-26 14:20:41 -0700377 GR_GL_CALL(gl, DeleteProgram(fProgram));
378 GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin()));
379 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVAO));
joshualitt31b21f62015-07-16 13:40:51 -0700380 fBuffers.reset();
joshualitt6cd70ff2015-06-26 14:20:41 -0700381}
382
383///////////////////////////////////////////////////////////////////////////////
384
385DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseInstance_VboSetup, 0) )
386DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseOne_VboSetup, 0) )
387DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseTwo_VboSetup, 0) )
388DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseOne_VboSetup, 1) )
389DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseTwo_VboSetup, 1) )
390DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseOne_VboSetup, 2) )
391DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseTwo_VboSetup, 2) )
392DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseOne_VboSetup, 4) )
393DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseTwo_VboSetup, 4) )
394DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseOne_VboSetup, 8) )
395DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench::kUseTwo_VboSetup, 8) )
396
397#endif