1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Based on Hello_Triangle.c from
8 // Book: OpenGL(R) ES 2.0 Programming Guide
9 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10 // ISBN-10: 0321502795
11 // ISBN-13: 9780321502797
12 // Publisher: Addison-Wesley Professional
13 // URLs: http://safari.informit.com/9780321563835
14 // http://www.opengles-book.com
15
16 #include "SampleApplication.h"
17
18 #include "util/shader_utils.h"
19
20 #include <cstring>
21 #include <iostream>
22
23 // This small sample compares the per-frame render time for a series of
24 // squares drawn with TRIANGLE_FANS versus squares drawn with TRIANGLES.
25 // To exacerbate differences between the two, we use a large collection
26 // of short buffers with pre-translated vertex data.
27
28 class TriangleFanBenchSample : public SampleApplication
29 {
30 public:
TriangleFanBenchSample(int argc,char ** argv)31 TriangleFanBenchSample(int argc, char **argv)
32 : SampleApplication("Microbench", argc, argv, 2, 0, 1280, 1280), mFrameCount(0)
33 {}
34
createVertexBuffers()35 void createVertexBuffers()
36 {
37 const unsigned int slices = 8;
38 const unsigned int numFanVertices = slices + 2;
39 const unsigned int fanFloats = numFanVertices * 3;
40
41 mNumFanVerts = numFanVertices;
42
43 const GLfloat halfDim = 0.0625;
44 GLfloat fanVertices[] = {
45 0.0f, 0.0f, 0.0f, // center
46 -halfDim, -halfDim, 0.0f, // LL
47 -halfDim, 0.0f, 0.0f, // CL
48 -halfDim, halfDim, 0.0f, // UL
49 0.0f, halfDim, 0.0f, // UC
50 halfDim, halfDim, 0.0f, // UR
51 halfDim, 0.0f, 0.0f, // CR
52 halfDim, -halfDim, 0.0f, // LR
53 0.0f, -halfDim, 0.0f, // LC
54 -halfDim, -halfDim, 0.0f // LL (closes the fan)
55 };
56
57 const GLfloat xMin = -1.0f; // We leave viewport/worldview untransformed in this sample
58 const GLfloat xMax = 1.0f;
59 const GLfloat yMin = -1.0f;
60 // const GLfloat yMax = 1.0f;
61
62 glGenBuffers(mNumSquares, mFanBufId);
63
64 GLfloat xOffset = xMin;
65 GLfloat yOffset = yMin;
66 for (unsigned int i = 0; i < mNumSquares; ++i)
67 {
68 GLfloat tempVerts[fanFloats] = {0};
69 for (unsigned int j = 0; j < numFanVertices; ++j)
70 {
71 tempVerts[j * 3] = fanVertices[j * 3] + xOffset;
72 tempVerts[j * 3 + 1] = fanVertices[j * 3 + 1] + yOffset;
73 tempVerts[j * 3 + 2] = 0.0f;
74 }
75
76 glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]);
77 glBufferData(GL_ARRAY_BUFFER, fanFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW);
78
79 xOffset += 2 * halfDim;
80 if (xOffset > xMax)
81 {
82 xOffset = xMin;
83 yOffset += 2 * halfDim;
84 }
85 }
86
87 const unsigned int numTriVertices = slices * 3;
88 const unsigned int triFloats = numTriVertices * 3;
89 GLfloat triVertices[triFloats];
90 GLfloat *triPointer = triVertices;
91
92 mNumTriVerts = numTriVertices;
93
94 for (unsigned int i = 0; i < slices; ++i)
95 {
96 memcpy(triPointer, fanVertices,
97 3 * sizeof(GLfloat)); // copy center point as first vertex for this slice
98 triPointer += 3;
99 for (unsigned int j = 1; j < 3; ++j)
100 {
101 GLfloat *vertex =
102 &(fanVertices[(i + j) * 3]); // copy two outer vertices for this point
103 memcpy(triPointer, vertex, 3 * sizeof(GLfloat));
104 triPointer += 3;
105 }
106 }
107
108 // GLfloat triVertices2[triFloats];
109 glGenBuffers(mNumSquares, mTriBufId);
110 xOffset = xMin;
111 yOffset = yMin;
112
113 for (unsigned int i = 0; i < mNumSquares; ++i)
114 {
115 triPointer = triVertices;
116 GLfloat tempVerts[triFloats];
117 for (unsigned int j = 0; j < numTriVertices; ++j)
118 {
119 tempVerts[j * 3] = triPointer[0] + xOffset;
120 tempVerts[j * 3 + 1] = triPointer[1] + yOffset;
121 tempVerts[j * 3 + 2] = 0.0f;
122 triPointer += 3;
123 }
124
125 glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]);
126 glBufferData(GL_ARRAY_BUFFER, triFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW);
127 xOffset += 2 * halfDim;
128 if (xOffset > xMax)
129 {
130 yOffset += 2 * halfDim;
131 xOffset = xMin;
132 }
133 }
134 }
135
initialize()136 bool initialize() override
137 {
138 constexpr char kVS[] = R"(attribute vec4 vPosition;
139 void main()
140 {
141 gl_Position = vPosition;
142 })";
143
144 constexpr char kFS[] = R"(precision mediump float;
145 void main()
146 {
147 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
148 })";
149
150 mProgram = CompileProgram(kVS, kFS);
151 if (!mProgram)
152 {
153 return false;
154 }
155
156 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
157
158 createVertexBuffers();
159
160 mFanTotalTime = 0;
161 mTriTotalTime = 0;
162
163 return true;
164 }
165
destroy()166 void destroy() override
167 {
168 std::cout << "Total draw time using TRIANGLE_FAN: " << mFanTotalTime << "ms ("
169 << (float)mFanTotalTime / (float)mFrameCount << " average per frame)"
170 << std::endl;
171 std::cout << "Total draw time using TRIANGLES: " << mTriTotalTime << "ms ("
172 << (float)mTriTotalTime / (float)mFrameCount << " average per frame)"
173 << std::endl;
174 glDeleteProgram(mProgram);
175 }
176
draw()177 void draw() override
178 {
179 // Set the viewport
180 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
181
182 // Clear the color buffer
183 glClear(GL_COLOR_BUFFER_BIT);
184
185 // Use the program object
186 glUseProgram(mProgram);
187
188 // Bind the vertex data
189 glEnableVertexAttribArray(0);
190
191 // Draw using triangle fans, stored in VBO
192 mFanTimer.start();
193 for (unsigned i = 0; i < mNumSquares; ++i)
194 {
195 glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]);
196 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
197 glDrawArrays(GL_TRIANGLE_FAN, 0, mNumFanVerts);
198 }
199 mFanTimer.stop();
200
201 mFanTotalTime += static_cast<unsigned int>(
202 mFanTimer.getElapsedTime() * 1000); // convert from usec to msec when accumulating
203
204 // Clear to eliminate driver-side gains from occlusion
205 glClear(GL_COLOR_BUFFER_BIT);
206
207 // Draw using triangles, stored in VBO
208 mTriTimer.start();
209 for (unsigned i = 1; i < mNumSquares; ++i)
210 {
211 glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]);
212 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
213 glDrawArrays(GL_TRIANGLES, 0, mNumTriVerts);
214 }
215 mTriTimer.stop();
216
217 mTriTotalTime += static_cast<unsigned int>(
218 mTriTimer.getElapsedTime() * 1000); // convert from usec to msec when accumulating
219
220 mFrameCount++;
221 }
222
223 private:
224 static const unsigned int mNumSquares = 289;
225 unsigned int mNumFanVerts;
226 unsigned int mNumTriVerts;
227 GLuint mProgram;
228 GLuint mFanBufId[mNumSquares];
229 GLuint mTriBufId[mNumSquares];
230
231 Timer mFanTimer;
232 Timer mTriTimer;
233 unsigned int mFrameCount;
234 unsigned int mTriTotalTime;
235 unsigned int mFanTotalTime;
236 };
237
main(int argc,char ** argv)238 int main(int argc, char **argv)
239 {
240 TriangleFanBenchSample app(argc, argv);
241 return app.run();
242 }
243