blob: 52bf51af2a02fb29337a32d7cf42c19177844aee [file] [log] [blame]
//
// 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.getElapsedWallClockTime() *
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.getElapsedWallClockTime() *
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();
}