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