| // | |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // Based on Hello_Triangle.c from | |
| // Book: OpenGL(R) ES 2.0 Programming Guide | |
| // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner | |
| // ISBN-10: 0321502795 | |
| // ISBN-13: 9780321502797 | |
| // Publisher: Addison-Wesley Professional | |
| // URLs: http://safari.informit.com/9780321563835 | |
| // http://www.opengles-book.com | |
| #include "SampleApplication.h" | |
| #include "util/shader_utils.h" | |
| #include <cstring> | |
| #include <iostream> | |
| // This small sample compares the per-frame render time for a series of | |
| // squares drawn with TRIANGLE_FANS versus squares drawn with TRIANGLES. | |
| // To exacerbate differences between the two, we use a large collection | |
| // of short buffers with pre-translated vertex data. | |
| class TriangleFanBenchSample : public SampleApplication | |
| { | |
| public: | |
| TriangleFanBenchSample(int argc, char **argv) | |
| : SampleApplication("Microbench", argc, argv, 2, 0, 1280, 1280), mFrameCount(0) | |
| {} | |
| void createVertexBuffers() | |
| { | |
| const unsigned int slices = 8; | |
| const unsigned int numFanVertices = slices + 2; | |
| const unsigned int fanFloats = numFanVertices * 3; | |
| mNumFanVerts = numFanVertices; | |
| const GLfloat halfDim = 0.0625; | |
| GLfloat fanVertices[] = { | |
| 0.0f, 0.0f, 0.0f, // center | |
| -halfDim, -halfDim, 0.0f, // LL | |
| -halfDim, 0.0f, 0.0f, // CL | |
| -halfDim, halfDim, 0.0f, // UL | |
| 0.0f, halfDim, 0.0f, // UC | |
| halfDim, halfDim, 0.0f, // UR | |
| halfDim, 0.0f, 0.0f, // CR | |
| halfDim, -halfDim, 0.0f, // LR | |
| 0.0f, -halfDim, 0.0f, // LC | |
| -halfDim, -halfDim, 0.0f // LL (closes the fan) | |
| }; | |
| const GLfloat xMin = -1.0f; // We leave viewport/worldview untransformed in this sample | |
| const GLfloat xMax = 1.0f; | |
| const GLfloat yMin = -1.0f; | |
| // const GLfloat yMax = 1.0f; | |
| glGenBuffers(mNumSquares, mFanBufId); | |
| GLfloat xOffset = xMin; | |
| GLfloat yOffset = yMin; | |
| for (unsigned int i = 0; i < mNumSquares; ++i) | |
| { | |
| GLfloat tempVerts[fanFloats] = {0}; | |
| for (unsigned int j = 0; j < numFanVertices; ++j) | |
| { | |
| tempVerts[j * 3] = fanVertices[j * 3] + xOffset; | |
| tempVerts[j * 3 + 1] = fanVertices[j * 3 + 1] + yOffset; | |
| tempVerts[j * 3 + 2] = 0.0f; | |
| } | |
| glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]); | |
| glBufferData(GL_ARRAY_BUFFER, fanFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW); | |
| xOffset += 2 * halfDim; | |
| if (xOffset > xMax) | |
| { | |
| xOffset = xMin; | |
| yOffset += 2 * halfDim; | |
| } | |
| } | |
| const unsigned int numTriVertices = slices * 3; | |
| const unsigned int triFloats = numTriVertices * 3; | |
| GLfloat triVertices[triFloats]; | |
| GLfloat *triPointer = triVertices; | |
| mNumTriVerts = numTriVertices; | |
| for (unsigned int i = 0; i < slices; ++i) | |
| { | |
| memcpy(triPointer, fanVertices, | |
| 3 * sizeof(GLfloat)); // copy center point as first vertex for this slice | |
| triPointer += 3; | |
| for (unsigned int j = 1; j < 3; ++j) | |
| { | |
| GLfloat *vertex = | |
| &(fanVertices[(i + j) * 3]); // copy two outer vertices for this point | |
| memcpy(triPointer, vertex, 3 * sizeof(GLfloat)); | |
| triPointer += 3; | |
| } | |
| } | |
| // GLfloat triVertices2[triFloats]; | |
| glGenBuffers(mNumSquares, mTriBufId); | |
| xOffset = xMin; | |
| yOffset = yMin; | |
| for (unsigned int i = 0; i < mNumSquares; ++i) | |
| { | |
| triPointer = triVertices; | |
| GLfloat tempVerts[triFloats]; | |
| for (unsigned int j = 0; j < numTriVertices; ++j) | |
| { | |
| tempVerts[j * 3] = triPointer[0] + xOffset; | |
| tempVerts[j * 3 + 1] = triPointer[1] + yOffset; | |
| tempVerts[j * 3 + 2] = 0.0f; | |
| triPointer += 3; | |
| } | |
| glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]); | |
| glBufferData(GL_ARRAY_BUFFER, triFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW); | |
| xOffset += 2 * halfDim; | |
| if (xOffset > xMax) | |
| { | |
| yOffset += 2 * halfDim; | |
| xOffset = xMin; | |
| } | |
| } | |
| } | |
| bool initialize() override | |
| { | |
| constexpr char kVS[] = R"(attribute vec4 vPosition; | |
| void main() | |
| { | |
| gl_Position = vPosition; | |
| })"; | |
| constexpr char kFS[] = R"(precision mediump float; | |
| void main() | |
| { | |
| gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); | |
| })"; | |
| mProgram = CompileProgram(kVS, kFS); | |
| if (!mProgram) | |
| { | |
| return false; | |
| } | |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
| createVertexBuffers(); | |
| mFanTotalTime = 0; | |
| mTriTotalTime = 0; | |
| return true; | |
| } | |
| void destroy() override | |
| { | |
| std::cout << "Total draw time using TRIANGLE_FAN: " << mFanTotalTime << "ms (" | |
| << (float)mFanTotalTime / (float)mFrameCount << " average per frame)" | |
| << std::endl; | |
| std::cout << "Total draw time using TRIANGLES: " << mTriTotalTime << "ms (" | |
| << (float)mTriTotalTime / (float)mFrameCount << " average per frame)" | |
| << std::endl; | |
| glDeleteProgram(mProgram); | |
| } | |
| void draw() override | |
| { | |
| // Set the viewport | |
| glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); | |
| // Clear the color buffer | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| // Use the program object | |
| glUseProgram(mProgram); | |
| // Bind the vertex data | |
| glEnableVertexAttribArray(0); | |
| // Draw using triangle fans, stored in VBO | |
| mFanTimer.start(); | |
| for (unsigned i = 0; i < mNumSquares; ++i) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]); | |
| glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); | |
| glDrawArrays(GL_TRIANGLE_FAN, 0, mNumFanVerts); | |
| } | |
| mFanTimer.stop(); | |
| mFanTotalTime += static_cast<unsigned int>( | |
| mFanTimer.getElapsedTime() * 1000); // convert from usec to msec when accumulating | |
| // Clear to eliminate driver-side gains from occlusion | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| // Draw using triangles, stored in VBO | |
| mTriTimer.start(); | |
| for (unsigned i = 1; i < mNumSquares; ++i) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]); | |
| glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); | |
| glDrawArrays(GL_TRIANGLES, 0, mNumTriVerts); | |
| } | |
| mTriTimer.stop(); | |
| mTriTotalTime += static_cast<unsigned int>( | |
| mTriTimer.getElapsedTime() * 1000); // convert from usec to msec when accumulating | |
| mFrameCount++; | |
| } | |
| private: | |
| static const unsigned int mNumSquares = 289; | |
| unsigned int mNumFanVerts; | |
| unsigned int mNumTriVerts; | |
| GLuint mProgram; | |
| GLuint mFanBufId[mNumSquares]; | |
| GLuint mTriBufId[mNumSquares]; | |
| Timer mFanTimer; | |
| Timer mTriTimer; | |
| unsigned int mFrameCount; | |
| unsigned int mTriTotalTime; | |
| unsigned int mFanTotalTime; | |
| }; | |
| int main(int argc, char **argv) | |
| { | |
| TriangleFanBenchSample app(argc, argv); | |
| return app.run(); | |
| } |