blob: 8cc329a33bab810b952f3c288a0001b5d4f3c027 [file] [log] [blame]
wangyix891f0f32015-07-15 12:26:07 -07001/*
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"
Brian Salomon94efbf52016-11-29 13:43:05 -050014#include "GrShaderCaps.h"
Brian Salomon99938a82016-11-21 13:41:08 -050015#include "GrShaderVar.h"
egdanielf5294392015-10-21 07:14:17 -070016#include "gl/GrGLContext.h"
wangyix891f0f32015-07-15 12:26:07 -070017#include "gl/GrGLInterface.h"
wangyix891f0f32015-07-15 12:26:07 -070018#include "gl/GrGLUtil.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050019#include "../private/GrGLSL.h"
wangyix891f0f32015-07-15 12:26:07 -070020
21#include <stdio.h>
22
23/**
24 * This is a GL benchmark for comparing the performance of using vec4 or float for coverage in GLSL.
25 * The generated shader code from this bench will draw several overlapping circles, one in each
26 * stage, to simulate coverage calculations. The number of circles (i.e. the number of stages) can
27 * be set as a parameter.
28 */
29
30class GLVec4ScalarBench : public GLBench {
31public:
32 /*
33 * Use float or vec4 as GLSL data type for the output coverage
34 */
35 enum CoverageSetup {
36 kUseScalar_CoverageSetup,
37 kUseVec4_CoverageSetup,
38 };
39
40 /*
41 * numStages determines the number of shader stages before the XP,
42 * which consequently determines how many circles are drawn
43 */
44 GLVec4ScalarBench(CoverageSetup coverageSetup, uint32_t numStages)
45 : fCoverageSetup(coverageSetup)
46 , fNumStages(numStages)
47 , fVboId(0)
48 , fProgram(0) {
49 fName = NumStagesSetupToStr(coverageSetup, numStages);
50 }
51
52protected:
53 const char* onGetName() override {
54 return fName.c_str();
55 }
56
57 void setup(const GrGLContext*) override;
mtkleina1ebeb22015-10-01 09:43:39 -070058 void glDraw(int loops, const GrGLContext*) override;
wangyix891f0f32015-07-15 12:26:07 -070059 void teardown(const GrGLInterface*) override;
60
61private:
62 void setupSingleVbo(const GrGLInterface*, const SkMatrix*);
63 GrGLuint setupShader(const GrGLContext*);
64
65
66 static SkString NumStagesSetupToStr(CoverageSetup coverageSetup, uint32_t numStages) {
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 fFboTextureId;
91};
92
93///////////////////////////////////////////////////////////////////////////////////////////////////
94
95GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) {
Brian Salomon1edc5b92016-11-29 13:43:46 -050096 const GrShaderCaps* shaderCaps = ctx->caps()->shaderCaps();
97 const char* version = shaderCaps->versionDeclString();
wangyix891f0f32015-07-15 12:26:07 -070098
99 // this shader draws fNumStages overlapping circles of increasing opacity (coverage) 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
Brian Salomon99938a82016-11-21 13:41:08 -0500104 GrShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier);
105 GrShaderVar oPosition("o_position", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier);
106 GrShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kIn_TypeModifier);
107 GrShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kOut_TypeModifier);
wangyix891f0f32015-07-15 12:26:07 -0700108
109 SkString vshaderTxt(version);
Brian Salomon1edc5b92016-11-29 13:43:46 -0500110 aPosition.appendDecl(shaderCaps, &vshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700111 vshaderTxt.append(";\n");
Brian Salomon1edc5b92016-11-29 13:43:46 -0500112 aColor.appendDecl(shaderCaps, &vshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700113 vshaderTxt.append(";\n");
Brian Salomon1edc5b92016-11-29 13:43:46 -0500114 oPosition.appendDecl(shaderCaps, &vshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700115 vshaderTxt.append(";\n");
Brian Salomon1edc5b92016-11-29 13:43:46 -0500116 oColor.appendDecl(shaderCaps, &vshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700117 vshaderTxt.append(";\n");
118
119 vshaderTxt.append(
120 "void main()\n"
121 "{\n"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400122 " gl_Position = float4(a_position, 0.0, 1.0);\n"
wangyix891f0f32015-07-15 12:26:07 -0700123 " o_position = a_position;\n"
124 " o_color = a_color;\n"
125 "}\n");
126
wangyix891f0f32015-07-15 12:26:07 -0700127 // set up fragment shader; this fragment shader will have fNumStages coverage stages plus an
128 // XP stage at the end. Each coverage stage computes the pixel's distance from 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 and passed to the
131 // next stage.
Brian Salomon99938a82016-11-21 13:41:08 -0500132 GrShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
wangyix891f0f32015-07-15 12:26:07 -0700133 SkString fshaderTxt(version);
Brian Osman33aa2c72017-04-05 09:26:15 -0400134 GrGLSLAppendDefaultFloatPrecisionDeclaration(kMedium_GrSLPrecision, *shaderCaps, &fshaderTxt);
Brian Salomonf31ae492016-11-18 15:35:33 -0500135 oPosition.setTypeModifier(GrShaderVar::kIn_TypeModifier);
Brian Salomon1edc5b92016-11-29 13:43:46 -0500136 oPosition.appendDecl(shaderCaps, &fshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700137 fshaderTxt.append(";\n");
Brian Salomonf31ae492016-11-18 15:35:33 -0500138 oColor.setTypeModifier(GrShaderVar::kIn_TypeModifier);
Brian Salomon1edc5b92016-11-29 13:43:46 -0500139 oColor.appendDecl(shaderCaps, &fshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700140 fshaderTxt.append(";\n");
141
142 const char* fsOutName;
Brian Salomon1edc5b92016-11-29 13:43:46 -0500143 if (shaderCaps->mustDeclareFragmentShaderOutput()) {
144 oFragColor.appendDecl(shaderCaps, &fshaderTxt);
wangyix891f0f32015-07-15 12:26:07 -0700145 fshaderTxt.append(";\n");
146 fsOutName = oFragColor.c_str();
147 } else {
ethannicholasfbbbb9d2016-10-12 11:46:07 -0700148 fsOutName = "sk_FragColor";
wangyix891f0f32015-07-15 12:26:07 -0700149 }
150
151
152 fshaderTxt.appendf(
153 "void main()\n"
154 "{\n"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400155 " float4 outputColor;\n"
wangyix891f0f32015-07-15 12:26:07 -0700156 " %s outputCoverage;\n"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400157 " outputColor = float4(%s, 1.0);\n"
wangyix891f0f32015-07-15 12:26:07 -0700158 " outputCoverage = %s;\n",
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400159 fCoverageSetup == kUseVec4_CoverageSetup ? "float4" : "float",
wangyix891f0f32015-07-15 12:26:07 -0700160 oColor.getName().c_str(),
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400161 fCoverageSetup == kUseVec4_CoverageSetup ? "float4(1.0)" : "1.0"
wangyix891f0f32015-07-15 12:26:07 -0700162 );
163
164 float radius = 1.0f;
165 for (uint32_t i = 0; i < fNumStages; i++) {
166 float centerX = 1.0f - radius;
167 float centerY = 1.0f - radius;
168 fshaderTxt.appendf(
169 " {\n"
Ethan Nicholas31981ec2017-07-28 19:25:48 -0400170 " float d = length(%s - float2(%f, %f));\n"
wangyix891f0f32015-07-15 12:26:07 -0700171 " float edgeAlpha = clamp(100.0 * (%f - d), 0.0, 1.0);\n"
172 " outputCoverage = 0.5 * outputCoverage + 0.5 * %s;\n"
173 " }\n",
174 oPosition.getName().c_str(), centerX, centerY,
175 radius,
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400176 fCoverageSetup == kUseVec4_CoverageSetup ? "float4(edgeAlpha)" : "edgeAlpha"
wangyix891f0f32015-07-15 12:26:07 -0700177 );
178 radius *= 0.8f;
179 }
180 fshaderTxt.appendf(
181 " {\n"
182 " %s = outputColor * outputCoverage;\n"
183 " }\n"
184 "}\n",
185 fsOutName);
186
ethannicholas5961bc92016-10-12 06:39:56 -0700187 return CreateProgram(ctx, vshaderTxt.c_str(), fshaderTxt.c_str());
wangyix891f0f32015-07-15 12:26:07 -0700188}
189
190template<typename Func>
191static void setup_matrices(int numQuads, Func f) {
192 // We draw a really small triangle so we are not fill rate limited
193 for (int i = 0 ; i < numQuads; i++) {
194 SkMatrix m = SkMatrix::I();
195 m.setScale(0.01f, 0.01f);
196 f(m);
197 }
198}
199
200///////////////////////////////////////////////////////////////////////////////////////////////////
201
202struct Vertex {
203 SkPoint fPositions;
204 GrGLfloat fColors[3];
205};
206
207void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix* viewMatrices) {
208 // triangles drawn will alternate between the top-right half of the screen and the bottom-left
209 // half of the screen
210 Vertex vertices[kVerticesPerTri * kNumTriPerDraw];
211 for (uint32_t i = 0; i < kNumTriPerDraw; i++) {
212 Vertex* v = &vertices[i * kVerticesPerTri];
213 if (i % 2 == 0) {
214 v[0].fPositions.set(-1.0f, -1.0f);
215 v[1].fPositions.set( 1.0f, -1.0f);
216 v[2].fPositions.set( 1.0f, 1.0f);
217 } else {
218 v[0].fPositions.set(-1.0f, -1.0f);
219 v[1].fPositions.set( 1.0f, 1.0f);
220 v[2].fPositions.set( -1.0f, 1.0f);
221 }
222 SkPoint* position = reinterpret_cast<SkPoint*>(v);
223 viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesPerTri);
224
225 GrGLfloat color[3] = {1.0f, 0.0f, 1.0f};
226 for (uint32_t j = 0; j < kVerticesPerTri; j++) {
227 v->fColors[0] = color[0];
228 v->fColors[1] = color[1];
229 v->fColors[2] = color[2];
230 v++;
231 }
232 }
233
234 GR_GL_CALL(gl, GenBuffers(1, &fVboId));
235 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId));
236 GR_GL_CALL(gl, EnableVertexAttribArray(0));
237 GR_GL_CALL(gl, EnableVertexAttribArray(1));
238 GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex),
239 (GrGLvoid*)0));
240 GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex),
241 (GrGLvoid*)(sizeof(SkPoint))));
242 GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR_GL_STATIC_DRAW));
243}
244
245void GLVec4ScalarBench::setup(const GrGLContext* ctx) {
246 const GrGLInterface* gl = ctx->interface();
247 if (!gl) {
halcanary96fcdcc2015-08-27 07:41:13 -0700248 SkFAIL("GL interface is nullptr in setup()!\n");
wangyix891f0f32015-07-15 12:26:07 -0700249 }
250 fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight);
251
252 fProgram = this->setupShader(ctx);
253
254 int index = 0;
255 SkMatrix viewMatrices[kNumTriPerDraw];
256 setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) {
257 viewMatrices[index++] = m;
258 });
259 this->setupSingleVbo(gl, viewMatrices);
260
261 GR_GL_CALL(gl, UseProgram(fProgram));
262}
263
mtkleina1ebeb22015-10-01 09:43:39 -0700264void GLVec4ScalarBench::glDraw(int loops, const GrGLContext* ctx) {
wangyix891f0f32015-07-15 12:26:07 -0700265 const GrGLInterface* gl = ctx->interface();
266
267 for (int i = 0; i < loops; i++) {
268 GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriPerDraw));
269 }
270
271// using -w when running nanobench will not produce correct images;
272// changing this to #if 1 will write the correct images to the Skia folder.
273#if 0
274 SkString filename("out");
275 filename.appendf("_%s.png", this->getName());
276 DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str());
277#endif
278}
279
280void GLVec4ScalarBench::teardown(const GrGLInterface* gl) {
281 GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0));
282 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0));
283 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0));
284 GR_GL_CALL(gl, DeleteTextures(1, &fFboTextureId));
285 GR_GL_CALL(gl, DeleteProgram(fProgram));
286 GR_GL_CALL(gl, DeleteBuffers(1, &fVboId));
287}
288
289///////////////////////////////////////////////////////////////////////////////
290
291DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 1) )
292DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 1) )
293DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 2) )
294DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 2) )
295DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 4) )
296DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 4) )
297DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 6) )
298DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 6) )
299DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseScalar_CoverageSetup, 8) )
300DEF_BENCH( return new GLVec4ScalarBench(GLVec4ScalarBench::kUseVec4_CoverageSetup, 8) )
301
302#endif