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 */
25 class GLVertexAttributesBench : public GLBench {
26 public:
GLVertexAttributesBench(uint32_t attribs)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:
onGetName()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
setupShader(const GrGLContext * ctx,uint32_t attribs,uint32_t maxAttribs)66 GrGLuint 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(kMedium_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
setup(const GrGLContext * ctx)155 void 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
glDraw(int loops,const GrGLContext * ctx)209 void 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
teardown(const GrGLInterface * gl)247 void 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
260 DEF_BENCH( return new GLVertexAttributesBench(0) )
261 DEF_BENCH( return new GLVertexAttributesBench(1) )
262 DEF_BENCH( return new GLVertexAttributesBench(2) )
263 DEF_BENCH( return new GLVertexAttributesBench(3) )
264 DEF_BENCH( return new GLVertexAttributesBench(4) )
265 DEF_BENCH( return new GLVertexAttributesBench(5) )
266 DEF_BENCH( return new GLVertexAttributesBench(6) )
267 DEF_BENCH( return new GLVertexAttributesBench(7) )
268 #endif
269