GLVertexAttributesBench.cpp revision 0d3f061262a53b775f0a92b0abf8a4a846290d65
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/GrGLGLSL.h"
16#include "gl/GrGLInterface.h"
17#include "gl/GrGLUtil.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 */
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 char* version = GrGLGetGLSLVersionDecl(*ctx);
69
70    // setup vertex shader
71    GrGLSLShaderVar aPosition("a_position", kVec4f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
72    SkTArray<GrGLSLShaderVar> aVars;
73    SkTArray<GrGLSLShaderVar> oVars;
74
75    SkString vshaderTxt(version);
76    aPosition.appendDecl(ctx->caps()->glslCaps(), &vshaderTxt);
77    vshaderTxt.append(";\n");
78
79    for (uint32_t i = 0; i < attribs; i++) {
80        SkString aname;
81        aname.appendf("a_color_%d", i);
82        aVars.push_back(GrGLSLShaderVar(aname.c_str(),
83                                      kVec4f_GrSLType,
84                                      GrShaderVar::kAttribute_TypeModifier));
85        aVars.back().appendDecl(ctx->caps()->glslCaps(), &vshaderTxt);
86        vshaderTxt.append(";\n");
87
88    }
89
90    for (uint32_t i = 0; i < maxAttribs; i++) {
91        SkString oname;
92        oname.appendf("o_color_%d", i);
93        oVars.push_back(GrGLSLShaderVar(oname.c_str(),
94                                      kVec4f_GrSLType,
95                                      GrShaderVar::kVaryingOut_TypeModifier));
96        oVars.back().appendDecl(ctx->caps()->glslCaps(), &vshaderTxt);
97        vshaderTxt.append(";\n");
98    }
99
100    vshaderTxt.append(
101            "void main()\n"
102            "{\n"
103                "gl_Position = a_position;\n");
104
105    for (uint32_t i = 0; i < attribs; i++) {
106        vshaderTxt.appendf("%s = %s;\n", oVars[i].c_str(), aVars[i].c_str());
107    }
108
109    // Passthrough position as a dummy
110    for (uint32_t i = attribs; i < maxAttribs; i++) {
111        vshaderTxt.appendf("%s = vec4(0, 0, 0, 1);\n", oVars[i].c_str());
112    }
113
114    vshaderTxt.append("}\n");
115
116    const GrGLInterface* gl = ctx->interface();
117
118    // setup fragment shader
119    GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
120    SkString fshaderTxt(version);
121    GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->fStandard,
122                                                   &fshaderTxt);
123
124    const char* fsOutName;
125    if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) {
126        oFragColor.appendDecl(ctx->caps()->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(ctx->caps()->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
157void 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
211void 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
249void 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
262DEF_BENCH( return new GLVertexAttributesBench(0) )
263DEF_BENCH( return new GLVertexAttributesBench(1) )
264DEF_BENCH( return new GLVertexAttributesBench(2) )
265DEF_BENCH( return new GLVertexAttributesBench(3) )
266DEF_BENCH( return new GLVertexAttributesBench(4) )
267DEF_BENCH( return new GLVertexAttributesBench(5) )
268DEF_BENCH( return new GLVertexAttributesBench(6) )
269DEF_BENCH( return new GLVertexAttributesBench(7) )
270#endif
271