Index: bench/GLVec4ScalarBench.cpp |
diff --git a/bench/GLVec4ScalarBench.cpp b/bench/GLVec4ScalarBench.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..314bce3571e20ed0cd7b8829e3dfac6cc3b91af1 |
--- /dev/null |
+++ b/bench/GLVec4ScalarBench.cpp |
@@ -0,0 +1,339 @@ |
+/* |
+ * 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 "Benchmark.h" |
+#include "SkCanvas.h" |
+#include "SkImageEncoder.h" |
tomhudson
2015/07/10 19:23:54
You don't seem to need any of these 3 includes any
wangyix
2015/07/13 17:29:52
Done.
|
+ |
+#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> |
+ |
+/* |
tomhudson
2015/07/10 19:23:54
Please make this /** so doxygen can pick it up.
Al
wangyix
2015/07/13 17:29:53
Done.
|
+ * This is a native GL benchmark for instanced arrays vs vertex buffer objects. To benchmark this |
+ * functionality, we draw n * kDrawMultipier triangles per run. If this number is less than |
+ * kNumTri then we do a single draw, either with instances, or drawArrays. Otherwise we do |
+ * multiple draws. |
+ * |
+ * Additionally, there is a divisor, which if > 0 will act as a multiplier for the number of draws |
+ * issued. |
+ */ |
+ |
+class GLVec4ScalarBench : public GLBench { |
+public: |
+ /* |
+ * Use float or vec4 as GLSL data type for the output coverage |
+ */ |
+ enum CoverageSetup { |
+ kUseScalar_CoverageSetup, |
+ kUseVec4_CoverageSetup, |
+ }; |
+ |
+ /* |
+ * drawDiv will act as a multiplier for the number of draws we issue if > 0. ie, 2 will issue |
+ * 2x as many draws, 4 will issue 4x as many draws etc. There is a limit however, which is |
+ * kDrawMultipier. |
tomhudson
2015/07/10 19:23:54
Outdated comment; cut.
If the class comment is goo
wangyix
2015/07/13 17:29:52
Done.
|
+ */ |
+ GLVec4ScalarBench(CoverageSetup coverageSetup, uint32_t numStages) |
+ : fCoverageSetup(coverageSetup) |
+ , fNumStages(numStages) |
+ , fProgram(0) |
+ , fVAO(0) { |
tomhudson
2015/07/10 19:23:55
Why explicitly clear fVAO but not fVBO?
wangyix
2015/07/13 17:29:53
Done.
|
+ fName = CoverageSetupToStr(coverageSetup, numStages); |
+ } |
+ |
+protected: |
+ const char* onGetName() override { |
+ return fName.c_str(); |
+ } |
+ |
+ const GrGLContext* onGetGLContext(const GrGLContext*) override; |
tomhudson
2015/07/13 16:00:13
Once we've started reviewing, it's good for the re
wangyix
2015/07/13 17:29:52
Yep that was the reason. The override was specific
|
+ 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*, bool useVec4ForCoverage); |
+ |
+ |
+ static SkString CoverageSetupToStr(CoverageSetup vboSetup, uint32_t numStages) { |
tomhudson
2015/07/10 19:23:55
Consider tweaking the function name, since you're
wangyix
2015/07/13 17:29:52
Done.
|
+ SkString name("GLVec4ScalarBench"); |
+ switch (vboSetup) { |
+ 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 fVBO; |
tomhudson
2015/07/10 19:23:54
Consider writing out name instead of using abbrevi
wangyix
2015/07/13 17:29:52
Vao and Vbo are extremely common occurrences in Op
|
+ GrGLuint fProgram; |
+ GrGLuint fVAO; |
tomhudson
2015/07/10 19:23:55
... particularly when two abbreviations are very c
wangyix
2015/07/13 17:29:52
Done.
|
+ GrGLuint fTexture; |
tomhudson
2015/07/10 19:23:55
It makes the name a bit long, but you might want t
wangyix
2015/07/13 17:29:52
Done.
|
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx, bool useVec4ForCoverage) { |
tomhudson
2015/07/10 19:23:55
Instead of passing the bool here, pass the enum! T
wangyix
2015/07/13 17:29:52
Done.
|
+ const char* version = GrGLGetGLSLVersionDecl(*ctx); |
+ |
+ // setup vertex shader |
tomhudson
2015/07/10 19:23:54
I'd like to see a "// This shader draws 4 overlapp
wangyix
2015/07/13 17:29:53
Done.
|
+ 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(); |
+ |
+ // setup fragment shader |
+ 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"; |
+ } |
+ |
+ if (useVec4ForCoverage) { |
+ fshaderTxt.appendf( |
+ "void main()\n" |
+ "{\n" |
+ " vec4 outputColor;\n" |
+ " vec4 outputCoverage;\n" |
+ " outputColor = vec4(%s, 1.0);\n" |
+ " outputCoverage = vec4(1.0);\n", |
+ oColor.getName().c_str()); |
+ } else { |
+ fshaderTxt.appendf( |
+ "void main()\n" |
+ "{\n" |
+ " vec4 outputColor;\n" |
+ " float outputCoverage;\n" |
+ " outputColor = vec4(%s, 1.0);\n" |
+ " outputCoverage = 1.0;\n", |
+ oColor.getName().c_str()); |
+ } |
+ float radius = 1.0f; |
+ for (uint32_t i = 0; i < fNumStages; i++) { |
tomhudson
2015/07/10 19:23:54
Why pass in fConverageSetup (or a bool derived fro
wangyix
2015/07/13 17:29:52
Done.
|
+ float centerX = 1.0f - radius; |
+ float centerY = 1.0f - radius; |
+ if (useVec4ForCoverage) { |
+ 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 * vec4(edgeAlpha);\n" |
+ " }\n", |
+ oPosition.getName().c_str(), |
+ centerX, centerY, |
+ radius |
+ ); |
+ } else { |
+ 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 * edgeAlpha;\n" |
+ " }\n", |
+ oPosition.getName().c_str(), |
+ centerX, centerY, |
+ radius |
+ ); |
+ } |
+ radius *= 0.8f; |
+ } |
+ fshaderTxt.appendf( |
+ " {\n" |
+ " %s = outputColor * outputCoverage;\n" |
+ " }\n" |
+ "}\n", |
+ fsOutName); |
+ |
+//printf("\n%s\n", fshaderTxt.c_str()); |
tomhudson
2015/07/10 19:23:55
Remove commented-out code.
wangyix
2015/07/13 17:29:53
Done.
|
+ |
+ 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); |
+ } |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+const GrGLContext* GLVec4ScalarBench::onGetGLContext(const GrGLContext* ctx) { |
+ // We only care about gpus with drawArraysInstanced support |
+ if (!ctx->interface()->fFunctions.fDrawArraysInstanced) { |
+ return NULL; |
+ } |
+ return ctx; |
+} |
+ |
+struct Vertex { |
+ SkPoint fPositions; |
+ GrGLfloat fColors[3]; |
+}; |
+ |
+void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, |
+ const SkMatrix* viewMatrices) { |
tomhudson
2015/07/10 19:23:54
Nit: fix indentation
wangyix
2015/07/13 17:29:53
Done.
|
+ // Constants for our various shader programs |
tomhudson
2015/07/10 19:23:55
This comment is not very high-value. Omit?
wangyix
2015/07/13 17:29:52
Done.
|
+ 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); |
+ |
+ // set colors |
tomhudson
2015/07/10 19:23:55
Bad evil comment. Expurgate!
wangyix
2015/07/13 17:29:53
Done.
|
+ 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++; |
+ } |
+ } |
+ |
+ // setup VBO |
tomhudson
2015/07/10 19:23:54
Low-value comment. What is it? Or why are we doing
wangyix
2015/07/13 17:29:53
Done.
|
+ GR_GL_CALL(gl, GenBuffers(1, &fVBO)); |
+ GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVBO)); |
+ 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(); |
+ fTexture = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); |
+ |
+ fProgram = this->setupShader(ctx, fCoverageSetup == kUseVec4_CoverageSetup); |
+ |
+ // setup matrices |
tomhudson
2015/07/10 19:23:55
Useless comment.
What matrices? Why? Or eliminate!
wangyix
2015/07/13 17:29:52
Done.
|
+ int index = 0; |
+ SkMatrix viewMatrices[kNumTriPerDraw]; |
+ setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { |
+ viewMatrices[index++] = m; |
+ }); |
+ |
+ // setup VAO |
+ GR_GL_CALL(gl, GenVertexArrays(1, &fVAO)); |
+ GR_GL_CALL(gl, BindVertexArray(fVAO)); |
+ |
+ this->setupSingleVbo(gl, viewMatrices); |
+ |
+ // set us up to draw |
+ GR_GL_CALL(gl, UseProgram(fProgram)); |
+ GR_GL_CALL(gl, BindVertexArray(fVAO)); |
+} |
+ |
+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)); |
+ } |
+ |
+ |
+#if 0 |
+ //const char* filename = "/data/local/tmp/out.png"; |
tomhudson
2015/07/10 19:23:55
Delete commented-out code.
In theory you could pro
tomhudson
2015/07/13 16:00:13
Again: How is your #0 different than the command-l
wangyix
2015/07/13 17:29:53
Using -w when running nanobench does not write out
|
+ 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, &fTexture)); |
+ GR_GL_CALL(gl, DeleteProgram(fProgram)); |
+ GR_GL_CALL(gl, DeleteBuffers(1, &fVBO)); |
+ GR_GL_CALL(gl, DeleteVertexArrays(1, &fVAO)); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+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 |