1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Single-program test case wrapper for ShaderPerformanceMeasurer.
22 *//*--------------------------------------------------------------------*/
23
24#include "glsShaderPerformanceCase.hpp"
25#include "tcuRenderTarget.hpp"
26#include "deStringUtil.hpp"
27#include "deMath.h"
28
29#include "glwFunctions.hpp"
30#include "glwEnums.hpp"
31
32using tcu::Vec4;
33using tcu::TestLog;
34using namespace glw; // GL types
35
36namespace deqp
37{
38namespace gls
39{
40
41ShaderPerformanceCase::ShaderPerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, PerfCaseType caseType)
42	: tcu::TestCase		(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
43	, m_renderCtx		(renderCtx)
44	, m_caseType		(caseType)
45	, m_program			(DE_NULL)
46	, m_measurer		(renderCtx, caseType)
47{
48}
49
50ShaderPerformanceCase::~ShaderPerformanceCase (void)
51{
52	ShaderPerformanceCase::deinit();
53}
54
55void ShaderPerformanceCase::setGridSize (int gridW, int gridH)
56{
57	m_measurer.setGridSize(gridW, gridH);
58}
59
60void ShaderPerformanceCase::setViewportSize (int width, int height)
61{
62	m_measurer.setViewportSize(width, height);
63}
64
65void ShaderPerformanceCase::setVertexFragmentRatio (float fragmentsPerVertices)
66{
67	const float	eps			= 0.01f;
68	int			gridW		= 255;
69	int			gridH		= 255;
70	int			viewportW	= m_renderCtx.getRenderTarget().getWidth();
71	int			viewportH	= m_renderCtx.getRenderTarget().getHeight();
72
73	for (int i = 0; i < 10; i++)
74	{
75		int		numVert	= (gridW+1)*(gridH+1);
76		int		numFrag	= viewportW*viewportH;
77		float	ratio	= (float)numFrag / (float)numVert;
78
79		if (de::abs(ratio - fragmentsPerVertices) < eps)
80			break;
81		else if (ratio < fragmentsPerVertices)
82		{
83			// Not enough fragments.
84			numVert = deRoundFloatToInt32((float)numFrag / fragmentsPerVertices);
85
86			while ((gridW+1)*(gridH+1) > numVert)
87			{
88				if (gridW > gridH)
89					gridW -= 1;
90				else
91					gridH -= 1;
92			}
93		}
94		else
95		{
96			// Not enough vertices.
97			numFrag = deRoundFloatToInt32((float)numVert * fragmentsPerVertices);
98
99			while (viewportW*viewportH > numFrag)
100			{
101				if (viewportW > viewportH)
102					viewportW -= 1;
103				else
104					viewportH -= 1;
105			}
106		}
107	}
108
109	float finalRatio = (float)(viewportW*viewportH) / (float)((gridW+1)*(gridH+1));
110	m_testCtx.getLog() << TestLog::Message << "Requested fragment/vertex-ratio: " << de::floatToString(fragmentsPerVertices, 2) << "\n"
111										   << "Computed fragment/vertex-ratio: " << de::floatToString(finalRatio, 2)
112					   << TestLog::EndMessage;
113
114	setGridSize(gridW, gridH);
115	setViewportSize(viewportW, viewportH);
116}
117
118static void logRenderTargetInfo (TestLog& log, const tcu::RenderTarget& renderTarget)
119{
120	log << TestLog::Section("RenderTarget", "Render target")
121		<< TestLog::Message << "size: " << renderTarget.getWidth() << "x" << renderTarget.getHeight() << TestLog::EndMessage
122		<< TestLog::Message << "bits:"
123							<< " R" << renderTarget.getPixelFormat().redBits
124							<< " G" << renderTarget.getPixelFormat().greenBits
125							<< " B" << renderTarget.getPixelFormat().blueBits
126							<< " A" << renderTarget.getPixelFormat().alphaBits
127							<< " D" << renderTarget.getDepthBits()
128							<< " S" << renderTarget.getStencilBits()
129							<< TestLog::EndMessage;
130
131	if (renderTarget.getNumSamples() != 0)
132		log << TestLog::Message << renderTarget.getNumSamples() << "x MSAA" << TestLog::EndMessage;
133	else
134		log << TestLog::Message << "No MSAA" << TestLog::EndMessage;
135
136	log << TestLog::EndSection;
137}
138
139void ShaderPerformanceCase::init (void)
140{
141	tcu::TestLog& log = m_testCtx.getLog();
142
143	m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(m_vertShaderSource, m_fragShaderSource));
144
145	if (m_program->isOk())
146	{
147		const int initialCallCount = m_initialCalibration ? m_initialCalibration->initialNumCalls : 1;
148		logRenderTargetInfo(log, m_renderCtx.getRenderTarget());
149		m_measurer.init(m_program->getProgram(), m_attributes, initialCallCount);
150		m_measurer.logParameters(log);
151		log << *m_program;
152	}
153	else
154	{
155		log << *m_program;
156		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
157		return; // Skip rest of init.
158	}
159
160	setupProgram(m_program->getProgram());
161	setupRenderState();
162}
163
164void ShaderPerformanceCase::deinit (void)
165{
166	delete m_program;
167	m_program = DE_NULL;
168
169	m_measurer.deinit();
170}
171
172void ShaderPerformanceCase::setupProgram (deUint32 program)
173{
174	DE_UNREF(program);
175}
176
177void ShaderPerformanceCase::setupRenderState (void)
178{
179}
180
181ShaderPerformanceCase::IterateResult ShaderPerformanceCase::iterate (void)
182{
183	DE_ASSERT(m_program);
184
185	if (!m_program->isOk()) // This happens when compilation failed in init().
186		return STOP;
187
188	m_measurer.iterate();
189
190	if (m_measurer.isFinished())
191	{
192		m_measurer.logMeasurementInfo(m_testCtx.getLog());
193
194		if (m_initialCalibration)
195			m_initialCalibration->initialNumCalls = de::max(1, m_measurer.getFinalCallCount());
196
197		const ShaderPerformanceMeasurer::Result result = m_measurer.getResult();
198		reportResult(result.megaVertPerSec, result.megaFragPerSec);
199		return STOP;
200	}
201	else
202		return CONTINUE;
203}
204
205void ShaderPerformanceCase::reportResult (float mvertPerSecond, float mfragPerSecond)
206{
207	float result = 0.0f;
208	switch (m_caseType)
209	{
210		case CASETYPE_VERTEX:	result = mvertPerSecond;	break;
211		case CASETYPE_FRAGMENT:	result = mfragPerSecond;	break;
212		case CASETYPE_BALANCED:	result = mfragPerSecond;	break;
213		default:
214			DE_ASSERT(false);
215	}
216
217	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str());
218}
219
220ShaderPerformanceCaseGroup::ShaderPerformanceCaseGroup (tcu::TestContext& testCtx, const char* name, const char* description)
221	: TestCaseGroup					(testCtx, name, description)
222	, m_initialCalibrationStorage	(new ShaderPerformanceCase::InitialCalibration)
223{
224}
225
226void ShaderPerformanceCaseGroup::addChild (ShaderPerformanceCase* perfCase)
227{
228	perfCase->setCalibrationInitialParamStorage(m_initialCalibrationStorage);
229	TestCaseGroup::addChild(perfCase);
230}
231
232} // gls
233} // deqp
234