blob: 32137bb6b0798e14315f2e946b4ba0a274b1160c [file] [log] [blame]
//
// Copyright (c) 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 "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()
: SampleApplication("Microbench", 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;
}
}
}
virtual bool initialize()
{
const std::string vs = SHADER_SOURCE
(
attribute vec4 vPosition;
void main()
{
gl_Position = vPosition;
}
);
const std::string fs = SHADER_SOURCE
(
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
);
mProgram = CompileProgram(vs, fs);
if (!mProgram)
{
return false;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
createVertexBuffers();
mFanTimer = CreateTimer();
mTriTimer = CreateTimer();
mFanTotalTime = 0;
mTriTotalTime = 0;
return true;
}
virtual void destroy()
{
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);
}
virtual void draw()
{
// 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;
return app.run();
}