// // 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 #include // 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( 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( 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(); }