Source

GL Profile Suite / tests / interleave_arrays / suite.lua


suite "interleave_arrays"
	desc "Determine how much better interleaved arrays perform compared to non-interleaved and multiple-buffered arrays."
	
	includes "<boost/range.hpp>"
	includes { "<sstream>", "<boost/range/irange.hpp>" }
	
	params
	{
		attribute_count = closed_range(3, 8),
		vertex_count = {25000, 50000, 100000},
	}
	
	timings {"gpu_time", "gpu_latency",}
	executions(3)
	
	variables {
		separateArrayBuffers = "gl list buffer object",
		individualArrayBuffer = "gl buffer object",
		interleavedArrayBuffers = "gl list buffer object",

		individualOffsets = "std::vector<int>",
		interleavedStrides = "std::vector<int>",
		interleavedOffsets = "std::vector<int>",

		attribSize = "std::vector<GLint>",
		attribType = "std::vector<GLenum>",
		attribNormalized = "std::vector<GLboolean>",

		programs = "gl list program",

		indexBuffer = "gl buffer object"
	}
	
	init [[

separateArrayBuffers = util::CreateBufferObjects($attribute_count.max);
glGenBuffers(1, &individualArrayBuffer);
interleavedArrayBuffers = util::CreateBufferObjects($attribute_count.count);
glGenBuffers(1, &indexBuffer);
programs = util::CreatePrograms($attribute_count.count);
]]
	local attribute_list = dofile("attrib_data.lua")

	init [[
attribSize.resize($attribute_count.max);
attribType.resize($attribute_count.max);
attribNormalized.resize($attribute_count.max);]]
	
	--Generate buffer storage.
	init(function(paramIface)
		assert(paramIface.attribute_count.max == #attribute_list, "Need to make sure the attribute list is kept up-to-date with the attribute_count parameter.")
		
		local strlist = {}

		strlist[#strlist + 1] = "{\n"
		
		for index, typedef in ipairs(attribute_list) do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
				"\tattribSize[%i] = %i; attribType[%i] = %s; attribNormalized[%i] = %s;\n",
				cindex, typedef.size,
				cindex, typedef.type,
				cindex, typedef.norm)
		end
		
		strlist[#strlist + 1] = "\n\t//Create separate array buffers\n"
		
		for index, typedef in ipairs(attribute_list) do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
				"\tstd::vector<%s> %s(attribSize[%i] * $vertex_count.max, %s);\n",
				typedef.ctype,
				typedef.name,
				cindex,
				typedef.initVal)
		end
		
		strlist[#strlist + 1] = "\n"
		
		for index, typedef in ipairs(attribute_list) do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
				"\tutil::FillBufferData(separateArrayBuffers[%i], GL_ARRAY_BUFFER, %s, GL_STATIC_DRAW);\n",
				cindex,
				typedef.name)
		end
		
		strlist[#strlist + 1] = "\n\t//Create the individual buffer\n"
		strlist[#strlist + 1] = [[
	individualOffsets.reserve($attribute_count.max);
	int totalBufferSize = 0;
]]
	
		for index, typedef in ipairs(attribute_list) do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format([[
	individualOffsets.push_back(totalBufferSize);
	totalBufferSize += util::CalcOffset(%s);
]]				,
				typedef.name)
		end
		
		strlist[#strlist + 1] = "\n"

		
		strlist[#strlist + 1] = [[
	glBindBuffer(GL_ARRAY_BUFFER, individualArrayBuffer);
	glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STATIC_DRAW);
]]

		for index, typedef in ipairs(attribute_list) do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
				"\tglBufferSubData(GL_ARRAY_BUFFER, individualOffsets[%i], %s.size() * sizeof(%s), &%s[0]);\n",
				cindex,
				typedef.name,
				typedef.ctype,
				typedef.name)
		end

		strlist[#strlist + 1] = "\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n"
		
		strlist[#strlist + 1] = "\n"
		
		
		strlist[#strlist + 1] = [[
	//Create the interleaved buffer
	interleavedStrides.reserve($attribute_count.count);
	interleavedOffsets.reserve($attribute_count.max);
	std::vector<char> byteBuffer; //stores a single vertex worth of data.
]]

		
		for index = 1, paramIface.attribute_count.min - 1 do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
		[[
	interleavedOffsets.push_back(byteBuffer.size());
	util::AddToInterleaveBuffer(byteBuffer, %s[0], %s.size() / $vertex_count.max);
]]			,
			attribute_list[index].name, attribute_list[index].name)
		end
		
		for index, attrib in paramIface.attribute_count.iter() do
			local cindex = index - 1
			strlist[#strlist + 1] = string.format(
		[[
	//%i attribs
	interleavedOffsets.push_back(byteBuffer.size());
	util::AddToInterleaveBuffer(byteBuffer, %s[0], %s.size() / $vertex_count.max);
	interleavedStrides.push_back(byteBuffer.size());
	util::FillBufferData(interleavedArrayBuffers[%i], GL_ARRAY_BUFFER, util::RepeatBuffer(byteBuffer, $vertex_count.max), GL_STATIC_DRAW);

]]			,
			attrib,
			attribute_list[attrib].name, attribute_list[attrib].name,
			cindex)
		end
		
		strlist[#strlist + 1] = "}\n"

		return table.concat(strlist)
	end)
	
	init [[
std::string fragmentShader;
{
	std::ifstream input("frag.frag", std::ios::binary);
	if(input)
		fragmentShader.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
}

BOOST_FOREACH(int attrib, $attribute_count.range())
{
	std::ostringstream buildName;
	buildName << "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 - $attribute_count.min], vertexShader, fragmentShader);
	}
	catch(std::exception &e)
	{
		std::cout << e.what() << std::endl;
		throw;
	}
}]]

test "arrayIndivSep"
	desc "Separate arrays, where each array is within its own buffer object."
	
	flags {--[["finish", "swap"]]}
	render_flags {"discard"}
	
	variables {
		vaos = "gl list vao",
	}
	
	init [[
vaos = util::CreateVertexArrays($attribute_count.count);
BOOST_FOREACH(int numAttribs, $attribute_count.range())
{
	glBindVertexArray(vaos[numAttribs - $attribute_count.min]);
	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);
]]

	execinit [[
glBindVertexArray(vaos[$attribute_count.index]);
glUseProgram(suite.programs[$attribute_count.index]);
]]

	exec [[glDrawArrays(GL_POINTS, 0, $vertex_count.value);
]]


	execfinal [[
glBindVertexArray(0);
glUseProgram(0);
]]