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