diff options
author | wangyix <wangyix@google.com> | 2015-07-13 10:46:34 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-13 10:46:34 -0700 |
commit | 6104ced165f17eb2f765ace354d5895c0bc890c5 (patch) | |
tree | bf39c3b4dfcac9691bf81509f3ee7a7028931300 /bench | |
parent | 24d2a7b463d585f9300ceac946431e822531d504 (diff) |
Added a glBench for testing performance of vec4 vs scalar coverage in generated shaders.
Added bench for timing vec4 vs scalar type for coverage in shaders
BUG=skia:
Review URL: https://codereview.chromium.org/1225383002
Diffstat (limited to 'bench')
-rw-r--r-- | bench/GLVec4ScalarBench.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/bench/GLVec4ScalarBench.cpp b/bench/GLVec4ScalarBench.cpp new file mode 100644 index 0000000000..a0858ceaed --- /dev/null +++ b/bench/GLVec4ScalarBench.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkMatrix.h" +#include "SkPoint.h" +#include "SkString.h" + +#if SK_SUPPORT_GPU +#include "GLBench.h" +#include "gl/GrGLGLSL.h" +#include "gl/GrGLInterface.h" +#include "gl/GrGLShaderVar.h" +#include "gl/GrGLUtil.h" +#include "glsl/GrGLSLCaps.h" + +#include <stdio.h> + +/** + * This is a GL benchmark for comparing the performance of using vec4 or float for coverage in GLSL. + * The generated shader code from this bench will draw several overlapping circles, one in each + * stage, to simulate coverage calculations. The number of circles (i.e. the number of stages) can + * be set as a parameter. + */ + +class GLVec4ScalarBench : public GLBench { +public: + /* + * Use float or vec4 as GLSL data type for the output coverage + */ + enum CoverageSetup { + kUseScalar_CoverageSetup, + kUseVec4_CoverageSetup, + }; + + /* + * numStages determines the number of shader stages before the XP, + * which consequently determines how many circles are drawn + */ + GLVec4ScalarBench(CoverageSetup coverageSetup, uint32_t numStages) + : fCoverageSetup(coverageSetup) + , fNumStages(numStages) + , fVboId(0) + , fProgram(0) + , fVaoId(0) { + fName = NumStagesSetupToStr(coverageSetup, numStages); + } + +protected: + const char* onGetName() override { + return fName.c_str(); + } + + void setup(const GrGLContext*) override; + void glDraw(const int loops, const GrGLContext*) override; + void teardown(const GrGLInterface*) override; + +private: + void setupSingleVbo(const GrGLInterface*, const SkMatrix*); + GrGLuint setupShader(const GrGLContext*); + + + static SkString NumStagesSetupToStr(CoverageSetup coverageSetup, uint32_t numStages) { + SkString name("GLVec4ScalarBench"); + switch (coverageSetup) { + default: + case kUseScalar_CoverageSetup: + name.appendf("_scalar_%u_stage", numStages); + break; + case kUseVec4_CoverageSetup: + name.appendf("_vec4_%u_stage", numStages); + break; + } + return name; + } + + static const GrGLuint kScreenWidth = 800; + static const GrGLuint kScreenHeight = 600; + static const uint32_t kNumTriPerDraw = 512; + static const uint32_t kVerticesPerTri = 3; + + SkString fName; + CoverageSetup fCoverageSetup; + uint32_t fNumStages; + GrGLuint fVboId; + GrGLuint fProgram; + GrGLuint fVaoId; + GrGLuint fFboTextureId; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) { + const char* version = GrGLGetGLSLVersionDecl(*ctx); + + // this shader draws fNumStages overlapping circles of increasing opacity (coverage) and + // decreasing size, with the center of each subsequent circle closer to the bottom-right + // corner of the screen than the previous circle. + + // set up vertex shader; this is a trivial vertex shader that passes through position and color + GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); + GrGLShaderVar oPosition("o_position", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); + GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_TypeModifier); + GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); + + SkString vshaderTxt(version); + aPosition.appendDecl(*ctx, &vshaderTxt); + vshaderTxt.append(";\n"); + aColor.appendDecl(*ctx, &vshaderTxt); + vshaderTxt.append(";\n"); + oPosition.appendDecl(*ctx, &vshaderTxt); + vshaderTxt.append(";\n"); + oColor.appendDecl(*ctx, &vshaderTxt); + vshaderTxt.append(";\n"); + + vshaderTxt.append( + "void main()\n" + "{\n" + " gl_Position = vec4(a_position, 0.f, 1.f);\n" + " o_position = a_position;\n" + " o_color = a_color;\n" + "}\n"); + + const GrGLInterface* gl = ctx->interface(); + + // set up fragment shader; this fragment shader will have fNumStages coverage stages plus an + // XP stage at the end. Each coverage stage computes the pixel's distance from some hard- + // coded center and compare that to some hard-coded circle radius to compute a coverage. + // Then, this coverage is mixed with the coverage from the previous stage and passed to the + // next stage. + GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); + SkString fshaderTxt(version); + GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->fStandard, + &fshaderTxt); + oPosition.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); + oPosition.appendDecl(*ctx, &fshaderTxt); + fshaderTxt.append(";\n"); + oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); + oColor.appendDecl(*ctx, &fshaderTxt); + fshaderTxt.append(";\n"); + + const char* fsOutName; + if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { + oFragColor.appendDecl(*ctx, &fshaderTxt); + fshaderTxt.append(";\n"); + fsOutName = oFragColor.c_str(); + } else { + fsOutName = "gl_FragColor"; + } + + + fshaderTxt.appendf( + "void main()\n" + "{\n" + " vec4 outputColor;\n" + " %s outputCoverage;\n" + " outputColor = vec4(%s, 1.0);\n" + " outputCoverage = %s;\n", + fCoverageSetup == kUseVec4_CoverageSetup ? "vec4" : "float", + oColor.getName().c_str(), + fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(1.0)" : "1.0" + ); + + float radius = 1.0f; + for (uint32_t i = 0; i < fNumStages; i++) { + float centerX = 1.0f - radius; + float centerY = 1.0f - radius; + fshaderTxt.appendf( + " {\n" + " float d = length(%s - vec2(%f, %f));\n" + " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n" + " outputCoverage = 0.5 * outputCoverage + 0.5 * %s;\n" + " }\n", + oPosition.getName().c_str(), centerX, centerY, + radius, + fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(edgeAlpha)" : "edgeAlpha" + ); + radius *= 0.8f; + } + fshaderTxt.appendf( + " {\n" + " %s = outputColor * outputCoverage;\n" + " }\n" + "}\n", + fsOutName); + + return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str()); +} + +template<typename Func> +static void setup_matrices(int numQuads, Func f) { + // We draw a really small triangle so we are not fill rate limited + for (int i = 0 ; i < numQuads; i++) { + SkMatrix m = SkMatrix::I(); + m.setScale(0.01f, 0.01f); + f(m); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Vertex { + SkPoint fPositions; + GrGLfloat fColors[3]; +}; + +void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix* viewMatrices) { + // triangles drawn will alternate between the top-right half of the screen and the bottom-left + // half of the screen + Vertex vertices[kVerticesPerTri * kNumTriPerDraw]; + for (uint32_t i = 0; i < kNumTriPerDraw; i++) { + Vertex* v = &vertices[i * kVerticesPerTri]; + if (i % 2 == 0) { + v[0].fPositions.set(-1.0f, -1.0f); + v[1].fPositions.set( 1.0f, -1.0f); + v[2].fPositions.set( 1.0f, 1.0f); + } else { + v[0].fPositions.set(-1.0f, -1.0f); + v[1].fPositions.set( 1.0f, 1.0f); + v[2].fPositions.set( -1.0f, 1.0f); + } + SkPoint* position = reinterpret_cast<SkPoint*>(v); + viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesPerTri); + + GrGLfloat color[3] = {1.0f, 0.0f, 1.0f}; + for (uint32_t j = 0; j < kVerticesPerTri; j++) { + v->fColors[0] = color[0]; + v->fColors[1] = color[1]; + v->fColors[2] = color[2]; + v++; + } + } + + GR_GL_CALL(gl, GenBuffers(1, &fVboId)); + GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId)); + GR_GL_CALL(gl, EnableVertexAttribArray(0)); + GR_GL_CALL(gl, EnableVertexAttribArray(1)); + GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex), + (GrGLvoid*)0)); + GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex), + (GrGLvoid*)(sizeof(SkPoint)))); + GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR_GL_STATIC_DRAW)); +} + +void GLVec4ScalarBench::setup(const GrGLContext* ctx) { + const GrGLInterface* gl = ctx->interface(); + fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); + + fProgram = this->setupShader(ctx); + + GR_GL_CALL(gl, GenVertexArrays(1, &fVaoId)); + GR_GL_CALL(gl, BindVertexArray(fVaoId)); + + int index = 0; + SkMatrix viewMatrices[kNumTriPerDraw]; + setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { + viewMatrices[index++] = m; + }); + this->setupSingleVbo(gl, viewMatrices); + + GR_GL_CALL(gl, UseProgram(fProgram)); + GR_GL_CALL(gl, BindVertexArray(fVaoId)); +} + +void GLVec4ScalarBench::glDraw(const int loops, const GrGLContext* ctx) { + const GrGLInterface* gl = ctx->interface(); + + for (int i = 0; i < loops; i++) { + GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriPerDraw)); + } + +// using -w when running nanobench will not produce correct images; +// changing this to #if 1 will write the correct images to the Skia folder. +#if 0 + SkString filename("out"); + filename.appendf("_%s.png", this->getName()); + DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); +#endif +} + +void GLVec4ScalarBench::teardown(const GrGLInterface* gl) { + GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); + GR_GL_CALL(gl, BindVertexArray(0)); + GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); + GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); + GR_GL_CALL(gl, DeleteTextures(1, &fFboTextureId)); + GR_GL_CALL(gl, DeleteProgram(fProgram)); + GR_GL_CALL(gl, DeleteBuffers(1, &fVboId)); + GR_GL_CALL(gl, DeleteVertexArrays(1, &fVaoId)); +} + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 1) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 1) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 2) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 2) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 4) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 4) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 6) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 6) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 8) ) +DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 8) ) + +#endif |