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 
32 using tcu::Vec4;
33 using tcu::TestLog;
34 using namespace glw; // GL types
35 
36 namespace deqp
37 {
38 namespace gls
39 {
40 
ShaderPerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,PerfCaseType caseType)41 ShaderPerformanceCase::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 
~ShaderPerformanceCase(void)50 ShaderPerformanceCase::~ShaderPerformanceCase (void)
51 {
52 	ShaderPerformanceCase::deinit();
53 }
54 
setGridSize(int gridW,int gridH)55 void ShaderPerformanceCase::setGridSize (int gridW, int gridH)
56 {
57 	m_measurer.setGridSize(gridW, gridH);
58 }
59 
setViewportSize(int width,int height)60 void ShaderPerformanceCase::setViewportSize (int width, int height)
61 {
62 	m_measurer.setViewportSize(width, height);
63 }
64 
setVertexFragmentRatio(float fragmentsPerVertices)65 void 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 
logRenderTargetInfo(TestLog & log,const tcu::RenderTarget & renderTarget)118 static 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 
init(void)139 void 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 
deinit(void)164 void ShaderPerformanceCase::deinit (void)
165 {
166 	delete m_program;
167 	m_program = DE_NULL;
168 
169 	m_measurer.deinit();
170 }
171 
setupProgram(deUint32 program)172 void ShaderPerformanceCase::setupProgram (deUint32 program)
173 {
174 	DE_UNREF(program);
175 }
176 
setupRenderState(void)177 void ShaderPerformanceCase::setupRenderState (void)
178 {
179 }
180 
iterate(void)181 ShaderPerformanceCase::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 
reportResult(float mvertPerSecond,float mfragPerSecond)205 void 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 
ShaderPerformanceCaseGroup(tcu::TestContext & testCtx,const char * name,const char * description)220 ShaderPerformanceCaseGroup::ShaderPerformanceCaseGroup (tcu::TestContext& testCtx, const char* name, const char* description)
221 	: TestCaseGroup					(testCtx, name, description)
222 	, m_initialCalibrationStorage	(new ShaderPerformanceCase::InitialCalibration)
223 {
224 }
225 
addChild(ShaderPerformanceCase * perfCase)226 void ShaderPerformanceCaseGroup::addChild (ShaderPerformanceCase* perfCase)
227 {
228 	perfCase->setCalibrationInitialParamStorage(m_initialCalibrationStorage);
229 	TestCaseGroup::addChild(perfCase);
230 }
231 
232 } // gls
233 } // deqp
234