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 "Benchmark.h" |
| 9 #include "SkCanvas.h" |
| 10 #include "SkImageEncoder.h" |
| 11 #if SK_SUPPORT_GPU |
| 12 #include "GrTest.h" |
| 13 #include "gl/GrGLGLSL.h" |
| 14 #include "gl/GrGLInterface.h" |
| 15 #include "gl/GrGLShaderVar.h" |
| 16 #include "gl/GrGLUtil.h" |
| 17 #include "glsl/GrGLSLCaps.h" |
| 18 #include <stdio.h> |
| 19 |
| 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. Othe
rwise we do |
| 24 * multiple draws. |
| 25 * |
| 26 * Additionally, there is a divisor, which if > 0 will act as a multiplier for t
he number of draws |
| 27 * issued. |
| 28 */ |
| 29 class GLInstancedArraysBench : public Benchmark { |
| 30 protected: |
| 31 void onPerCanvasPreDraw(SkCanvas* canvas) override; |
| 32 virtual void setup(const GrGLContext*)=0; |
| 33 void onPerCanvasPostDraw(SkCanvas* canvas) override; |
| 34 virtual void teardown(const GrGLInterface*)=0; |
| 35 |
| 36 static const GrGLuint kScreenWidth = 800; |
| 37 static const GrGLuint kScreenHeight = 600; |
| 38 static const uint32_t kNumTri = 10000; |
| 39 static const uint32_t kVerticesPerTri = 3; |
| 40 static const uint32_t kDrawMultiplier = 512; |
| 41 |
| 42 private: |
| 43 GrGLuint fTexture; |
| 44 typedef Benchmark INHERITED; |
| 45 }; |
| 46 |
| 47 #if 0 |
| 48 class GLGpuPosInstancedArraysBench : public GLInstancedArraysBench { |
| 49 protected: |
| 50 const char* onGetName() override { |
| 51 return "GLInstancedArraysBench_gpupos"; |
| 52 } |
| 53 |
| 54 void setup(const GrGLContext*) override; |
| 55 void onDraw(const int loops, SkCanvas* canvas) override; |
| 56 }; |
| 57 #endif |
| 58 |
| 59 class GLCpuPosInstancedArraysBench : public GLInstancedArraysBench { |
| 60 public: |
| 61 /* |
| 62 * Clients can decide to use either: |
| 63 * kUseOne_VboSetup - one vertex buffer with colors and positions inter
leaved |
| 64 * kUseTwo_VboSetup - two vertex buffers, one for colors, one for posit
ions |
| 65 * kUseInstance_VboSetup - two vertex buffers, one with per vertex indices,
one with per |
| 66 * instance colors |
| 67 */ |
| 68 enum VboSetup { |
| 69 kUseOne_VboSetup, |
| 70 kUseTwo_VboSetup, |
| 71 kUseInstance_VboSetup, |
| 72 }; |
| 73 |
| 74 /* |
| 75 * drawDiv will act as a multiplier for the number of draws we issue if > 0.
ie, 2 will issue |
| 76 * 2x as many draws, 4 will issue 4x as many draws etc. There is a limit ho
wever, which is |
| 77 * kDrawMultipier. |
| 78 */ |
| 79 GLCpuPosInstancedArraysBench(VboSetup vboSetup, int32_t drawDiv) |
| 80 : fVboSetup(vboSetup) |
| 81 , fDrawDiv(drawDiv) { |
| 82 fName = VboSetupToStr(vboSetup, fDrawDiv); |
| 83 } |
| 84 |
| 85 protected: |
| 86 const char* onGetName() override { |
| 87 return fName.c_str(); |
| 88 } |
| 89 |
| 90 void setup(const GrGLContext*) override; |
| 91 void onDraw(const int loops, SkCanvas* canvas) override; |
| 92 void teardown(const GrGLInterface*) override; |
| 93 |
| 94 private: |
| 95 void setupInstanceVbo(const GrGLInterface*, const SkMatrix*); |
| 96 void setupDoubleVbo(const GrGLInterface*, const SkMatrix*); |
| 97 void setupSingleVbo(const GrGLInterface*, const SkMatrix*); |
| 98 |
| 99 static SkString VboSetupToStr(VboSetup vboSetup, uint32_t drawDiv) { |
| 100 SkString name("GLInstancedArraysBench"); |
| 101 switch (vboSetup) { |
| 102 default: |
| 103 case kUseOne_VboSetup: |
| 104 name.appendf("_one_%u", drawDiv); |
| 105 break; |
| 106 case kUseTwo_VboSetup: |
| 107 name.appendf("_two_%u", drawDiv); |
| 108 break; |
| 109 case kUseInstance_VboSetup: |
| 110 name.append("_instance"); |
| 111 break; |
| 112 } |
| 113 return name; |
| 114 } |
| 115 |
| 116 SkString fName; |
| 117 VboSetup fVboSetup; |
| 118 uint32_t fDrawDiv; |
| 119 SkTArray<GrGLuint> fBuffers; |
| 120 GrGLuint fProgram; |
| 121 GrGLuint fVAO; |
| 122 }; |
| 123 |
| 124 static const GrGLContext* get_gl_context(SkCanvas* canvas) { |
| 125 // This bench exclusively tests GL calls directly |
| 126 if (NULL == canvas->getGrContext()) { |
| 127 return NULL; |
| 128 } |
| 129 GrContext* context = canvas->getGrContext(); |
| 130 |
| 131 GrTestTarget tt; |
| 132 context->getTestTarget(&tt); |
| 133 if (!tt.target()) { |
| 134 SkDebugf("Couldn't get Gr test target."); |
| 135 return NULL; |
| 136 } |
| 137 |
| 138 const GrGLContext* ctx = tt.glContext(); |
| 139 if (!ctx) { |
| 140 SkDebugf("Couldn't get an interface\n"); |
| 141 return NULL; |
| 142 } |
| 143 |
| 144 // We only care about gpus with drawArraysInstanced support |
| 145 if (!ctx->interface()->fFunctions.fDrawArraysInstanced) { |
| 146 return NULL; |
| 147 } |
| 148 return ctx; |
| 149 } |
| 150 |
| 151 void GLInstancedArraysBench::onPerCanvasPreDraw(SkCanvas* canvas) { |
| 152 // This bench exclusively tests GL calls directly |
| 153 const GrGLContext* ctx = get_gl_context(canvas); |
| 154 if (!ctx) { |
| 155 return; |
| 156 } |
| 157 this->setup(ctx); |
| 158 } |
| 159 |
| 160 void GLInstancedArraysBench::onPerCanvasPostDraw(SkCanvas* canvas) { |
| 161 // This bench exclusively tests GL calls directly |
| 162 const GrGLContext* ctx = get_gl_context(canvas); |
| 163 if (!ctx) { |
| 164 return; |
| 165 } |
| 166 |
| 167 const GrGLInterface* gl = ctx->interface(); |
| 168 |
| 169 // teardown |
| 170 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); |
| 171 GR_GL_CALL(gl, BindVertexArray(0)); |
| 172 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); |
| 173 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); |
| 174 GR_GL_CALL(gl, DeleteTextures(1, &fTexture)); |
| 175 |
| 176 this->teardown(gl); |
| 177 } |
| 178 |
| 179 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 180 |
| 181 // TODO move all of the gpu positioning stuff to a new file |
| 182 #ifdef GPU_POS |
| 183 static const char* gpu_vertex_shader = |
| 184 "layout (location = 0) in vec2 position;\n" |
| 185 "layout (location = 1) in vec3 color;\n" |
| 186 "layout (location = 2) in mat3 offset;\n" |
| 187 |
| 188 "out vec3 fColor;\n" |
| 189 |
| 190 "void main()\n" |
| 191 "{\n" |
| 192 "gl_Position = vec4(offset * vec3(position, 1.0f), 1.f);\n" |
| 193 "fColor = color;\n" |
| 194 "}\n"; |
| 195 #endif |
| 196 |
| 197 static GrGLuint load_shader(const GrGLInterface* gl, const char* shaderSrc, GrGL
enum type) { |
| 198 GrGLuint shader; |
| 199 // Create the shader object |
| 200 GR_GL_CALL_RET(gl, shader, CreateShader(type)); |
| 201 |
| 202 // Load the shader source |
| 203 GR_GL_CALL(gl, ShaderSource(shader, 1, &shaderSrc, NULL)); |
| 204 |
| 205 // Compile the shader |
| 206 GR_GL_CALL(gl, CompileShader(shader)); |
| 207 |
| 208 // Check for compile time errors |
| 209 GrGLint success; |
| 210 GrGLchar infoLog[512]; |
| 211 GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &success)); |
| 212 if (!success) |
| 213 { |
| 214 GR_GL_CALL(gl, GetShaderInfoLog(shader, 512, NULL, infoLog)); |
| 215 SkDebugf("ERROR::SHADER::COMPLIATION_FAILED: %s\n", infoLog); |
| 216 } |
| 217 |
| 218 return shader; |
| 219 } |
| 220 |
| 221 static GrGLuint compile_shader(const GrGLContext* ctx) { |
| 222 const char* version = GrGLGetGLSLVersionDecl(*ctx); |
| 223 |
| 224 // setup vertex shader |
| 225 GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribu
te_TypeModifier); |
| 226 GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_Typ
eModifier); |
| 227 GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_Ty
peModifier); |
| 228 |
| 229 SkString vshaderTxt(version); |
| 230 aPosition.appendDecl(*ctx, &vshaderTxt); |
| 231 vshaderTxt.append(";\n"); |
| 232 aColor.appendDecl(*ctx, &vshaderTxt); |
| 233 vshaderTxt.append(";\n"); |
| 234 oColor.appendDecl(*ctx, &vshaderTxt); |
| 235 vshaderTxt.append(";\n"); |
| 236 |
| 237 vshaderTxt.append( |
| 238 "void main()\n" |
| 239 "{\n" |
| 240 "gl_Position = vec4(a_position, 0.f, 1.f);\n" |
| 241 "o_color = a_color;\n" |
| 242 "}\n"); |
| 243 |
| 244 const GrGLInterface* gl = ctx->interface(); |
| 245 GrGLuint vertexShader = load_shader(gl, vshaderTxt.c_str(), GR_GL_VERTEX_SHA
DER); |
| 246 |
| 247 // setup fragment shader |
| 248 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_T
ypeModifier); |
| 249 SkString fshaderTxt(version); |
| 250 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->f
Standard, |
| 251 &fshaderTxt); |
| 252 oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); |
| 253 oColor.appendDecl(*ctx, &fshaderTxt); |
| 254 fshaderTxt.append(";\n"); |
| 255 |
| 256 const char* fsOutName; |
| 257 if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { |
| 258 oFragColor.appendDecl(*ctx, &fshaderTxt); |
| 259 fshaderTxt.append(";\n"); |
| 260 fsOutName = oFragColor.c_str(); |
| 261 } else { |
| 262 fsOutName = "gl_FragColor"; |
| 263 } |
| 264 |
| 265 fshaderTxt.appendf( |
| 266 "void main()\n" |
| 267 "{\n" |
| 268 "%s = vec4(o_color, 1.0f);\n" |
| 269 "}\n", fsOutName); |
| 270 |
| 271 GrGLuint fragmentShader = load_shader(gl, fshaderTxt.c_str(), GR_GL_FRAGMENT
_SHADER); |
| 272 |
| 273 GrGLint shaderProgram; |
| 274 GR_GL_CALL_RET(gl, shaderProgram, CreateProgram()); |
| 275 GR_GL_CALL(gl, AttachShader(shaderProgram, vertexShader)); |
| 276 GR_GL_CALL(gl, AttachShader(shaderProgram, fragmentShader)); |
| 277 GR_GL_CALL(gl, LinkProgram(shaderProgram)); |
| 278 |
| 279 // Check for linking errors |
| 280 GrGLint success; |
| 281 GrGLchar infoLog[512]; |
| 282 GR_GL_CALL(gl, GetProgramiv(shaderProgram, GR_GL_LINK_STATUS, &success)); |
| 283 if (!success) { |
| 284 GR_GL_CALL(gl, GetProgramInfoLog(shaderProgram, 512, NULL, infoLog)); |
| 285 SkDebugf("Linker Error: %s\n", infoLog); |
| 286 } |
| 287 GR_GL_CALL(gl, DeleteShader(vertexShader)); |
| 288 GR_GL_CALL(gl, DeleteShader(fragmentShader)); |
| 289 |
| 290 return shaderProgram; |
| 291 } |
| 292 |
| 293 //#define DUMP_IMAGES |
| 294 #ifdef DUMP_IMAGES |
| 295 static void dump_image(const GrGLInterface* gl, uint32_t screenWidth, uint32_t s
creenHeight, |
| 296 const char* filename) { |
| 297 // read back pixels |
| 298 uint32_t readback[screenWidth * screenHeight]; |
| 299 GR_GL_CALL(gl, ReadPixels(0, // x |
| 300 0, // y |
| 301 screenWidth, // width |
| 302 screenHeight, // height |
| 303 GR_GL_RGBA, //format |
| 304 GR_GL_UNSIGNED_BYTE, //type |
| 305 readback)); |
| 306 |
| 307 // dump png |
| 308 SkBitmap bm; |
| 309 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(screenWidth, screenHeight)
)) { |
| 310 SkDebugf("couldn't allocate bitmap\n"); |
| 311 return; |
| 312 } |
| 313 |
| 314 bm.setPixels(readback); |
| 315 |
| 316 if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100
)) { |
| 317 SkDebugf("------ failed to encode %s\n", filename); |
| 318 remove(filename); // remove any partial file |
| 319 return; |
| 320 } |
| 321 } |
| 322 #endif |
| 323 |
| 324 static void setup_framebuffer(const GrGLInterface* gl, int screenWidth, int scre
enHeight) { |
| 325 //Setup framebuffer |
| 326 GrGLuint texture; |
| 327 GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); |
| 328 GR_GL_CALL(gl, PixelStorei(GR_GL_PACK_ROW_LENGTH, 0)); |
| 329 GR_GL_CALL(gl, GenTextures(1, &texture)); |
| 330 GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE15)); |
| 331 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texture)); |
| 332 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_
GL_NEAREST)); |
| 333 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_
GL_NEAREST)); |
| 334 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_C
LAMP_TO_EDGE)); |
| 335 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_C
LAMP_TO_EDGE)); |
| 336 GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, |
| 337 0, //level |
| 338 GR_GL_RGBA8, //internal format |
| 339 screenWidth, // width |
| 340 screenHeight, // height |
| 341 0, //border |
| 342 GR_GL_RGBA, //format |
| 343 GR_GL_UNSIGNED_BYTE, // type |
| 344 NULL)); |
| 345 |
| 346 // bind framebuffer |
| 347 GrGLuint framebuffer; |
| 348 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); |
| 349 GR_GL_CALL(gl, GenFramebuffers(1, &framebuffer)); |
| 350 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, framebuffer)); |
| 351 GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, |
| 352 GR_GL_COLOR_ATTACHMENT0, |
| 353 GR_GL_TEXTURE_2D, |
| 354 texture, 0)); |
| 355 GR_GL_CALL(gl, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); |
| 356 GR_GL_CALL(gl, Viewport(0, 0, screenWidth, screenHeight)); |
| 357 } |
| 358 |
| 359 template<typename Func> |
| 360 static void setup_matrices(int numQuads, Func f) { |
| 361 #if 0 |
| 362 float max = sqrt(numQuads); |
| 363 float pos = 1.f / (2 * max); |
| 364 GrGLfloat offset = pos * 2; |
| 365 for(GrGLint row = 0; row < max; row++) { |
| 366 for(GrGLint col = 0; col < max; col++) { |
| 367 SkScalar xOffset = col / max * 2.f - 1.f + offset; |
| 368 SkScalar yOffset = row / max * 2.f - 1.f + offset; |
| 369 SkMatrix translation; |
| 370 SkRandom random; |
| 371 translation.setScale(pos, pos); |
| 372 translation.postTranslate(xOffset, yOffset); |
| 373 f(translation); |
| 374 } |
| 375 } |
| 376 #endif |
| 377 // We draw a really small triangle so we are not fill rate limited |
| 378 for (int i = 0 ; i < numQuads; i++) { |
| 379 SkMatrix m = SkMatrix::I(); |
| 380 m.setScale(0.0001f, 0.0001f); |
| 381 f(m); |
| 382 } |
| 383 } |
| 384 |
| 385 #ifdef GPU_POS |
| 386 void GLGpuPosInstancedArraysBench::setup(const GrGLInterface* gl) { |
| 387 setup_framebuffer(gl, kScreenWidth, kScreenHeight); |
| 388 |
| 389 // compile and use shaders |
| 390 GrGLint shaderProgram = compile_shader(gl, gpu_vertex_shader, fragment_shade
r); |
| 391 |
| 392 // translations |
| 393 int index = 0; |
| 394 GrGLfloat viewMatrices[fNumQuads * fSkMatrixNumCells]; |
| 395 setup_matrices(fNumQuads, [&index, &viewMatrices](const SkMatrix& m) { |
| 396 GrGLGetMatrix<3>(&viewMatrices[index], m); |
| 397 index += fSkMatrixNumCells; |
| 398 }); |
| 399 |
| 400 // Constants for our various shader programs |
| 401 GrGLfloat quad_vertices[] = { |
| 402 // Positions // Colors |
| 403 -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, |
| 404 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
| 405 -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, |
| 406 |
| 407 -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, |
| 408 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
| 409 1.0f, 1.0f, 0.0f, 1.0f, 1.0f |
| 410 }; |
| 411 |
| 412 // update vertex data |
| 413 GrGLuint quadVAO, quadVBO; |
| 414 GR_GL_CALL(gl, GenVertexArrays(1, &quadVAO)); |
| 415 GR_GL_CALL(gl, GenBuffers(1, &quadVBO)); |
| 416 GR_GL_CALL(gl, BindVertexArray(quadVAO)); |
| 417 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, quadVBO)); |
| 418 GR_GL_CALL(gl, EnableVertexAttribArray(0)); |
| 419 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 5 * sizeo
f(GrGLfloat), (GrGLvoid*)0)); |
| 420 GR_GL_CALL(gl, EnableVertexAttribArray(1)); |
| 421 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 5 * sizeo
f(GrGLfloat), (GrGLvoid*)(2 * sizeof(GrGLfloat)))); |
| 422 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_ve
rtices, GR_GL_STATIC_DRAW)); |
| 423 |
| 424 // Also set instance data |
| 425 GrGLuint instanceVBO; |
| 426 GR_GL_CALL(gl, GenBuffers(1, &instanceVBO)); |
| 427 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, instanceVBO)); |
| 428 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(GrGLfloat) * fSkMatrixN
umCells * fNumQuads, |
| 429 &viewMatrices[0], GR_GL_STATIC_DRAW)); |
| 430 GR_GL_CALL(gl, EnableVertexAttribArray(2)); |
| 431 GR_GL_CALL(gl, EnableVertexAttribArray(3)); |
| 432 GR_GL_CALL(gl, EnableVertexAttribArray(4)); |
| 433 GR_GL_CALL(gl, VertexAttribPointer(2, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeo
f(GrGLfloat), (GrGLvoid*)0)); |
| 434 GR_GL_CALL(gl, VertexAttribPointer(3, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeo
f(GrGLfloat), (GrGLvoid*)(3 * sizeof(GrGLfloat)))); |
| 435 GR_GL_CALL(gl, VertexAttribPointer(4, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeo
f(GrGLfloat), (GrGLvoid*)(6 * sizeof(GrGLfloat)))); |
| 436 GR_GL_CALL(gl, VertexAttribDivisor(2, 1)); |
| 437 GR_GL_CALL(gl, VertexAttribDivisor(3, 1)); |
| 438 GR_GL_CALL(gl, VertexAttribDivisor(4, 1)); |
| 439 |
| 440 // draw |
| 441 GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); |
| 442 GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); |
| 443 |
| 444 // set us up to draw |
| 445 GR_GL_CALL(gl, UseProgram(shaderProgram)); |
| 446 GR_GL_CALL(gl, BindVertexArray(quadVAO)); |
| 447 } |
| 448 |
| 449 void GLGpuPosInstancedArraysBench::onDraw(const int loops, SkCanvas* canvas) { |
| 450 const GrGLInterface* gl = get_interface(canvas); |
| 451 if (!gl) { |
| 452 return; |
| 453 } |
| 454 |
| 455 GR_GL_CALL(gl, DrawArraysInstanced(GR_GL_TRIANGLES, 0, 6, fNumQuads)); |
| 456 |
| 457 #ifdef DUMP_IMAGES |
| 458 const char* filename = "out.png"; |
| 459 dump_image(gl, kScreenWidth, kScreenHeight, filename); |
| 460 #endif |
| 461 SkFAIL("done\n"); |
| 462 } |
| 463 |
| 464 static uint32_t setup_quad_index_buffer(const GrGLInterface* gl) { |
| 465 static const int kMaxQuads = 1;//1 << 12; // max possible: (1 << 14) - 1; |
| 466 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535); |
| 467 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 }; |
| 468 static const int kPatternSize = 6; |
| 469 static const int kVertCount = 4; |
| 470 static const int kIndicesCount = kPatternSize * kMaxQuads; |
| 471 int size = kPatternSize * kMaxQuads * sizeof(uint16_t); |
| 472 |
| 473 uint16_t* data = SkNEW_ARRAY(uint16_t, kMaxQuads * kPatternSize); |
| 474 |
| 475 for (int i = 0; i < kMaxQuads; ++i) { |
| 476 int baseIdx = i * kPatternSize; |
| 477 uint16_t baseVert = (uint16_t)(i * kVertCount); |
| 478 for (int j = 0; j < kPatternSize; ++j) { |
| 479 data[baseIdx+j] = baseVert + kPattern[j]; |
| 480 } |
| 481 } |
| 482 |
| 483 GrGLuint quadIBO; |
| 484 GR_GL_CALL(gl, GenBuffers(1, &quadIBO)); |
| 485 GR_GL_CALL(gl, BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, quadIBO)); |
| 486 GR_GL_CALL(gl, BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size, data, GR_GL_STAT
IC_DRAW)); |
| 487 |
| 488 SkDELETE_ARRAY(data); |
| 489 return kIndicesCount; |
| 490 } |
| 491 #endif |
| 492 |
| 493 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 494 |
| 495 void GLCpuPosInstancedArraysBench::setupInstanceVbo(const GrGLInterface* gl, |
| 496 const SkMatrix* viewMatrices
) { |
| 497 // We draw all of the instances at a single place because we aren't allowed
to have per vertex |
| 498 // per instance attributes |
| 499 SkPoint positions[kVerticesPerTri]; |
| 500 positions[0].set(-1.0f, -1.0f); |
| 501 positions[1].set( 1.0f, -1.0f); |
| 502 positions[2].set( 1.0f, 1.0f); |
| 503 viewMatrices[0].mapPointsWithStride(positions, sizeof(SkPoint), kVerticesPer
Tri); |
| 504 |
| 505 // setup colors so we can detect we are actually drawing instances(the last
triangle will be |
| 506 // a different color) |
| 507 GrGLfloat colors[kVerticesPerTri * kNumTri]; |
| 508 for (uint32_t i = 0; i < kNumTri; i++) { |
| 509 // set colors |
| 510 uint32_t offset = i * kVerticesPerTri; |
| 511 float color = i == kNumTri - 1 ? 1.0f : 0.0f; |
| 512 colors[offset++] = color; colors[offset++] = 0.0f; colors[offset++] = 0.
0f; |
| 513 } |
| 514 |
| 515 GrGLuint posVBO; |
| 516 // setup position VBO |
| 517 GR_GL_CALL(gl, GenBuffers(1, &posVBO)); |
| 518 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, posVBO)); |
| 519 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(positions), positions,
GR_GL_STATIC_DRAW)); |
| 520 GR_GL_CALL(gl, EnableVertexAttribArray(0)); |
| 521 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 2 * sizeo
f(GrGLfloat), |
| 522 (GrGLvoid*)0)); |
| 523 |
| 524 // setup color VBO |
| 525 GrGLuint instanceVBO; |
| 526 GR_GL_CALL(gl, GenBuffers(1, &instanceVBO)); |
| 527 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, instanceVBO)); |
| 528 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(colors), colors, GR_GL_
STATIC_DRAW)); |
| 529 GR_GL_CALL(gl, EnableVertexAttribArray(1)); |
| 530 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 3 * sizeo
f(GrGLfloat), |
| 531 (GrGLvoid*)0)); |
| 532 GR_GL_CALL(gl, VertexAttribDivisor(1, 1)); |
| 533 fBuffers.push_back(posVBO); |
| 534 fBuffers.push_back(instanceVBO); |
| 535 } |
| 536 |
| 537 void GLCpuPosInstancedArraysBench::setupDoubleVbo(const GrGLInterface* gl, |
| 538 const SkMatrix* viewMatrices)
{ |
| 539 // Constants for our various shader programs |
| 540 SkPoint positions[kVerticesPerTri * kNumTri]; |
| 541 GrGLfloat colors[kVerticesPerTri * kNumTri * 3]; |
| 542 for (uint32_t i = 0; i < kNumTri; i++) { |
| 543 SkPoint* position = &positions[i * kVerticesPerTri]; |
| 544 position[0].set(-1.0f, -1.0f); |
| 545 position[1].set( 1.0f, -1.0f); |
| 546 position[2].set( 1.0f, 1.0f); |
| 547 viewMatrices[i].mapPointsWithStride(position, sizeof(SkPoint), kVertices
PerTri); |
| 548 |
| 549 // set colors |
| 550 float color = i == kNumTri - 1 ? 1.0f : 0.0f; |
| 551 uint32_t offset = i * kVerticesPerTri * 3; |
| 552 for (uint32_t j = 0; j < kVerticesPerTri; j++) { |
| 553 colors[offset++] = color; colors[offset++] = 0.0f; colors[offset++]
= 0.0f; |
| 554 } |
| 555 } |
| 556 |
| 557 GrGLuint posVBO, colorVBO; |
| 558 // setup position VBO |
| 559 GR_GL_CALL(gl, GenBuffers(1, &posVBO)); |
| 560 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, posVBO)); |
| 561 GR_GL_CALL(gl, EnableVertexAttribArray(0)); |
| 562 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 2 * sizeo
f(GrGLfloat), |
| 563 (GrGLvoid*)0)); |
| 564 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(positions), positions,
GR_GL_STATIC_DRAW)); |
| 565 |
| 566 // setup color VBO |
| 567 GR_GL_CALL(gl, GenBuffers(1, &colorVBO)); |
| 568 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, colorVBO)); |
| 569 GR_GL_CALL(gl, EnableVertexAttribArray(1)); |
| 570 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 3 * sizeo
f(GrGLfloat), |
| 571 (GrGLvoid*)0)); |
| 572 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(colors), colors, GR_GL_
STATIC_DRAW)); |
| 573 |
| 574 fBuffers.push_back(posVBO); |
| 575 fBuffers.push_back(colorVBO); |
| 576 } |
| 577 |
| 578 struct Vertex { |
| 579 SkPoint fPositions; |
| 580 GrGLfloat fColors[3]; |
| 581 }; |
| 582 |
| 583 void GLCpuPosInstancedArraysBench::setupSingleVbo(const GrGLInterface* gl, |
| 584 const SkMatrix* viewMatrices)
{ |
| 585 // Constants for our various shader programs |
| 586 Vertex vertices[kVerticesPerTri * kNumTri]; |
| 587 for (uint32_t i = 0; i < kNumTri; i++) { |
| 588 Vertex* v = &vertices[i * kVerticesPerTri]; |
| 589 v[0].fPositions.set(-1.0f, -1.0f); |
| 590 v[1].fPositions.set( 1.0f, -1.0f); |
| 591 v[2].fPositions.set( 1.0f, 1.0f); |
| 592 |
| 593 SkPoint* position = reinterpret_cast<SkPoint*>(v); |
| 594 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesP
erTri); |
| 595 |
| 596 // set colors |
| 597 float color = i == kNumTri - 1 ? 1.0f : 0.0f; |
| 598 for (uint32_t j = 0; j < kVerticesPerTri; j++) { |
| 599 uint32_t offset = 0; |
| 600 v->fColors[offset++] = color; v->fColors[offset++] = 0.0f; v->fColor
s[offset++] = 0.0f; |
| 601 v++; |
| 602 } |
| 603 } |
| 604 |
| 605 GrGLuint vbo; |
| 606 // setup VBO |
| 607 GR_GL_CALL(gl, GenBuffers(1, &vbo)); |
| 608 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, vbo)); |
| 609 GR_GL_CALL(gl, EnableVertexAttribArray(0)); |
| 610 GR_GL_CALL(gl, EnableVertexAttribArray(1)); |
| 611 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), |
| 612 (GrGLvoid*)0)); |
| 613 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), |
| 614 (GrGLvoid*)(sizeof(SkPoint)))); |
| 615 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR
_GL_STATIC_DRAW)); |
| 616 fBuffers.push_back(vbo); |
| 617 } |
| 618 |
| 619 void GLCpuPosInstancedArraysBench::setup(const GrGLContext* ctx) { |
| 620 const GrGLInterface* gl = ctx->interface(); |
| 621 setup_framebuffer(gl, kScreenWidth, kScreenHeight); |
| 622 |
| 623 fProgram = compile_shader(ctx); |
| 624 |
| 625 // setup matrices |
| 626 int index = 0; |
| 627 SkMatrix viewMatrices[kNumTri]; |
| 628 setup_matrices(kNumTri, [&index, &viewMatrices](const SkMatrix& m) { |
| 629 viewMatrices[index++] = m; |
| 630 }); |
| 631 |
| 632 // setup VAO |
| 633 GR_GL_CALL(gl, GenVertexArrays(1, &fVAO)); |
| 634 GR_GL_CALL(gl, BindVertexArray(fVAO)); |
| 635 |
| 636 switch (fVboSetup) { |
| 637 case kUseOne_VboSetup: |
| 638 this->setupSingleVbo(gl, viewMatrices); |
| 639 break; |
| 640 case kUseTwo_VboSetup: |
| 641 this->setupDoubleVbo(gl, viewMatrices); |
| 642 break; |
| 643 case kUseInstance_VboSetup: |
| 644 this->setupInstanceVbo(gl, viewMatrices); |
| 645 break; |
| 646 } |
| 647 |
| 648 // clear screen |
| 649 GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); |
| 650 GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); |
| 651 |
| 652 // set us up to draw |
| 653 GR_GL_CALL(gl, UseProgram(fProgram)); |
| 654 GR_GL_CALL(gl, BindVertexArray(fVAO)); |
| 655 } |
| 656 |
| 657 void GLCpuPosInstancedArraysBench::onDraw(const int loops, SkCanvas* canvas) { |
| 658 const GrGLContext* ctx = get_gl_context(canvas); |
| 659 if (!ctx) { |
| 660 return; |
| 661 } |
| 662 |
| 663 const GrGLInterface* gl = ctx->interface(); |
| 664 |
| 665 uint32_t maxTrianglesPerFlush = fDrawDiv == 0 ? kNumTri : |
| 666 kDrawMultiplier / fDrawDiv; |
| 667 uint32_t trianglesToDraw = loops * kDrawMultiplier; |
| 668 |
| 669 if (kUseInstance_VboSetup == fVboSetup) { |
| 670 while (trianglesToDraw > 0) { |
| 671 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush); |
| 672 GR_GL_CALL(gl, DrawArraysInstanced(GR_GL_TRIANGLES, 0, kVerticesPerT
ri, triangles)); |
| 673 trianglesToDraw -= triangles; |
| 674 } |
| 675 } else { |
| 676 while (trianglesToDraw > 0) { |
| 677 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush); |
| 678 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * tria
ngles)); |
| 679 trianglesToDraw -= triangles; |
| 680 } |
| 681 } |
| 682 |
| 683 #ifdef DUMP_IMAGES |
| 684 //const char* filename = "/data/local/tmp/out.png"; |
| 685 SkString filename("out"); |
| 686 filename.appendf("_%s.png", this->getName()); |
| 687 dump_image(gl, kScreenWidth, kScreenHeight, filename.c_str()); |
| 688 #endif |
| 689 } |
| 690 |
| 691 void GLCpuPosInstancedArraysBench::teardown(const GrGLInterface* gl) { |
| 692 GR_GL_CALL(gl, DeleteProgram(fProgram)); |
| 693 GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin())); |
| 694 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVAO)); |
| 695 } |
| 696 |
| 697 /////////////////////////////////////////////////////////////////////////////// |
| 698 |
| 699 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseInstance_VboSetup, 0) ) |
| 700 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseOne_VboSetup, 0) ) |
| 701 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseTwo_VboSetup, 0) ) |
| 702 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseOne_VboSetup, 1) ) |
| 703 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseTwo_VboSetup, 1) ) |
| 704 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseOne_VboSetup, 2) ) |
| 705 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseTwo_VboSetup, 2) ) |
| 706 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseOne_VboSetup, 4) ) |
| 707 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseTwo_VboSetup, 4) ) |
| 708 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseOne_VboSetup, 8) ) |
| 709 DEF_BENCH( return new GLCpuPosInstancedArraysBench(GLCpuPosInstancedArraysBench:
:kUseTwo_VboSetup, 8) ) |
| 710 |
| 711 #endif |
OLD | NEW |