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 12 #if SK_SUPPORT_GPU 13 #include "GLBench.h" 14 #include "gl/GrGLContext.h" 15 #include "gl/GrGLInterface.h" 16 #include "gl/GrGLUtil.h" 17 #include "glsl/GrGLSL.h" 18 #include "glsl/GrGLSLCaps.h" 19 #include "glsl/GrGLSLShaderVar.h" 20 #include <stdio.h> 21 22 /* 23 * This is a native GL benchmark for determining the cost of uploading vertex attributes 24 */ 25 class GLVertexAttributesBench : public GLBench { 26 public: 27 GLVertexAttributesBench(uint32_t attribs) 28 : fTexture(0) 29 , fBuffers(0) 30 , fProgram(0) 31 , fVBO(0) 32 , fAttribs(attribs) 33 , fStride(2 * sizeof(SkPoint) + fAttribs * sizeof(GrGLfloat) * 4) { 34 fName.appendf("GLVertexAttributesBench_%d", fAttribs); 35 } 36 37 protected: 38 const char* onGetName() override { return fName.c_str(); } 39 void setup(const GrGLContext*) override; 40 void glDraw(int loops, const GrGLContext*) override; 41 void teardown(const GrGLInterface*) 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 setupShader(const GrGLContext*, uint32_t attribs, uint32_t maxAttribs); 52 53 GrGLuint fTexture; 54 SkTArray<GrGLuint> fBuffers; 55 GrGLuint fProgram; 56 GrGLuint fVBO; 57 SkTArray<unsigned char> fVertices; 58 uint32_t fAttribs; 59 size_t fStride; 60 SkString fName; 61 typedef Benchmark INHERITED; 62 }; 63 64 /////////////////////////////////////////////////////////////////////////////////////////////////// 65 66 GrGLuint GLVertexAttributesBench::setupShader(const GrGLContext* ctx, uint32_t attribs, 67 uint32_t maxAttribs) { 68 const GrGLSLCaps* glslCaps = ctx->caps()->glslCaps(); 69 const char* version = glslCaps->versionDeclString(); 70 71 // setup vertex shader 72 GrGLSLShaderVar aPosition("a_position", kVec4f_GrSLType, GrShaderVar::kAttribute_TypeModifier); 73 SkTArray<GrGLSLShaderVar> aVars; 74 SkTArray<GrGLSLShaderVar> oVars; 75 76 SkString vshaderTxt(version); 77 aPosition.appendDecl(glslCaps, &vshaderTxt); 78 vshaderTxt.append(";\n"); 79 80 for (uint32_t i = 0; i < attribs; i++) { 81 SkString aname; 82 aname.appendf("a_color_%d", i); 83 aVars.push_back(GrGLSLShaderVar(aname.c_str(), 84 kVec4f_GrSLType, 85 GrShaderVar::kAttribute_TypeModifier)); 86 aVars.back().appendDecl(glslCaps, &vshaderTxt); 87 vshaderTxt.append(";\n"); 88 89 } 90 91 for (uint32_t i = 0; i < maxAttribs; i++) { 92 SkString oname; 93 oname.appendf("o_color_%d", i); 94 oVars.push_back(GrGLSLShaderVar(oname.c_str(), 95 kVec4f_GrSLType, 96 GrShaderVar::kVaryingOut_TypeModifier)); 97 oVars.back().appendDecl(glslCaps, &vshaderTxt); 98 vshaderTxt.append(";\n"); 99 } 100 101 vshaderTxt.append( 102 "void main()\n" 103 "{\n" 104 "gl_Position = a_position;\n"); 105 106 for (uint32_t i = 0; i < attribs; i++) { 107 vshaderTxt.appendf("%s = %s;\n", oVars[i].c_str(), aVars[i].c_str()); 108 } 109 110 // Passthrough position as a dummy 111 for (uint32_t i = attribs; i < maxAttribs; i++) { 112 vshaderTxt.appendf("%s = vec4(0, 0, 0, 1);\n", oVars[i].c_str()); 113 } 114 115 vshaderTxt.append("}\n"); 116 117 const GrGLInterface* gl = ctx->interface(); 118 119 // setup fragment shader 120 GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); 121 SkString fshaderTxt(version); 122 GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, &fshaderTxt); 123 124 const char* fsOutName; 125 if (glslCaps->mustDeclareFragmentShaderOutput()) { 126 oFragColor.appendDecl(glslCaps, &fshaderTxt); 127 fshaderTxt.append(";\n"); 128 fsOutName = oFragColor.c_str(); 129 } else { 130 fsOutName = "gl_FragColor"; 131 } 132 133 for (uint32_t i = 0; i < maxAttribs; i++) { 134 oVars[i].setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); 135 oVars[i].appendDecl(glslCaps, &fshaderTxt); 136 fshaderTxt.append(";\n"); 137 } 138 139 fshaderTxt.appendf( 140 "void main()\n" 141 "{\n" 142 "%s = ", fsOutName); 143 144 fshaderTxt.appendf("%s", oVars[0].c_str()); 145 for (uint32_t i = 1; i < maxAttribs; i++) { 146 fshaderTxt.appendf(" + %s", oVars[i].c_str()); 147 } 148 149 fshaderTxt.append(";\n" 150 "}\n"); 151 152 return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str()); 153 } 154 155 /////////////////////////////////////////////////////////////////////////////////////////////////// 156 157 void GLVertexAttributesBench::setup(const GrGLContext* ctx) { 158 const GrGLInterface* gl = ctx->interface(); 159 fTexture = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); 160 161 fProgram = setupShader(ctx, fAttribs, kMaxAttribs); 162 163 // setup matrices 164 SkMatrix viewMatrices[kNumTri]; 165 for (uint32_t i = 0 ; i < kNumTri; i++) { 166 SkMatrix m = SkMatrix::I(); 167 m.setScale(0.0001f, 0.0001f); 168 viewMatrices[i] = m; 169 } 170 171 // presetup vertex attributes, color is set to be a light gray no matter how many vertex 172 // attributes are used 173 float targetColor = 0.9f; 174 float colorContribution = targetColor / fAttribs; 175 fVertices.reset(static_cast<int>(kVerticesPerTri * kNumTri * fStride)); 176 for (uint32_t i = 0; i < kNumTri; i++) { 177 unsigned char* ptr = &fVertices[static_cast<int>(i * kVerticesPerTri * fStride)]; 178 SkPoint* p = reinterpret_cast<SkPoint*>(ptr); 179 p->set(-1.0f, -1.0f); p++; p->set( 0.0f, 1.0f); 180 p = reinterpret_cast<SkPoint*>(ptr + fStride); 181 p->set( 1.0f, -1.0f); p++; p->set( 0.0f, 1.0f); 182 p = reinterpret_cast<SkPoint*>(ptr + fStride * 2); 183 p->set( 1.0f, 1.0f); p++; p->set( 0.0f, 1.0f); 184 185 SkPoint* position = reinterpret_cast<SkPoint*>(ptr); 186 viewMatrices[i].mapPointsWithStride(position, fStride, kVerticesPerTri); 187 188 // set colors 189 for (uint32_t j = 0; j < kVerticesPerTri; j++) { 190 GrGLfloat* f = reinterpret_cast<GrGLfloat*>(ptr + 2 * sizeof(SkPoint) + fStride * j); 191 for (uint32_t k = 0; k < fAttribs * 4; k += 4) { 192 f[k] = colorContribution; 193 f[k + 1] = colorContribution; 194 f[k + 2] = colorContribution; 195 f[k + 3] = 1.0f; 196 } 197 } 198 } 199 200 GR_GL_CALL(gl, GenBuffers(1, &fVBO)); 201 fBuffers.push_back(fVBO); 202 203 // clear screen 204 GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); 205 GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); 206 207 // set us up to draw 208 GR_GL_CALL(gl, UseProgram(fProgram)); 209 } 210 211 void GLVertexAttributesBench::glDraw(int loops, const GrGLContext* ctx) { 212 const GrGLInterface* gl = ctx->interface(); 213 214 // upload vertex attributes 215 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVBO)); 216 GR_GL_CALL(gl, EnableVertexAttribArray(0)); 217 GR_GL_CALL(gl, VertexAttribPointer(0, 4, GR_GL_FLOAT, GR_GL_FALSE, (GrGLsizei)fStride, 218 (GrGLvoid*)0)); 219 220 size_t runningStride = 2 * sizeof(SkPoint); 221 for (uint32_t i = 0; i < fAttribs; i++) { 222 int attribId = i + 1; 223 GR_GL_CALL(gl, EnableVertexAttribArray(attribId)); 224 GR_GL_CALL(gl, VertexAttribPointer(attribId, 4, GR_GL_FLOAT, GR_GL_FALSE, 225 (GrGLsizei)fStride, (GrGLvoid*)(runningStride))); 226 runningStride += sizeof(GrGLfloat) * 4; 227 } 228 229 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, fVertices.count(), fVertices.begin(), 230 GR_GL_STREAM_DRAW)); 231 232 uint32_t maxTrianglesPerFlush = kNumTri; 233 uint32_t trianglesToDraw = loops * kDrawMultiplier; 234 235 while (trianglesToDraw > 0) { 236 uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush); 237 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * triangles)); 238 trianglesToDraw -= triangles; 239 } 240 241 #if 0 242 //const char* filename = "/data/local/tmp/out.png"; 243 SkString filename("out"); 244 filename.appendf("_%s.png", this->getName()); 245 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); 246 #endif 247 } 248 249 void GLVertexAttributesBench::teardown(const GrGLInterface* gl) { 250 // teardown 251 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); 252 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); 253 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); 254 GR_GL_CALL(gl, DeleteTextures(1, &fTexture)); 255 GR_GL_CALL(gl, DeleteProgram(fProgram)); 256 GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin())); 257 fBuffers.reset(); 258 } 259 260 /////////////////////////////////////////////////////////////////////////////// 261 262 DEF_BENCH( return new GLVertexAttributesBench(0) ) 263 DEF_BENCH( return new GLVertexAttributesBench(1) ) 264 DEF_BENCH( return new GLVertexAttributesBench(2) ) 265 DEF_BENCH( return new GLVertexAttributesBench(3) ) 266 DEF_BENCH( return new GLVertexAttributesBench(4) ) 267 DEF_BENCH( return new GLVertexAttributesBench(5) ) 268 DEF_BENCH( return new GLVertexAttributesBench(6) ) 269 DEF_BENCH( return new GLVertexAttributesBench(7) ) 270 #endif 271