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