Chromium Code Reviews| 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 determining the cost of uploading vertex at tributes | |
| 22 */ | |
| 23 class GLVertexAttributesBench : public Benchmark { | |
| 24 public: | |
| 25 GLVertexAttributesBench(uint32_t attribs) | |
| 26 : fTexture(0) | |
| 27 , fBuffers(0) | |
| 28 , fProgram(0) | |
| 29 , fVAO(0) | |
| 30 , fVBO(0) | |
| 31 , fAttribs(attribs) | |
| 32 , fStride(2 * sizeof(SkPoint) + fAttribs * sizeof(GrGLfloat) * 4) { | |
| 33 fName.appendf("GLVertexAttributesBench_%d", fAttribs); | |
| 34 } | |
| 35 | |
| 36 protected: | |
| 37 const char* onGetName() override { return fName.c_str(); } | |
| 38 void onPerCanvasPreDraw(SkCanvas* canvas) override; | |
| 39 void setup(const GrGLContext*); | |
| 40 void onDraw(int loops, SkCanvas*) override; | |
| 41 void onPerCanvasPostDraw(SkCanvas* canvas) override; | |
| 42 | |
| 43 static const GrGLuint kScreenWidth = 800; | |
| 44 static const GrGLuint kScreenHeight = 600; | |
| 45 static const uint32_t kNumTri = 10000; | |
| 46 static const uint32_t kVerticesPerTri = 3; | |
| 47 static const uint32_t kDrawMultiplier = 512; | |
| 48 static const uint32_t kMaxAttribs = 7; | |
| 49 | |
| 50 private: | |
| 51 GrGLuint fTexture; | |
| 52 SkTArray<GrGLuint> fBuffers; | |
| 53 GrGLuint fProgram; | |
| 54 GrGLuint fVAO; | |
| 55 GrGLuint fVBO; | |
| 56 SkTArray<unsigned char> fVertices; | |
| 57 uint32_t fAttribs; | |
| 58 size_t fStride; | |
| 59 SkString fName; | |
| 60 typedef Benchmark INHERITED; | |
| 61 }; | |
| 62 | |
| 63 static const GrGLContext* get_gl_context(SkCanvas* canvas) { | |
| 64 // This bench exclusively tests GL calls directly | |
| 65 if (NULL == canvas->getGrContext()) { | |
| 66 return NULL; | |
| 67 } | |
| 68 GrContext* context = canvas->getGrContext(); | |
| 69 | |
| 70 GrTestTarget tt; | |
| 71 context->getTestTarget(&tt); | |
| 72 if (!tt.target()) { | |
| 73 SkDebugf("Couldn't get Gr test target."); | |
| 74 return NULL; | |
| 75 } | |
| 76 | |
| 77 const GrGLContext* ctx = tt.glContext(); | |
| 78 if (!ctx) { | |
| 79 SkDebugf("Couldn't get an interface\n"); | |
| 80 return NULL; | |
| 81 } | |
| 82 | |
| 83 return ctx; | |
| 84 } | |
| 85 | |
| 86 void GLVertexAttributesBench::onPerCanvasPreDraw(SkCanvas* canvas) { | |
| 87 // This bench exclusively tests GL calls directly | |
| 88 const GrGLContext* ctx = get_gl_context(canvas); | |
| 89 if (!ctx) { | |
| 90 return; | |
| 91 } | |
| 92 this->setup(ctx); | |
| 93 } | |
| 94 | |
| 95 void GLVertexAttributesBench::onPerCanvasPostDraw(SkCanvas* canvas) { | |
| 96 // This bench exclusively tests GL calls directly | |
| 97 const GrGLContext* ctx = get_gl_context(canvas); | |
| 98 if (!ctx) { | |
| 99 return; | |
| 100 } | |
| 101 | |
| 102 const GrGLInterface* gl = ctx->interface(); | |
| 103 | |
| 104 // teardown | |
| 105 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); | |
| 106 GR_GL_CALL(gl, BindVertexArray(0)); | |
| 107 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); | |
| 108 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); | |
| 109 GR_GL_CALL(gl, DeleteTextures(1, &fTexture)); | |
| 110 GR_GL_CALL(gl, DeleteProgram(fProgram)); | |
| 111 GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin())); | |
| 112 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVAO)); | |
| 113 } | |
| 114 | |
| 115 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
| 116 | |
| 117 static GrGLuint load_shader(const GrGLInterface* gl, const char* shaderSrc, GrGL enum type) { | |
| 118 GrGLuint shader; | |
| 119 // Create the shader object | |
| 120 GR_GL_CALL_RET(gl, shader, CreateShader(type)); | |
| 121 | |
| 122 // Load the shader source | |
| 123 GR_GL_CALL(gl, ShaderSource(shader, 1, &shaderSrc, NULL)); | |
| 124 | |
| 125 // Compile the shader | |
| 126 GR_GL_CALL(gl, CompileShader(shader)); | |
| 127 | |
| 128 // Check for compile time errors | |
| 129 GrGLint success; | |
| 130 GrGLchar infoLog[512]; | |
| 131 GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &success)); | |
| 132 if (!success) { | |
| 133 GR_GL_CALL(gl, GetShaderInfoLog(shader, 512, NULL, infoLog)); | |
| 134 SkDebugf("ERROR::SHADER::COMPLIATION_FAILED: %s\n", infoLog); | |
| 135 } | |
| 136 | |
| 137 return shader; | |
| 138 } | |
| 139 | |
| 140 static GrGLuint compile_shader(const GrGLContext* ctx, uint32_t attribs) { | |
| 141 const char* version = GrGLGetGLSLVersionDecl(*ctx); | |
| 142 | |
| 143 // setup vertex shader | |
| 144 GrGLShaderVar aPosition("a_position", kVec4f_GrSLType, GrShaderVar::kAttribu te_TypeModifier); | |
| 145 SkTArray<GrGLShaderVar> aVars; | |
| 146 SkTArray<GrGLShaderVar> oVars; | |
| 147 | |
| 148 SkString vshaderTxt(version); | |
| 149 aPosition.appendDecl(*ctx, &vshaderTxt); | |
| 150 vshaderTxt.append(";\n"); | |
| 151 | |
| 152 for (uint32_t i = 0; i < attribs; i++) { | |
| 153 SkString aname; | |
| 154 aname.appendf("a_color_%d", i); | |
| 155 aVars.push_back(GrGLShaderVar(aname.c_str(), | |
| 156 kVec4f_GrSLType, | |
| 157 GrShaderVar::kAttribute_TypeModifier)); | |
| 158 | |
| 159 SkString oname; | |
| 160 oname.appendf("o_color_%d", i); | |
| 161 oVars.push_back(GrGLShaderVar(oname.c_str(), | |
| 162 kVec4f_GrSLType, | |
| 163 GrShaderVar::kVaryingOut_TypeModifier)); | |
| 164 aVars.back().appendDecl(*ctx, &vshaderTxt); | |
| 165 vshaderTxt.append(";\n"); | |
| 166 oVars.back().appendDecl(*ctx, &vshaderTxt); | |
| 167 vshaderTxt.append(";\n"); | |
| 168 | |
| 169 } | |
| 170 | |
| 171 vshaderTxt.append( | |
| 172 "void main()\n" | |
| 173 "{\n" | |
| 174 "gl_Position = a_position;\n"); | |
| 175 | |
| 176 for (uint32_t i = 0; i < attribs; i++) { | |
| 177 vshaderTxt.appendf("%s = %s;\n", oVars[i].c_str(), aVars[i].c_str()); | |
| 178 } | |
| 179 | |
| 180 vshaderTxt.append("}\n"); | |
| 181 | |
| 182 const GrGLInterface* gl = ctx->interface(); | |
| 183 GrGLuint vertexShader = load_shader(gl, vshaderTxt.c_str(), GR_GL_VERTEX_SHA DER); | |
| 184 | |
| 185 // setup fragment shader | |
| 186 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_T ypeModifier); | |
| 187 SkString fshaderTxt(version); | |
| 188 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->f Standard, | |
| 189 &fshaderTxt); | |
| 190 | |
| 191 const char* fsOutName; | |
| 192 if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { | |
| 193 oFragColor.appendDecl(*ctx, &fshaderTxt); | |
| 194 fshaderTxt.append(";\n"); | |
| 195 fsOutName = oFragColor.c_str(); | |
| 196 } else { | |
| 197 fsOutName = "gl_FragColor"; | |
| 198 } | |
| 199 | |
| 200 for (uint32_t i = 0; i < attribs; i++) { | |
| 201 oVars[i].setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); | |
| 202 oVars[i].appendDecl(*ctx, &fshaderTxt); | |
| 203 fshaderTxt.append(";\n"); | |
| 204 } | |
| 205 | |
| 206 fshaderTxt.appendf( | |
| 207 "void main()\n" | |
| 208 "{\n" | |
| 209 "%s = ", fsOutName); | |
| 210 | |
| 211 if (attribs == 0) { | |
| 212 fshaderTxt.append("vec4(0.0f, 0.0f, 0.0f, 1.f)"); | |
| 213 } else { | |
| 214 fshaderTxt.appendf("%s", oVars[0].c_str()); | |
| 215 for (uint32_t i = 1; i < attribs; i++) { | |
| 216 fshaderTxt.appendf(" + %s", oVars[i].c_str()); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 fshaderTxt.append(";\n" | |
| 221 "}\n"); | |
| 222 | |
| 223 GrGLuint fragmentShader = load_shader(gl, fshaderTxt.c_str(), GR_GL_FRAGMENT _SHADER); | |
| 224 | |
| 225 GrGLint shaderProgram; | |
| 226 GR_GL_CALL_RET(gl, shaderProgram, CreateProgram()); | |
| 227 GR_GL_CALL(gl, AttachShader(shaderProgram, vertexShader)); | |
| 228 GR_GL_CALL(gl, AttachShader(shaderProgram, fragmentShader)); | |
| 229 GR_GL_CALL(gl, LinkProgram(shaderProgram)); | |
| 230 | |
| 231 // Check for linking errors | |
| 232 GrGLint success; | |
| 233 GrGLchar infoLog[512]; | |
| 234 GR_GL_CALL(gl, GetProgramiv(shaderProgram, GR_GL_LINK_STATUS, &success)); | |
| 235 if (!success) { | |
| 236 GR_GL_CALL(gl, GetProgramInfoLog(shaderProgram, 512, NULL, infoLog)); | |
| 237 SkDebugf("Linker Error: %s\n", infoLog); | |
| 238 } | |
| 239 GR_GL_CALL(gl, DeleteShader(vertexShader)); | |
| 240 GR_GL_CALL(gl, DeleteShader(fragmentShader)); | |
| 241 | |
| 242 return shaderProgram; | |
| 243 } | |
| 244 | |
| 245 //#define DUMP_IMAGES | |
| 246 #ifdef DUMP_IMAGES | |
| 247 static void dump_image(const GrGLInterface* gl, uint32_t screenWidth, uint32_t s creenHeight, | |
| 248 const char* filename) { | |
| 249 // read back pixels | |
| 250 uint32_t readback[screenWidth * screenHeight]; | |
| 251 GR_GL_CALL(gl, ReadPixels(0, // x | |
| 252 0, // y | |
| 253 screenWidth, // width | |
| 254 screenHeight, // height | |
| 255 GR_GL_RGBA, //format | |
| 256 GR_GL_UNSIGNED_BYTE, //type | |
| 257 readback)); | |
| 258 | |
| 259 // dump png | |
| 260 SkBitmap bm; | |
| 261 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(screenWidth, screenHeight) )) { | |
| 262 SkDebugf("couldn't allocate bitmap\n"); | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 bm.setPixels(readback); | |
| 267 | |
| 268 if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100 )) { | |
| 269 SkDebugf("------ failed to encode %s\n", filename); | |
| 270 remove(filename); // remove any partial file | |
| 271 return; | |
| 272 } | |
| 273 } | |
| 274 #endif | |
| 275 | |
| 276 static void setup_framebuffer(const GrGLInterface* gl, int screenWidth, int scre enHeight) { | |
| 277 //Setup framebuffer | |
| 278 GrGLuint texture; | |
| 279 GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); | |
| 280 GR_GL_CALL(gl, PixelStorei(GR_GL_PACK_ROW_LENGTH, 0)); | |
| 281 GR_GL_CALL(gl, GenTextures(1, &texture)); | |
| 282 GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE15)); | |
| 283 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texture)); | |
| 284 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_ GL_NEAREST)); | |
| 285 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_ GL_NEAREST)); | |
| 286 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_C LAMP_TO_EDGE)); | |
| 287 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_C LAMP_TO_EDGE)); | |
| 288 GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, | |
| 289 0, //level | |
| 290 GR_GL_RGBA8, //internal format | |
| 291 screenWidth, // width | |
| 292 screenHeight, // height | |
| 293 0, //border | |
| 294 GR_GL_RGBA, //format | |
| 295 GR_GL_UNSIGNED_BYTE, // type | |
| 296 NULL)); | |
| 297 | |
| 298 // bind framebuffer | |
| 299 GrGLuint framebuffer; | |
| 300 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); | |
| 301 GR_GL_CALL(gl, GenFramebuffers(1, &framebuffer)); | |
| 302 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, framebuffer)); | |
| 303 GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, | |
| 304 GR_GL_COLOR_ATTACHMENT0, | |
| 305 GR_GL_TEXTURE_2D, | |
| 306 texture, 0)); | |
| 307 GR_GL_CALL(gl, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | |
| 308 GR_GL_CALL(gl, Viewport(0, 0, screenWidth, screenHeight)); | |
| 309 } | |
| 310 | |
| 311 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
| 312 | |
| 313 void GLVertexAttributesBench::setup(const GrGLContext* ctx) { | |
| 314 const GrGLInterface* gl = ctx->interface(); | |
| 315 setup_framebuffer(gl, kScreenWidth, kScreenHeight); | |
| 316 | |
| 317 fProgram = compile_shader(ctx, fAttribs); | |
| 318 | |
| 319 // setup matrices | |
| 320 SkMatrix viewMatrices[kNumTri]; | |
| 321 for (uint32_t i = 0 ; i < kNumTri; i++) { | |
| 322 SkMatrix m = SkMatrix::I(); | |
| 323 m.setScale(0.0001f, 0.0001f); | |
| 324 viewMatrices[i] = m; | |
| 325 } | |
| 326 | |
| 327 // setup VAO | |
| 328 GR_GL_CALL(gl, GenVertexArrays(1, &fVAO)); | |
| 329 GR_GL_CALL(gl, BindVertexArray(fVAO)); | |
| 330 | |
| 331 // presetup vertex attributes, color is set to be a light gray no matter how many vertex | |
| 332 // attributes are used | |
| 333 float targetColor = 0.9f; | |
| 334 float colorContribution = targetColor / fAttribs; | |
| 335 fVertices.reset(kVerticesPerTri * kNumTri * fStride); | |
| 336 for (uint32_t i = 0; i < kNumTri; i++) { | |
| 337 unsigned char* ptr = &fVertices[i * kVerticesPerTri * fStride]; | |
| 338 SkPoint* p = reinterpret_cast<SkPoint*>(ptr); | |
| 339 p->set(-1.0f, -1.0f); p++; p->set( 0.0f, 1.0f); | |
| 340 p = reinterpret_cast<SkPoint*>(ptr + fStride); | |
| 341 p->set( 1.0f, -1.0f); p++; p->set( 0.0f, 1.0f); | |
| 342 p = reinterpret_cast<SkPoint*>(ptr + fStride * 2); | |
| 343 p->set( 1.0f, 1.0f); p++; p->set( 0.0f, 1.0f); | |
| 344 | |
| 345 SkPoint* position = reinterpret_cast<SkPoint*>(ptr); | |
| 346 viewMatrices[i].mapPointsWithStride(position, fStride, kVerticesPerTri); | |
| 347 | |
| 348 // set colors | |
| 349 for (uint32_t j = 0; j < kVerticesPerTri; j++) { | |
| 350 GrGLfloat* f = reinterpret_cast<GrGLfloat*>(ptr + 2 * sizeof(SkPoint ) + fStride * j); | |
| 351 for (uint32_t k = 0; k < fAttribs * 4; k += 4) { | |
| 352 f[k] = colorContribution; | |
| 353 f[k + 1] = colorContribution; | |
| 354 f[k + 2] = colorContribution; | |
| 355 f[k + 3] = 1.0f; | |
| 356 } | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 GR_GL_CALL(gl, GenBuffers(1, &fVBO)); | |
| 361 fBuffers.push_back(fVBO); | |
| 362 | |
| 363 // clear screen | |
| 364 GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); | |
| 365 GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); | |
| 366 | |
| 367 // set us up to draw | |
| 368 GR_GL_CALL(gl, UseProgram(fProgram)); | |
| 369 GR_GL_CALL(gl, BindVertexArray(fVAO)); | |
| 370 } | |
| 371 | |
| 372 void GLVertexAttributesBench::onDraw(const int loops, SkCanvas* canvas) { | |
| 373 const GrGLContext* ctx = get_gl_context(canvas); | |
| 374 if (!ctx) { | |
| 375 return; | |
| 376 } | |
| 377 | |
| 378 const GrGLInterface* gl = ctx->interface(); | |
| 379 | |
| 380 // upload vertex attributes | |
| 381 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVBO)); | |
| 382 GR_GL_CALL(gl, EnableVertexAttribArray(0)); | |
| 383 GR_GL_CALL(gl, VertexAttribPointer(0, 4, GR_GL_FLOAT, GR_GL_FALSE, fStride, | |
| 384 (GrGLvoid*)0)); | |
| 385 | |
| 386 size_t runningStride = 2 * sizeof(SkPoint); | |
| 387 for (uint32_t i = 0; i < fAttribs; i++) { | |
| 388 int attribId = i + 1; | |
| 389 GR_GL_CALL(gl, EnableVertexAttribArray(attribId)); | |
| 390 GR_GL_CALL(gl, VertexAttribPointer(attribId, 4, GR_GL_FLOAT, GR_GL_FALSE , fStride, | |
| 391 (GrGLvoid*)(runningStride))); | |
| 392 runningStride += sizeof(GrGLfloat) * 4; | |
| 393 } | |
| 394 | |
| 395 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, fVertices.count(), fVertices.b egin(), | |
| 396 GR_GL_STATIC_DRAW)); | |
|
bsalomon
2015/06/30 19:37:15
I think we typically use DYNAMIC or STREAM because
| |
| 397 | |
| 398 uint32_t maxTrianglesPerFlush = kNumTri; | |
| 399 uint32_t trianglesToDraw = loops * kDrawMultiplier; | |
| 400 | |
| 401 while (trianglesToDraw > 0) { | |
| 402 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush); | |
| 403 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * triangle s)); | |
| 404 trianglesToDraw -= triangles; | |
| 405 } | |
| 406 | |
| 407 #ifdef DUMP_IMAGES | |
| 408 //const char* filename = "/data/local/tmp/out.png"; | |
| 409 SkString filename("out"); | |
| 410 filename.appendf("_%s.png", this->getName()); | |
| 411 dump_image(gl, kScreenWidth, kScreenHeight, filename.c_str()); | |
| 412 #endif | |
| 413 } | |
| 414 | |
| 415 | |
| 416 /////////////////////////////////////////////////////////////////////////////// | |
| 417 | |
| 418 DEF_BENCH( return new GLVertexAttributesBench(0) ) | |
| 419 DEF_BENCH( return new GLVertexAttributesBench(1) ) | |
| 420 DEF_BENCH( return new GLVertexAttributesBench(2) ) | |
| 421 DEF_BENCH( return new GLVertexAttributesBench(3) ) | |
| 422 DEF_BENCH( return new GLVertexAttributesBench(4) ) | |
| 423 DEF_BENCH( return new GLVertexAttributesBench(5) ) | |
| 424 DEF_BENCH( return new GLVertexAttributesBench(6) ) | |
| 425 DEF_BENCH( return new GLVertexAttributesBench(7) ) | |
| 426 #endif | |
| OLD | NEW |