OLD | NEW |
(Empty) | |
| 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 "SkMatrix.h" |
| 9 #include "SkPoint.h" |
| 10 #include "SkString.h" |
| 11 |
| 12 #if SK_SUPPORT_GPU |
| 13 #include "GLBench.h" |
| 14 #include "gl/GrGLGLSL.h" |
| 15 #include "gl/GrGLInterface.h" |
| 16 #include "gl/GrGLShaderVar.h" |
| 17 #include "gl/GrGLUtil.h" |
| 18 #include "glsl/GrGLSLCaps.h" |
| 19 |
| 20 #include <stdio.h> |
| 21 |
| 22 /** |
| 23 * This is a GL benchmark for comparing the performance of using vec4 or float f
or coverage in GLSL. |
| 24 * The generated shader code from this bench will draw several overlapping circl
es, one in each |
| 25 * stage, to simulate coverage calculations. The number of circles (i.e. the nu
mber of stages) can |
| 26 * be set as a parameter. |
| 27 */ |
| 28 |
| 29 class GLVec4ScalarBench : public GLBench { |
| 30 public: |
| 31 /* |
| 32 * Use float or vec4 as GLSL data type for the output coverage |
| 33 */ |
| 34 enum CoverageSetup { |
| 35 kUseScalar_CoverageSetup, |
| 36 kUseVec4_CoverageSetup, |
| 37 }; |
| 38 |
| 39 /* |
| 40 * numStages determines the number of shader stages before the XP, |
| 41 * which consequently determines how many circles are drawn |
| 42 */ |
| 43 GLVec4ScalarBench(CoverageSetup coverageSetup, uint32_t numStages) |
| 44 : fCoverageSetup(coverageSetup) |
| 45 , fNumStages(numStages) |
| 46 , fVboId(0) |
| 47 , fProgram(0) |
| 48 , fVaoId(0) { |
| 49 fName = NumStagesSetupToStr(coverageSetup, numStages); |
| 50 } |
| 51 |
| 52 protected: |
| 53 const char* onGetName() override { |
| 54 return fName.c_str(); |
| 55 } |
| 56 |
| 57 void setup(const GrGLContext*) override; |
| 58 void glDraw(const int loops, const GrGLContext*) override; |
| 59 void teardown(const GrGLInterface*) override; |
| 60 |
| 61 private: |
| 62 void setupSingleVbo(const GrGLInterface*, const SkMatrix*); |
| 63 GrGLuint setupShader(const GrGLContext*); |
| 64 |
| 65 |
| 66 static SkString NumStagesSetupToStr(CoverageSetup coverageSetup, uint32_t nu
mStages) { |
| 67 SkString name("GLVec4ScalarBench"); |
| 68 switch (coverageSetup) { |
| 69 default: |
| 70 case kUseScalar_CoverageSetup: |
| 71 name.appendf("_scalar_%u_stage", numStages); |
| 72 break; |
| 73 case kUseVec4_CoverageSetup: |
| 74 name.appendf("_vec4_%u_stage", numStages); |
| 75 break; |
| 76 } |
| 77 return name; |
| 78 } |
| 79 |
| 80 static const GrGLuint kScreenWidth = 800; |
| 81 static const GrGLuint kScreenHeight = 600; |
| 82 static const uint32_t kNumTriPerDraw = 512; |
| 83 static const uint32_t kVerticesPerTri = 3; |
| 84 |
| 85 SkString fName; |
| 86 CoverageSetup fCoverageSetup; |
| 87 uint32_t fNumStages; |
| 88 GrGLuint fVboId; |
| 89 GrGLuint fProgram; |
| 90 GrGLuint fVaoId; |
| 91 GrGLuint fFboTextureId; |
| 92 }; |
| 93 |
| 94 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 95 |
| 96 GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) { |
| 97 const char* version = GrGLGetGLSLVersionDecl(*ctx); |
| 98 |
| 99 // this shader draws fNumStages overlapping circles of increasing opacity (c
overage) and |
| 100 // decreasing size, with the center of each subsequent circle closer to the
bottom-right |
| 101 // corner of the screen than the previous circle. |
| 102 |
| 103 // set up vertex shader; this is a trivial vertex shader that passes through
position and color |
| 104 GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribu
te_TypeModifier); |
| 105 GrGLShaderVar oPosition("o_position", kVec2f_GrSLType, GrShaderVar::kVarying
Out_TypeModifier); |
| 106 GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_Typ
eModifier); |
| 107 GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_Ty
peModifier); |
| 108 |
| 109 SkString vshaderTxt(version); |
| 110 aPosition.appendDecl(*ctx, &vshaderTxt); |
| 111 vshaderTxt.append(";\n"); |
| 112 aColor.appendDecl(*ctx, &vshaderTxt); |
| 113 vshaderTxt.append(";\n"); |
| 114 oPosition.appendDecl(*ctx, &vshaderTxt); |
| 115 vshaderTxt.append(";\n"); |
| 116 oColor.appendDecl(*ctx, &vshaderTxt); |
| 117 vshaderTxt.append(";\n"); |
| 118 |
| 119 vshaderTxt.append( |
| 120 "void main()\n" |
| 121 "{\n" |
| 122 " gl_Position = vec4(a_position, 0.0, 1.0);\n" |
| 123 " o_position = a_position;\n" |
| 124 " o_color = a_color;\n" |
| 125 "}\n"); |
| 126 |
| 127 const GrGLInterface* gl = ctx->interface(); |
| 128 |
| 129 // set up fragment shader; this fragment shader will have fNumStages coverag
e stages plus an |
| 130 // XP stage at the end. Each coverage stage computes the pixel's distance f
rom some hard- |
| 131 // coded center and compare that to some hard-coded circle radius to compute
a coverage. |
| 132 // Then, this coverage is mixed with the coverage from the previous stage an
d passed to the |
| 133 // next stage. |
| 134 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_T
ypeModifier); |
| 135 SkString fshaderTxt(version); |
| 136 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->f
Standard, |
| 137 &fshaderTxt); |
| 138 oPosition.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); |
| 139 oPosition.appendDecl(*ctx, &fshaderTxt); |
| 140 fshaderTxt.append(";\n"); |
| 141 oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); |
| 142 oColor.appendDecl(*ctx, &fshaderTxt); |
| 143 fshaderTxt.append(";\n"); |
| 144 |
| 145 const char* fsOutName; |
| 146 if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { |
| 147 oFragColor.appendDecl(*ctx, &fshaderTxt); |
| 148 fshaderTxt.append(";\n"); |
| 149 fsOutName = oFragColor.c_str(); |
| 150 } else { |
| 151 fsOutName = "gl_FragColor"; |
| 152 } |
| 153 |
| 154 |
| 155 fshaderTxt.appendf( |
| 156 "void main()\n" |
| 157 "{\n" |
| 158 " vec4 outputColor;\n" |
| 159 " %s outputCoverage;\n" |
| 160 " outputColor = vec4(%s, 1.0);\n" |
| 161 " outputCoverage = %s;\n", |
| 162 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4" : "float", |
| 163 oColor.getName().c_str(), |
| 164 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(1.0)" : "1.0" |
| 165 ); |
| 166 |
| 167 float radius = 1.0f; |
| 168 for (uint32_t i = 0; i < fNumStages; i++) { |
| 169 float centerX = 1.0f - radius; |
| 170 float centerY = 1.0f - radius; |
| 171 fshaderTxt.appendf( |
| 172 " {\n" |
| 173 " float d = length(%s - vec2(%f, %f));\n" |
| 174 " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n" |
| 175 " outputCoverage = 0.5 * outputCoverage + 0.5 * %s;\n" |
| 176 " }\n", |
| 177 oPosition.getName().c_str(), centerX, centerY, |
| 178 radius, |
| 179 fCoverageSetup == kUseVec4_CoverageSetup ? "vec4(edgeAlpha)" : "edge
Alpha" |
| 180 ); |
| 181 radius *= 0.8f; |
| 182 } |
| 183 fshaderTxt.appendf( |
| 184 " {\n" |
| 185 " %s = outputColor * outputCoverage;\n" |
| 186 " }\n" |
| 187 "}\n", |
| 188 fsOutName); |
| 189 |
| 190 return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str()); |
| 191 } |
| 192 |
| 193 template<typename Func> |
| 194 static void setup_matrices(int numQuads, Func f) { |
| 195 // We draw a really small triangle so we are not fill rate limited |
| 196 for (int i = 0 ; i < numQuads; i++) { |
| 197 SkMatrix m = SkMatrix::I(); |
| 198 m.setScale(0.01f, 0.01f); |
| 199 f(m); |
| 200 } |
| 201 } |
| 202 |
| 203 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 204 |
| 205 struct Vertex { |
| 206 SkPoint fPositions; |
| 207 GrGLfloat fColors[3]; |
| 208 }; |
| 209 |
| 210 void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix*
viewMatrices) { |
| 211 // triangles drawn will alternate between the top-right half of the screen a
nd the bottom-left |
| 212 // half of the screen |
| 213 Vertex vertices[kVerticesPerTri * kNumTriPerDraw]; |
| 214 for (uint32_t i = 0; i < kNumTriPerDraw; i++) { |
| 215 Vertex* v = &vertices[i * kVerticesPerTri]; |
| 216 if (i % 2 == 0) { |
| 217 v[0].fPositions.set(-1.0f, -1.0f); |
| 218 v[1].fPositions.set( 1.0f, -1.0f); |
| 219 v[2].fPositions.set( 1.0f, 1.0f); |
| 220 } else { |
| 221 v[0].fPositions.set(-1.0f, -1.0f); |
| 222 v[1].fPositions.set( 1.0f, 1.0f); |
| 223 v[2].fPositions.set( -1.0f, 1.0f); |
| 224 } |
| 225 SkPoint* position = reinterpret_cast<SkPoint*>(v); |
| 226 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesP
erTri); |
| 227 |
| 228 GrGLfloat color[3] = {1.0f, 0.0f, 1.0f}; |
| 229 for (uint32_t j = 0; j < kVerticesPerTri; j++) { |
| 230 v->fColors[0] = color[0]; |
| 231 v->fColors[1] = color[1]; |
| 232 v->fColors[2] = color[2]; |
| 233 v++; |
| 234 } |
| 235 } |
| 236 |
| 237 GR_GL_CALL(gl, GenBuffers(1, &fVboId)); |
| 238 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId)); |
| 239 GR_GL_CALL(gl, EnableVertexAttribArray(0)); |
| 240 GR_GL_CALL(gl, EnableVertexAttribArray(1)); |
| 241 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), |
| 242 (GrGLvoid*)0)); |
| 243 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Ve
rtex), |
| 244 (GrGLvoid*)(sizeof(SkPoint)))); |
| 245 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR
_GL_STATIC_DRAW)); |
| 246 } |
| 247 |
| 248 void GLVec4ScalarBench::setup(const GrGLContext* ctx) { |
| 249 const GrGLInterface* gl = ctx->interface(); |
| 250 if (!gl) { |
| 251 SkFAIL("GL interface is null in setup()\n"); |
| 252 } |
| 253 fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); |
| 254 |
| 255 fProgram = this->setupShader(ctx); |
| 256 |
| 257 GR_GL_CALL(gl, GenVertexArrays(1, &fVaoId)); |
| 258 GR_GL_CALL(gl, BindVertexArray(fVaoId)); |
| 259 |
| 260 int index = 0; |
| 261 SkMatrix viewMatrices[kNumTriPerDraw]; |
| 262 setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { |
| 263 viewMatrices[index++] = m; |
| 264 }); |
| 265 this->setupSingleVbo(gl, viewMatrices); |
| 266 |
| 267 GR_GL_CALL(gl, UseProgram(fProgram)); |
| 268 GR_GL_CALL(gl, BindVertexArray(fVaoId)); |
| 269 } |
| 270 |
| 271 void GLVec4ScalarBench::glDraw(const int loops, const GrGLContext* ctx) { |
| 272 const GrGLInterface* gl = ctx->interface(); |
| 273 |
| 274 for (int i = 0; i < loops; i++) { |
| 275 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriP
erDraw)); |
| 276 } |
| 277 |
| 278 // using -w when running nanobench will not produce correct images; |
| 279 // changing this to #if 1 will write the correct images to the Skia folder. |
| 280 #if 0 |
| 281 SkString filename("out"); |
| 282 filename.appendf("_%s.png", this->getName()); |
| 283 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); |
| 284 #endif |
| 285 } |
| 286 |
| 287 void GLVec4ScalarBench::teardown(const GrGLInterface* gl) { |
| 288 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0)); |
| 289 GR_GL_CALL(gl, BindVertexArray(0)); |
| 290 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); |
| 291 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); |
| 292 GR_GL_CALL(gl, DeleteTextures(1, &fFboTextureId)); |
| 293 GR_GL_CALL(gl, DeleteProgram(fProgram)); |
| 294 GR_GL_CALL(gl, DeleteBuffers(1, &fVboId)); |
| 295 GR_GL_CALL(gl, DeleteVertexArrays(1, &fVaoId)); |
| 296 } |
| 297 |
| 298 /////////////////////////////////////////////////////////////////////////////// |
| 299 |
| 300 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 1) ) |
| 301 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 1) ) |
| 302 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 2) ) |
| 303 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 2) ) |
| 304 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 4) ) |
| 305 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 4) ) |
| 306 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 6) ) |
| 307 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 6) ) |
| 308 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSe
tup, 8) ) |
| 309 DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetu
p, 8) ) |
| 310 |
| 311 #endif |
OLD | NEW |