Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1988)

Unified Diff: bench/GLVec4ScalarBench.cpp

Issue 1225383002: Added a GLBench for testing performance of vec4 vs scalar for coverage in generated shaders. (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: bench/GLVec4ScalarBench.cpp
diff --git a/bench/GLVec4ScalarBench.cpp b/bench/GLVec4ScalarBench.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ba8855862c92a55d7ed8f6212f47a34bf126c17
--- /dev/null
+++ b/bench/GLVec4ScalarBench.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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.0, 1.0);\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();
+ if (!gl) {
+ SkFAIL("GL interface is null in setup()\n");
+ }
+ 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698