Commits

Jason McKesson committed a947be4

Basic code generation complete. Builds the whole thing.

Comments (0)

Files changed (6)

tests/codegen.lua

 		end
 	end
 	hFile:write("\t}\n")
+
+	hFile:write("};\n");
+end
+
+local function WriteGenerator(hFile, gens, genmode)
+	for _,generator in ipairs(gens) do
+		if(generator[genmode]) then
+			hFile:write(generator[genmode]());
+		end
+	end
+end
+
+local function GetTestTimingGenerators(test)
+	--From least-important to most important.
+	local order = {"gpu_latency", "gpu_time", "cpu_time"}
+
+	local gens = {}
+	for _, timing in ipairs(order) do
+		if(test._suite.timings[timing]) then
+			gens[#gens + 1] = gen[timing]
+		end
+	end
 	
+	local revgens = {}
+	for i = #gens, 1, -1 do
+		revgens[#revgens + 1] = gens[i]
+	end
 	
-	hFile:write("};\n");
+	return gens, revgens;
 end
 
 local function WriteTestClass(hFile, test)
 	hFile:write(", ", gen.GetParamArgDef())
 	hFile:write(")\n\t{\n")
 	
+	local gens, revgens = GetTestTimingGenerators(test)
+	
 	--User initialization first.
 	WriteAndFormatExecStmtsList(hFile, test._suite, test.execinit)
+
+	--Initialize timings.
+	WriteGenerator(hFile, gens, "init");
+	hFile:write("\n");
 	
-	--TODO: Insert timing init code here.
+	WriteGenerator(hFile, gens, "start");
+	hFile:write("\t\t//Time this code.\n");
+	WriteAndFormatExecStmtsList(hFile, test._suite, test.exec)
+	WriteGenerator(hFile, revgens, "stop"); --Stop the timings in reverse order
+	hFile:write("\n");
 	
-	WriteAndFormatExecStmtsList(hFile, test._suite, test.exec)
+	if(test.flags["swap"]) then
+		--TODO: Do different swap when not GLUT.
+		hFile:write("\t\tglutSwapBuffers();\n")
+	end
+	if(test.flags["finish"]) then
+		hFile:write("\t\tglFinish();\n");
+	end
 	
-	--TODO: Insert timing storage and finalization code here.
-	
+	WriteGenerator(hFile, gens, "record");
+	hFile:write("\n");
+
+	WriteGenerator(hFile, gens, "final");
 	WriteAndFormatExecStmtsList(hFile, test._suite, test.execfinal)
-	
+
+
 	hFile:write("\t}\n")
 
 	hFile:write("};\n");
 end
 
+------------------------------------------
+-- Actual testing function
+local function GetLongStringForC(longStr)
+	return "\"" .. longStr .. "\""
+end
+
+
+local function WriteTestFunction(hFile, suite)
+	hFile:write("void ", gen.GetTestingFuncName(), "()\n{\n")
+	hFile:write("\ttry\n") --TODO: Don't do this if not FreeGLUT.
+	hFile:write("\t{\n")
+	
+	--Write the suite/test class instances
+	hFile:write("\t\t", gen.GetSuiteClassname(suite.name), " suite;\n")
+	for testname, test in pairs(suite._tests) do
+		hFile:write("\t\t", gen.GetTestClassname(testname), " ", testname,
+			"(suite);\n")
+	end
+	hFile:write("\n")
+	
+	--Write parameter declarations.
+	hFile:write("\t\tutil::ParamDecl params[] = {")
+	for i, paramname in ipairs(suite._param_array) do
+		hFile:write("{\"", paramname, "\"}")
+		if(i ~= #suite._param_array) then
+			hFile:write(", ")
+		end
+	end
+	hFile:write("};\n")
+	hFile:write("\t\tstd::vector<util::ParamDecl> paramDecl(boost::begin(params), boost::end(params));\n")
+	hFile:write("\n")
+
+	--Write test declarations.
+	hFile:write("\t\tutil::TestDesc testArray[] = {\n")
+	for testname, test in pairs(suite._tests) do
+		hFile:write("\t\t\t{\"", testname, "\", ",
+			GetLongStringForC(test.desc), "},\n")
+	end
+	hFile:write("\t\t};\n")
+	hFile:write("\t\tstd::vector<util::TestDesc> tests(boost::begin(testArray), boost::end(testArray));\n")
+	hFile:write("\n")
+
+	--Build up the list of instances.
+	hFile:write("\t\tstd::vector<int> instValues;\n")
+	for i, paramname in ipairs(suite._param_array) do
+		local varName = "param" .. i;
+		hFile:write(string.rep("\t", i + 1),
+			"BOOST_FOREACH(int ", varName, ", ",
+			gen.GetParamDefVarname(paramname), ".range())\n")
+		hFile:write(string.rep("\t", i + 1), "{\n")
+	end
+	
+	for i, paramname in ipairs(suite._param_array) do
+		local varName = "param" .. i;
+		hFile:write(string.rep("\t", #suite._param_array + 2),
+			string.format("instValues.push_back(%s)", varName), ";\n")
+	end
+
+	for i, paramname in ipairs(suite._param_array) do
+		hFile:write(string.rep("\t", #suite._param_array - i + 2), "}\n")
+	end
+	hFile:write("\n")
+	
+	--TODO: Get the number of executions from the command line.
+	hFile:write("\t\tutil::Report report(",
+		suite.executions, ", instValues, paramDecl, tests);\n")
+	hFile:write("\n")
+
+	--Perform the timings.
+	hFile:write([[
+		int instIx = 0;
+		boost::container::vector<ParamValue> paramValues;
+]])
+
+	hFile:write(string.format("\t\tparamValues.reserve(%i);\n", #suite._param_array))
+
+	--For each test, loop over each parameter.
+	for testname, test in pairs(suite._tests) do
+		for i, paramname in ipairs(suite._param_array) do
+			local varName = "paramIx" .. i;
+			local tabs = string.rep("\t", i + 1)
+			hFile:write(tabs,
+				"BOOST_FOREACH(int ", varName, ", boost::irange(0, ",
+				gen.GetParamDefVarname(paramname), ".count))\n")
+			hFile:write(tabs, "{\n")
+			hFile:write(tabs, "\t",
+				string.format("paramValues.emplace_back(%s, %s);\n",
+					gen.GetParamDefVarname(paramname), varName))
+		end
+		
+		local tabs = string.rep("\t", #suite._param_array + 2)
+		hFile:write(tabs,
+			string.format([[BOOST_FOREACH(int execCounter, boost::irange(0, %s))]],
+				suite.executions), "\n")
+		hFile:write(tabs, "{\n")
+		if(test.render_flags["discard"]) then
+			hFile:write(tabs, "\tglEnable(GL_RASTERIZER_DISCARD);\n");
+		end
+		hFile:write(tabs, "\t",
+			string.format([[util::TestDatum datum(report, "%s", instIx, execCounter);]],
+				testname), "\n")
+		hFile:write(tabs, "\t",
+			string.format([[%s.%s(datum, suite, &paramValues[0]);]],
+				testname, gen.GetExecuteFuncName()), "\n")
+
+		if(test.render_flags["discard"]) then
+			hFile:write(tabs, "\tglDisable(GL_RASTERIZER_DISCARD);\n");
+		end
+		hFile:write(tabs, "}\n")
+		hFile:write(tabs, "++instIx;\n")
+
+		for i, paramname in ipairs(suite._param_array) do
+			local tabs = string.rep("\t", #suite._param_array - i + 2)
+			hFile:write(tabs, "\tparamValues.pop_back();\n")
+			hFile:write(tabs, "}\n")
+		end
+	end
+	hFile:write("\n")
+	
+	--Deliver the report
+	--TODO: Make this write to a file if one is provided.
+	hFile:write("\t\treport.WriteToLua(std::cout, \"",
+		suite.name, "\", ", GetLongStringForC(suite.desc), ", \n")
+	--TODO: Get the various strings from OpenGL.
+	hFile:write("\t\t\t", [["GL Version", "GL Vendor", "GL Renderer"]])
+	hFile:write(");\n")
+	
+	hFile:write("\t}\n");
+	--TODO: Don't do this if not FreeGLUT
+	hFile:write([[
+	catch(...)
+	{
+		glutLeaveMainLoop();
+		throw;
+	}
+]])
+
+	--TODO: Don't do this if not FreeGLUT
+	hFile:write([[	glutLeaveMainLoop();
+]])
+	
+	
+	hFile:write("}\n");	
+end
+
+
+------------------------------------------
+-- Main startup
+local function WriteMainGlut(hFile, suite)
+	hFile:write("\tglutInit(&argc, argv);\n")
+
+	hFile:write "\n"
+	
+	--TODO: allow suite to determine resolution.
+	hFile:write[[
+	int width = 640;
+	int height = 480;
+]]
+
+	hFile:write "\n"
+	
+	--TODO: allow suite to determine these parameters
+	hFile:write [[
+	unsigned int displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL;
+]]
+	
+	hFile:write "\n"
+	
+	--TODO: Determine version and core profile manually.
+	hFile:write [[
+	glutInitDisplayMode(displayMode);
+	glutInitContextVersion (3, 3);
+	glutInitContextProfile(GLUT_CORE_PROFILE);
+]]
+
+	hFile:write "\n"
+
+	hFile:write [[
+	glutInitWindowSize (width, height); 
+	glutInitWindowPosition (300, 200);
+	int window = glutCreateWindow(argv[0]);
+
+	glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
+
+	glload::LoadFunctions();
+]]
+
+	hFile:write "\n"
+	
+	hFile:write(string.format("\tglutDisplayFunc(%s);\n", gen.GetTestingFuncName()))
+	
+	hFile:write "\n"
+	
+	hFile:write [[
+	glutMainLoop();
+
+	return 0;
+]]
+end
+
+local function WriteMainFunction(hFile, suite)
+	hFile:write [[
+	int main(int argc, char** argv)
+{
+]]
+	--TODO: alternate main form for GLFW.
+	WriteMainGlut(hFile, suite)
+	hFile:write("}\n")
+end
+
+
+------------------------------------------
+-- Primary codegeneration function
 function codegen.gencode()
 	for name, suite in pairs(codegen._suites) do
 		PreprocessSuite(suite)
 		
 		for testname, test in pairs(suite._tests) do	
 			WriteTestClass(hFile, test)
+			hFile:write("\n")
 		end
 		
+		hFile:write("\n")
+
+		--Write testing function
+		WriteTestFunction(hFile, suite)
+		
+		hFile:write("\n")
+
+		--Write main function
+		WriteMainFunction(hFile, suite)
+		
 		
 		hFile:close()
 	end

tests/generate.lua

 end
 
 function gen.GetParamArgVarname()
-	return "parameters"
+	return "test_parameters"
 end
 
 function gen.GetParamArgDef()
 	return string.format("%s[%i]", gen.GetParamArgVarname(), paramIndex)
 end
 
+function gen.GetExecuteFuncName()
+	return "Execute"
+end
+
+function gen.GetSuiteFuncParam(suite)
+	return "const " .. gen.GetSuiteClassname(suite.name) .. " &suite"
+end
+
+function gen.GetTestingFuncName()
+	return "test_display"
+end
+
 function gen.WritePreamble(hFile, suite_name)
 	hFile:write([=[
 	/* Here's some preamble text. */
 		"<vector>",
 		"<iostream>",
 		"<fstream>",
+		"<boost/container/vector.hpp>",
 		"<boost/range/irange.hpp>",
 		"<boost/range/iterator_range.hpp>",
 		"<boost/foreach.hpp>",
 	}
 end
 
-function gen.GetExecuteFuncName()
-	return "Execute"
-end
-
-function gen.GetSuiteFuncParam(suite)
-	return "const " .. gen.GetSuiteClassname(suite.name) .. " &suite"
-end
-
 function gen.GetParamDefStructDefinition()
 	return[[
 struct ParamDefinition
 };]]
 end
 
+--GPU timing.
+gen.gpu_time =
+{}
+
+function gen.gpu_time.init()
+	return [[
+		GLuint test_gpu_time_query = util::CreateQuery();
+]]
+end
+
+function gen.gpu_time.start()
+	return [[
+		glBeginQuery(GL_TIME_ELAPSED, test_gpu_time_query);
+]]
+end
+
+function gen.gpu_time.stop()
+	return [[
+		glEndQuery(GL_TIME_ELAPSED);
+]]
+end
+
+function gen.gpu_time.record()
+	return [[
+		{
+			GLuint64 elapsedTime;
+			glGetQueryObjectui64v(test_gpu_time_query, GL_QUERY_RESULT, &elapsedTime);
+
+			datum.SetValue(util::DATUM_GPU_ELAPSED, double(elapsedTime) / 1000000.0);
+		}
+]]
+end
+
+function gen.gpu_time.final()
+	return [[
+		glDeleteQueries(1, &test_gpu_time_query);
+]]
+end
+
+--GPU latency.
+gen.gpu_latency =
+{}
+
+function gen.gpu_latency.init()
+	return [[
+		GLuint test_gpu_latency_query = util::CreateQuery();
+]]
+end
+
+function gen.gpu_latency.stop()
+	return [[
+		glQueryCounter(test_gpu_latency_query, GL_TIMESTAMP);
+		GLint64 test_issue_time;
+		glGetInteger64v(GL_TIMESTAMP, &test_issue_time);
+]]
+end
+
+function gen.gpu_latency.record()
+	return [[
+		{
+			GLuint64 complete_time;
+			glGetQueryObjectui64v(test_gpu_latency_query, GL_QUERY_RESULT, &complete_time);
+
+			datum.SetValue(util::DATUM_GPU_LATENCY, double(complete_time - test_issue_time) / 1000000.0);
+		}
+]]
+end
+
+function gen.gpu_latency.final()
+	return [[
+		glDeleteQueries(1, &test_gpu_latency_query);
+]]
+end
+
 return gen

tests/interleave_arrays/suite.lua

 BOOST_FOREACH(int attrib, $attribute_count.range())
 {
 	std::ostringstream buildName;
-	buildName << "manual\\attrib" << attrib << ".vert";
+	buildName << "attrib" << attrib << ".vert";
 	std::string name = buildName.str();
 
 	std::ifstream input(name.c_str(), std::ios::binary);
 test "arrayIndivSep"
 	desc "Separate arrays, where each array is within its own buffer object."
 	
-	flags {"finish", "swap"}
+	flags {--[["finish", "swap"]]}
 	render_flags {"discard"}
 	
 	variables {
 glUseProgram(suite.programs[$attribute_count.index]);
 ]]
 
-	exec [[glDrawArrays(GL_POINTS, 0, $vertex_count.value);]]
+	exec [[glDrawArrays(GL_POINTS, 0, $vertex_count.value);
+]]
 
 
 	execfinal [[

tests/manual/main.cpp

 
 	void Execute(util::TestDatum &datum, const TestSuite &suite, int numAttributes, int vertexCount)
 	{
-
+		
 	}
 
 	std::vector<GLuint> vaos;

tests/util/globj.cpp

 		glDeleteVertexArrays(arrays.size(), &arrays[0]);
 	}
 
+	GLuint CreateQuery()
+	{
+		GLuint query;
+		glGenQueries(1, &query);
+		return query;
+	}
+
 	std::vector<GLuint> CreateQueries( int numQueries )
 	{
 		std::vector<GLuint> queries(numQueries);

tests/util/globj.h

 	std::vector<GLuint> CreateVertexArrays(int numArrays);
 	void DestroyVertexArrays(const std::vector<GLuint> &arrays);
 
+	GLuint CreateQuery();
 	std::vector<GLuint> CreateQueries(int numQueries);
 	void DestroyQueries(const std::vector<GLuint> &queries);