Commits

Anonymous committed 8484a73

Basic profiling started.

  • Participants
  • Parent commits 4de782a

Comments (0)

Files changed (14)

File tests/manual/attrib3.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+//layout(location = 3) in vec3 normal;
+//layout(location = 4) in vec3 tangent;
+//layout(location = 5) in vec3 bitangent;
+//layout(location = 6) in vec4 boneIndices;
+//layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(0.0);
+	accum += vec4(position, 1.0);
+	accum += vec4(color);
+	accum += vec4(texCoord, 0.0, 1.0);
+//	accum += vec4(normal, 1.0);
+//	accum += vec4(tangent, 1.0);
+//	accum += vec4(bitangent, 1.0);
+//	accum += vec4(boneIndices);
+//	accum += vec4(boneWeights);
+	gl_Position = accum;
+}
+

File tests/manual/attrib4.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+layout(location = 3) in vec3 normal;
+//layout(location = 4) in vec3 tangent;
+//layout(location = 5) in vec3 bitangent;
+//layout(location = 6) in vec4 boneIndices;
+//layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(0.0);
+	accum += vec4(position, 1.0);
+	accum += vec4(color);
+	accum += vec4(texCoord, 0.0, 1.0);
+	accum += vec4(normal, 1.0);
+//	accum += vec4(tangent, 1.0);
+//	accum += vec4(bitangent, 1.0);
+//	accum += vec4(boneIndices);
+//	accum += vec4(boneWeights);
+	gl_Position = accum;
+}
+

File tests/manual/attrib5.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+layout(location = 3) in vec3 normal;
+layout(location = 4) in vec3 tangent;
+//layout(location = 5) in vec3 bitangent;
+//layout(location = 6) in vec4 boneIndices;
+//layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(0.0);
+	accum += vec4(position, 1.0);
+	accum += vec4(color);
+	accum += vec4(texCoord, 0.0, 1.0);
+	accum += vec4(normal, 1.0);
+	accum += vec4(tangent, 1.0);
+//	accum += vec4(bitangent, 1.0);
+//	accum += vec4(boneIndices);
+//	accum += vec4(boneWeights);
+	gl_Position = accum;
+}
+

File tests/manual/attrib6.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+layout(location = 3) in vec3 normal;
+layout(location = 4) in vec3 tangent;
+layout(location = 5) in vec3 bitangent;
+//layout(location = 6) in vec4 boneIndices;
+//layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(0.0);
+	accum += vec4(position, 1.0);
+	accum += vec4(color);
+	accum += vec4(texCoord, 0.0, 1.0);
+	accum += vec4(normal, 1.0);
+	accum += vec4(tangent, 1.0);
+	accum += vec4(bitangent, 1.0);
+//	accum += vec4(boneIndices);
+//	accum += vec4(boneWeights);
+	gl_Position = accum;
+}
+

File tests/manual/attrib7.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+layout(location = 3) in vec3 normal;
+layout(location = 4) in vec3 tangent;
+layout(location = 5) in vec3 bitangent;
+layout(location = 6) in vec4 boneIndices;
+//layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(position, 1.0)
+	+ vec4(color)
+	+ vec4(texCoord, 0.0, 1.0)
+	+ vec4(normal, 1.0)
+	+ vec4(tangent, 1.0)
+	+ vec4(bitangent, 1.0)
+	+ vec4(boneIndices)
+//	+ vec4(boneWeights)
+	;
+	gl_Position = accum;
+}
+

File tests/manual/attrib8.vert

+
+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 color;
+layout(location = 2) in vec2 texCoord;
+layout(location = 3) in vec3 normal;
+layout(location = 4) in vec3 tangent;
+layout(location = 5) in vec3 bitangent;
+layout(location = 6) in vec4 boneIndices;
+layout(location = 7) in vec4 boneWeights;
+
+void main()
+{
+	vec4 accum = vec4(0.0);
+	accum += vec4(position, 1.0);
+	accum += vec4(color);
+	accum += vec4(texCoord, 0.0, 1.0);
+	accum += vec4(normal, 1.0);
+	accum += vec4(tangent, 1.0);
+	accum += vec4(bitangent, 1.0);
+	accum += vec4(boneIndices);
+	accum += vec4(boneWeights);
+	gl_Position = accum;
+}
+

File tests/manual/frag.frag

+
+#version 330
+
+out vec4 outColor;
+
+void main()
+{
+	outColor = vec4(1.0);
+}

File tests/manual/main.cpp

+
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <iterator>
+#include <glload/gl_3_3.h>
+#include <glload/gll.hpp>
+#include <glutil/Shader.h>
+#include <GL/freeglut.h>
+#include "../util/util.h"
+
+
+const int NUM_ATTRIBUTE_VARIATIONS = 6;
+const int START_ATTRIBUTE_COUNT = 3;
+const int TOTAL_ATTRIBUTE_COUNT = START_ATTRIBUTE_COUNT + NUM_ATTRIBUTE_VARIATIONS - 1;
+
+const int MAX_NUM_VERTICES = 50000;
+
+struct TestSuite
+{
+public:
+	TestSuite()
+		: separateArrayBuffers(util::CreateBufferObjects(TOTAL_ATTRIBUTE_COUNT))
+		, individualArrayBuffer(util::CreateBufferObject())
+		, interleavedArrayBuffers(util::CreateBufferObjects(NUM_ATTRIBUTE_VARIATIONS))
+		, indexBuffer(util::CreateBufferObject())
+		, programs(util::CreatePrograms(NUM_ATTRIBUTE_VARIATIONS))
+	{
+		{
+			attribSize.resize(TOTAL_ATTRIBUTE_COUNT);
+			attribType.resize(TOTAL_ATTRIBUTE_COUNT);
+			attribNormalized.resize(TOTAL_ATTRIBUTE_COUNT);
+			attribSize[0] = 3; attribType[0] = GL_FLOAT; attribNormalized[0] = GL_FALSE;
+			attribSize[1] = 4; attribType[1] = GL_UNSIGNED_BYTE; attribNormalized[1] = GL_TRUE;
+			attribSize[2] = 2; attribType[2] = GL_SHORT; attribNormalized[2] = GL_TRUE;
+			attribSize[3] = 3; attribType[3] = GL_FLOAT; attribNormalized[3] = GL_FALSE;
+			attribSize[4] = 3; attribType[4] = GL_FLOAT; attribNormalized[4] = GL_FALSE;
+			attribSize[5] = 3; attribType[5] = GL_FLOAT; attribNormalized[5] = GL_FALSE;
+			attribSize[6] = 4; attribType[6] = GL_UNSIGNED_BYTE; attribNormalized[6] = GL_FALSE;
+			attribSize[7] = 4; attribType[7] = GL_UNSIGNED_BYTE; attribNormalized[7] = GL_TRUE;
+
+			//Create the separate array buffers.
+			std::vector<GLfloat> positions(attribSize[0] * MAX_NUM_VERTICES, 1.0f);
+			std::vector<GLubyte> color(attribSize[1] * MAX_NUM_VERTICES, 255);
+			std::vector<GLshort> texCoord(attribSize[2] * MAX_NUM_VERTICES, 0);
+			std::vector<GLfloat> normal(attribSize[3] * MAX_NUM_VERTICES, 1.0f);
+			std::vector<GLfloat> tangent(attribSize[4] * MAX_NUM_VERTICES, 1.0f);
+			std::vector<GLfloat> bitangent(attribSize[5] * MAX_NUM_VERTICES, 1.0f);
+			std::vector<GLubyte> boneIndices(attribSize[6] * MAX_NUM_VERTICES, 0);
+			std::vector<GLubyte> boneWeights(attribSize[7] * MAX_NUM_VERTICES, 1);
+
+			util::FillBufferData(separateArrayBuffers[0], GL_ARRAY_BUFFER, positions, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[1], GL_ARRAY_BUFFER, color, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[2], GL_ARRAY_BUFFER, texCoord, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[3], GL_ARRAY_BUFFER, normal, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[4], GL_ARRAY_BUFFER, tangent, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[5], GL_ARRAY_BUFFER, bitangent, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[6], GL_ARRAY_BUFFER, boneIndices, GL_STATIC_DRAW);
+			util::FillBufferData(separateArrayBuffers[7], GL_ARRAY_BUFFER, boneWeights, GL_STATIC_DRAW);
+
+			//Create the individual buffer.
+			individualOffsets.reserve(TOTAL_ATTRIBUTE_COUNT);
+			int totalBufferSize = 0;
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(positions);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(color);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(texCoord);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(normal);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(tangent);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(bitangent);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(boneIndices);
+			individualOffsets.push_back(totalBufferSize);
+			totalBufferSize += util::CalcOffset(boneWeights);
+
+			glBindBuffer(GL_ARRAY_BUFFER, individualArrayBuffer);
+			glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STATIC_DRAW);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[0], positions.size() * sizeof(GLfloat), &positions[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[1], color.size() * sizeof(GLubyte), &color[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[2], texCoord.size() * sizeof(GLshort), &texCoord[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[3], normal.size() * sizeof(GLfloat), &normal[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[4], tangent.size() * sizeof(GLfloat), &tangent[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[5], bitangent.size() * sizeof(GLfloat), &bitangent[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[6], boneIndices.size() * sizeof(GLubyte), &boneIndices[0]);
+			glBufferSubData(GL_ARRAY_BUFFER, individualOffsets[7], boneWeights.size() * sizeof(GLubyte), &boneWeights[0]);
+			glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+			//Create the interleaved buffer. This requires some care.
+			//3 attribs.
+			interleavedStrides.reserve(NUM_ATTRIBUTE_VARIATIONS);
+			interleavedOffsets.reserve(TOTAL_ATTRIBUTE_COUNT);
+			std::vector<char> byteBuffer;
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, positions[0], positions.size() / MAX_NUM_VERTICES);
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, color[0], color.size() / MAX_NUM_VERTICES);
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, texCoord[0], texCoord.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[0], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+
+			//4 attribs.
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, normal[0], normal.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[1], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+
+			//5 attribs.
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, tangent[0], tangent.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[2], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+
+			//6 attribs.
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, bitangent[0], bitangent.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[3], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+
+			//7 attribs.
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, boneIndices[0], boneIndices.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[4], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+
+			//8 attribs.
+			interleavedOffsets.push_back(byteBuffer.size());
+			util::AddToInterleaveBuffer(byteBuffer, boneWeights[0], boneWeights.size() / MAX_NUM_VERTICES);
+			interleavedStrides.push_back(byteBuffer.size());
+			util::FillBufferData(interleavedArrayBuffers[5], GL_ARRAY_BUFFER,
+				util::RepeatBuffer(byteBuffer, MAX_NUM_VERTICES), GL_STATIC_DRAW);
+		}
+
+		//Load the shaders.
+		{
+			std::string fragmentShader;
+			{
+				std::ifstream input("manual\\frag.frag", std::ios::binary);
+				if(input)
+					fragmentShader.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
+			}
+
+			for(int attrib = START_ATTRIBUTE_COUNT; attrib < TOTAL_ATTRIBUTE_COUNT + 1; ++attrib)
+			{
+				std::ostringstream buildName;
+				buildName << "manual\\attrib" << attrib << ".vert";
+				std::string name = buildName.str();
+
+				std::ifstream input(name.c_str(), std::ios::binary);
+				std::string vertexShader((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
+
+				try
+				{
+					glutil::LinkProgram(programs[attrib - START_ATTRIBUTE_COUNT], vertexShader, fragmentShader);
+				}
+				catch(std::exception &e)
+				{
+					std::cout << e.what() << std::endl;
+					throw;
+				}
+			}
+		}
+
+
+		glDisable(GL_DEPTH_TEST);
+		glEnable(GL_RASTERIZER_DISCARD);
+
+		glClearColor(0.0, 0.0, 0.0, 0.0);
+		glClearDepth(1.0f);
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		glutSwapBuffers();
+	}
+
+	~TestSuite()
+	{
+		util::DestroyBufferObjects(separateArrayBuffers);
+		glDeleteBuffers(1, &individualArrayBuffer);
+		util::DestroyBufferObjects(interleavedArrayBuffers);
+		glDeleteBuffers(1, &indexBuffer);
+
+		util::DestroyPrograms(programs);
+	}
+
+	std::vector<GLuint> separateArrayBuffers;
+	GLuint individualArrayBuffer;
+	std::vector<GLuint> interleavedArrayBuffers;
+
+	std::vector<int> individualOffsets;
+	std::vector<int> interleavedStrides;
+	std::vector<int> interleavedOffsets;
+
+	std::vector<GLint> attribSize;
+	std::vector<GLenum> attribType;
+	std::vector<GLboolean> attribNormalized;
+
+	std::vector<GLuint> programs;
+
+	GLuint indexBuffer;
+};
+
+//Test for array rendering, individual arrays in separate buffers.
+struct Test_ArrayIndividualSeparate
+{
+	Test_ArrayIndividualSeparate(const TestSuite &suite)
+		: vaos(util::CreateVertexArrays(NUM_ATTRIBUTE_VARIATIONS))
+	{
+		for(int numAttribs = START_ATTRIBUTE_COUNT; numAttribs < (TOTAL_ATTRIBUTE_COUNT + 1); ++numAttribs)
+		{
+			glBindVertexArray(vaos[numAttribs - START_ATTRIBUTE_COUNT]);
+			for(int attrib = 0; attrib < numAttribs; ++attrib)
+			{
+				glEnableVertexAttribArray(attrib);
+				glBindBuffer(GL_ARRAY_BUFFER, suite.separateArrayBuffers[attrib]);
+				glVertexAttribPointer(
+					attrib,
+					suite.attribSize[attrib],
+					suite.attribType[attrib],
+					suite.attribNormalized[attrib],
+					0,
+					0);
+			}
+		}
+
+		glBindVertexArray(0);
+	}
+
+	~Test_ArrayIndividualSeparate()
+	{
+		util::DestroyVertexArrays(vaos);
+	}
+
+	void Execute(const TestSuite &suite, int numAttributes, int vertexCount)
+	{
+		std::vector<GLuint> timer = util::CreateQueries(2);
+		glBindVertexArray(vaos[numAttributes - START_ATTRIBUTE_COUNT]);
+		glUseProgram(suite.programs[numAttributes - START_ATTRIBUTE_COUNT]);
+
+		glBeginQuery(GL_TIME_ELAPSED, timer[0]);
+		glDrawArrays(GL_POINTS, 0, vertexCount);
+		glEndQuery(GL_TIME_ELAPSED);
+
+		glQueryCounter(timer[1], GL_TIMESTAMP);
+		GLint64 issueTime;
+		glGetInteger64v(GL_TIMESTAMP, &issueTime);
+
+		glutSwapBuffers();
+		glFinish();
+
+		GLuint64 elapsedTime;
+		glGetQueryObjectui64v(timer[0], GL_QUERY_RESULT, &elapsedTime);
+
+		GLuint64 completeTime;
+		glGetQueryObjectui64v(timer[1], GL_QUERY_RESULT, &completeTime);
+
+		std::cout << "ArrayIndividualSeparate: Attribute count: " << numAttributes << " Vertices: " << vertexCount << std::endl;
+		std::cout << "\tElapsed time: " << elapsedTime << std::endl;
+		std::cout << "\tIssue-to-complete latency: " << completeTime - issueTime << std::endl;
+		std::cout << std::endl;
+
+		util::DestroyQueries(timer);
+		glBindVertexArray(0);
+		glUseProgram(0);
+	}
+
+	std::vector<GLuint> vaos;
+};
+
+//Test for array rendering, individual arrays in a single buffer.
+struct Test_ArrayIndividualSingle
+{
+	Test_ArrayIndividualSingle(const TestSuite &suite)
+		: vaos(util::CreateVertexArrays(NUM_ATTRIBUTE_VARIATIONS))
+	{
+		glBindBuffer(GL_ARRAY_BUFFER, suite.individualArrayBuffer);
+
+		for(int numAttribs = START_ATTRIBUTE_COUNT; numAttribs < TOTAL_ATTRIBUTE_COUNT; ++numAttribs)
+		{
+			glBindVertexArray(vaos[numAttribs - START_ATTRIBUTE_COUNT]);
+			for(int attrib = 0; attrib < numAttribs; ++attrib)
+			{
+				glEnableVertexAttribArray(attrib);
+				glVertexAttribPointer(
+					attrib,
+					suite.attribSize[attrib],
+					suite.attribType[attrib],
+					suite.attribNormalized[attrib],
+					0,
+					reinterpret_cast<void*>(suite.individualOffsets[attrib]));
+			}
+		}
+
+		glBindVertexArray(0);
+	}
+
+	~Test_ArrayIndividualSingle()
+	{
+		util::DestroyVertexArrays(vaos);
+	}
+
+	void Execute()
+	{
+
+	}
+
+	std::vector<GLuint> vaos;
+};
+
+//Test for array rendering, interleaved arrays.
+struct Test_ArrayInterleaved
+{
+	Test_ArrayInterleaved(const TestSuite &suite)
+		: vaos(util::CreateVertexArrays(NUM_ATTRIBUTE_VARIATIONS))
+	{
+		for(int numAttribs = START_ATTRIBUTE_COUNT; numAttribs < TOTAL_ATTRIBUTE_COUNT; ++numAttribs)
+		{
+			glBindVertexArray(vaos[numAttribs - START_ATTRIBUTE_COUNT]);
+			glBindBuffer(GL_ARRAY_BUFFER, suite.interleavedArrayBuffers[numAttribs - START_ATTRIBUTE_COUNT]);
+			for(int attrib = 0; attrib < numAttribs; ++attrib)
+			{
+				glEnableVertexAttribArray(attrib);
+				glVertexAttribPointer(
+					attrib,
+					suite.attribSize[attrib],
+					suite.attribType[attrib],
+					suite.attribNormalized[attrib],
+					suite.interleavedOffsets[numAttribs - START_ATTRIBUTE_COUNT],
+					reinterpret_cast<void*>(suite.interleavedOffsets[attrib]));
+			}
+		}
+
+		glBindVertexArray(0);
+	}
+
+	~Test_ArrayInterleaved()
+	{
+		util::DestroyVertexArrays(vaos);
+	}
+
+	void Execute()
+	{
+
+	}
+
+	std::vector<GLuint> vaos;
+};
+
+
+void display()
+{
+	try
+	{
+		TestSuite suite;
+		Test_ArrayIndividualSeparate arrayIndivSep(suite);
+		Test_ArrayIndividualSingle arrayIndivSingle(suite);
+		Test_ArrayInterleaved arrayInterleaved(suite);
+
+		arrayIndivSep.Execute(suite, TOTAL_ATTRIBUTE_COUNT, MAX_NUM_VERTICES);
+
+		for(int attribs = START_ATTRIBUTE_COUNT;
+			attribs < START_ATTRIBUTE_COUNT + NUM_ATTRIBUTE_VARIATIONS;
+			++attribs)
+		{
+			arrayIndivSep.Execute(suite, attribs, MAX_NUM_VERTICES);
+			arrayIndivSep.Execute(suite, attribs, MAX_NUM_VERTICES);
+			arrayIndivSep.Execute(suite, attribs, MAX_NUM_VERTICES);
+		}
+	}
+	catch(...)
+	{
+		glutLeaveMainLoop();
+		throw;
+	}
+
+	glutLeaveMainLoop();
+}
+
+int main(int argc, char** argv)
+{
+	glutInit(&argc, argv);
+
+	int width = 640;
+	int height = 480;
+	unsigned int displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL;
+
+	glutInitDisplayMode(displayMode);
+	glutInitContextVersion (3, 3);
+	glutInitContextProfile(GLUT_CORE_PROFILE);
+
+	glutInitWindowSize (width, height); 
+	glutInitWindowPosition (300, 200);
+	int window = glutCreateWindow(argv[0]);
+
+	glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
+
+	glload::LoadFunctions();
+
+//	ShowCaps();
+
+	glutDisplayFunc(display);
+	glutMainLoop();
+
+	return 0;
+}

File tests/premake4.lua

+
+
+dofile "../glsdk/links.lua"
+
+solution "perftests"
+	configurations { "Debug", "Release" }
+
+	defines {"_CRT_SECURE_NO_WARNINGS", "_CRT_SECURE_NO_DEPRECATE", "_SCL_SECURE_NO_WARNINGS", "TIXML_USE_STL"}
+
+	defines {"FREEGLUT_STATIC"}
+	
+	configuration "windows"
+		defines {"WIN32"}
+		
+	configuration "linux"
+		defines {"LOAD_X11"}
+
+	
+project "manual"
+	kind "ConsoleApp"
+	language "c++"
+	
+	files {"util/*.h", "util/*.cpp"}
+	files {"manual/*.h", "manual/*.cpp"}
+
+	includedirs {}
+		
+	--Must be after including framwork... because GCC is stupid.
+	UseLibs("glload", "glutil", "glm", "freeglut")
+	
+	configuration "Debug"
+		defines {"DEBUG", "_DEBUG"}
+		flags "Symbols"
+		targetname("manualD")
+	
+	configuration "Release"
+		defines {"RELEASE", "NDEBUG"};
+		flags {"OptimizeSpeed", "NoFramePointer", "ExtraWarnings", "NoEditAndContinue"};
+		targetname("manual")
+
+	configuration {"windows"}
+		links {"glu32", "opengl32", "gdi32", "winmm", "user32"}
+
+	configuration "linux"
+		links {"GL", "GLU"}
+

File tests/util/CPUTiming.cpp

+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include "CPUTiming.h"
+
+#ifdef WIN32
+#include <windows.h>		// Header File For Windows
+#endif //WIN32
+
+
+namespace util
+{
+#ifdef WIN32
+	double GetPrecisionCPUTimeInSeconds()
+	{
+		LARGE_INTEGER frequency;
+		LARGE_INTEGER currTime;
+
+		QueryPerformanceFrequency(&frequency);
+		QueryPerformanceCounter(&currTime);
+
+		return (double)currTime.QuadPart / (double)frequency.QuadPart;
+	}
+#endif //WIN32
+
+	const int TOUCH_MEMORY_SIZE = 1024 * 1024;
+
+	void EmptyDataCache()
+	{
+		//Touch a *lot* of memory.
+		std::vector<char> theVec;
+		theVec.reserve(TOUCH_MEMORY_SIZE);
+		std::fill_n(std::back_inserter(theVec), TOUCH_MEMORY_SIZE, 1); //Make sure it's touched; no memcpy .
+	}
+}

File tests/util/CPUTiming.h

+
+#ifndef PERFORMANCE_CPU_TIMINGS_H
+#define PERFORMANCE_CPU_TIMINGS_H
+
+namespace util
+{
+	double GetPrecisionCPUTimeInSeconds();
+
+	void EmptyDataCache();
+}
+
+
+#endif //PERFORMANCE_CPU_TIMINGS_H

File tests/util/globj.cpp

+
+
+#include <algorithm>
+#include <iterator>
+#include "globj.h"
+
+
+namespace util
+{
+	GLuint CreateBufferObject()
+	{
+		GLuint buffer;
+		glGenBuffers(1, &buffer);
+		return buffer;
+	}
+
+	std::vector<GLuint> CreateBufferObjects( int numBuffers )
+	{
+		std::vector<GLuint> buffers(numBuffers);
+		glGenBuffers(numBuffers, &buffers[0]);
+		return buffers;
+	}
+
+	void DestroyBufferObjects( const std::vector<GLuint> &buffers )
+	{
+		glDeleteBuffers(buffers.size(), &buffers[0]);
+	}
+
+	std::vector<GLuint> CreateVertexArrays( int numArrays )
+	{
+		std::vector<GLuint> arrays(numArrays);
+		glGenVertexArrays(numArrays, &arrays[0]);
+		return arrays;
+	}
+
+	void DestroyVertexArrays( const std::vector<GLuint> &arrays )
+	{
+		glDeleteVertexArrays(arrays.size(), &arrays[0]);
+	}
+
+	std::vector<GLuint> CreateQueries( int numQueries )
+	{
+		std::vector<GLuint> queries(numQueries);
+		glGenQueries(numQueries, &queries[0]);
+		return queries;
+	}
+
+	void DestroyQueries( const std::vector<GLuint> &queries )
+	{
+		glDeleteQueries(queries.size(), &queries[0]);
+	}
+
+	std::vector<GLuint> CreatePrograms( int numPrograms )
+	{
+		std::vector<GLuint> programs;
+		programs.reserve(numPrograms);
+		std::generate_n(std::back_inserter(programs), numPrograms, glCreateProgram);
+		return programs;
+	}
+
+	void DestroyPrograms( const std::vector<GLuint> &programs )
+	{
+		std::for_each(programs.begin(), programs.end(), glDeleteProgram);
+	}
+}

File tests/util/globj.h

+
+#ifndef PERFORMANCE_OPENGL_OBJECTS_H
+#define PERFORMANCE_OPENGL_OBJECTS_H
+
+#include <vector>
+#include <glload/gl_all.h>
+
+namespace util
+{
+	GLuint CreateBufferObject();
+	std::vector<GLuint> CreateBufferObjects(int numBuffers);
+	void DestroyBufferObjects(const std::vector<GLuint> &buffers);
+
+	std::vector<GLuint> CreateVertexArrays(int numArrays);
+	void DestroyVertexArrays(const std::vector<GLuint> &arrays);
+
+	std::vector<GLuint> CreateQueries(int numQueries);
+	void DestroyQueries(const std::vector<GLuint> &queries);
+
+	std::vector<GLuint> CreatePrograms(int numPrograms);
+	void DestroyPrograms(const std::vector<GLuint> &programs);
+
+	inline std::vector<char> RepeatBuffer(const std::vector<char> &buffer, const int numRepetitions)
+	{
+		std::vector<char> ret;
+		ret.resize(buffer.size() * numRepetitions);
+		for(int loop = 0; loop < numRepetitions; ++loop)
+			memcpy(&ret[loop * (buffer.size())], &buffer[0], buffer.size());
+/*
+		ret.reserve(buffer.size() * numRepetitions);
+		for(int loop = 0; loop < numRepetitions; ++loop)
+			ret.insert(ret.end(), buffer.begin(), buffer.end());
+*/
+
+		return ret;
+	}
+
+	template<typename T>
+	void FillBufferData(GLuint buf, GLenum target, const std::vector<T> &data, GLenum usage)
+	{
+		glBindBuffer(target, buf);
+		glBufferData(target, data.size() * sizeof(T), &data[0], usage);
+		glBindBuffer(target, 0);
+	}
+
+	template<typename T>
+	size_t CalcOffset(const std::vector<T> &data)
+	{
+		return sizeof(T) * data.size();
+	}
+
+	template<typename T>
+	size_t FillBufferSubData(size_t offset, GLuint buf, GLenum target, const std::vector<T> &data)
+	{
+		glBindBuffer(target, buf);
+		glBufferSubData(target, offset, data.size() * sizeof(T), &data[0]);
+		glBindBuffer(target, 0);
+
+		return offset + (data.size() * sizeof(T));
+	}
+
+	//Uses the currently bound buffer.
+	template<typename T>
+	size_t FillBufferSubData(size_t offset, GLenum target, const std::vector<T> &data)
+	{
+		glBufferSubData(target, offset, data.size() * sizeof(T), &data[0]);
+
+		return offset + (data.size() * sizeof(T));
+	}
+
+	template<typename T>
+	void AddToInterleaveBuffer(std::vector<char> &byteBuffer, T value, const int repeat)
+	{
+		size_t elementSize = (((repeat * sizeof(T)) + 4 - 1) / 4) * 4;
+		size_t currLoc = byteBuffer.size();
+		byteBuffer.insert(byteBuffer.end(), elementSize, 0);
+
+		char *buffPtr = &byteBuffer[currLoc];
+
+		for(int loop = 0; loop < repeat; ++loop)
+		{
+			*reinterpret_cast<T*>(buffPtr) = value;
+			buffPtr += sizeof(T);
+		}
+	}
+
+}
+
+#endif //PERFORMANCE_OPENGL_OBJECTS_H

File tests/util/util.h

+
+#ifndef PERFORMANCE_UTILS_H
+#define PERFORMANCE_UTILS_H
+
+#include "globj.h"
+#include "CPUTiming.h"
+
+
+#endif // PERFORMANCE_UTILS_H