• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Compiler test case.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsShaderLibraryCase.hpp"
25 
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 
29 #include "tcuStringTemplate.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluDrawUtil.hpp"
33 #include "gluContextInfo.hpp"
34 #include "gluStrUtil.hpp"
35 
36 #include "glwFunctions.hpp"
37 #include "glwEnums.hpp"
38 
39 #include "deRandom.hpp"
40 #include "deInt32.h"
41 #include "deMath.h"
42 #include "deString.h"
43 #include "deStringUtil.hpp"
44 #include "deSharedPtr.hpp"
45 
46 #include <map>
47 #include <vector>
48 #include <string>
49 #include <sstream>
50 
51 using namespace std;
52 using namespace tcu;
53 using namespace glu;
54 
55 namespace deqp
56 {
57 namespace gls
58 {
59 namespace sl
60 {
61 
62 enum
63 {
64 	VIEWPORT_WIDTH		= 128,
65 	VIEWPORT_HEIGHT		= 128
66 };
67 
usesShaderInoutQualifiers(glu::GLSLVersion version)68 static inline bool usesShaderInoutQualifiers (glu::GLSLVersion version)
69 {
70 	switch (version)
71 	{
72 		case glu::GLSL_VERSION_100_ES:
73 		case glu::GLSL_VERSION_130:
74 		case glu::GLSL_VERSION_140:
75 		case glu::GLSL_VERSION_150:
76 			return false;
77 
78 		default:
79 			return true;
80 	}
81 }
82 
supportsFragmentHighp(glu::GLSLVersion version)83 static inline bool supportsFragmentHighp (glu::GLSLVersion version)
84 {
85 	return version != glu::GLSL_VERSION_100_ES;
86 }
87 
ValueBlock(void)88 ShaderCase::ValueBlock::ValueBlock (void)
89 	: arrayLength(0)
90 {
91 }
92 
CaseRequirement(void)93 ShaderCase::CaseRequirement::CaseRequirement (void)
94 	: m_type						(REQUIREMENTTYPE_LAST)
95 	, m_supportedExtensionNdx		(-1)
96 	, m_effectiveShaderStageFlags	(-1)
97 	, m_enumName					(-1)
98 	, m_referenceValue				(-1)
99 {
100 }
101 
createAnyExtensionRequirement(const std::vector<std::string> & requirements,deUint32 effectiveShaderStageFlags)102 ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createAnyExtensionRequirement (const std::vector<std::string>& requirements, deUint32 effectiveShaderStageFlags)
103 {
104 	CaseRequirement retVal;
105 
106 	retVal.m_type = REQUIREMENTTYPE_EXTENSION;
107 	retVal.m_extensions = requirements;
108 	retVal.m_effectiveShaderStageFlags = effectiveShaderStageFlags;
109 
110 	return retVal;
111 }
112 
createLimitRequirement(deUint32 enumName,int ref)113 ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createLimitRequirement (deUint32 enumName, int ref)
114 {
115 	CaseRequirement retVal;
116 
117 	retVal.m_type = REQUIREMENTTYPE_IMPLEMENTATION_LIMIT;
118 	retVal.m_enumName = enumName;
119 	retVal.m_referenceValue = ref;
120 
121 	return retVal;
122 }
123 
createFullGLSLES100SpecificationRequirement(void)124 ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createFullGLSLES100SpecificationRequirement (void)
125 {
126 	CaseRequirement retVal;
127 
128 	retVal.m_type = REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC;
129 
130 	return retVal;
131 }
132 
checkRequirements(glu::RenderContext & renderCtx,const glu::ContextInfo & contextInfo)133 void ShaderCase::CaseRequirement::checkRequirements (glu::RenderContext& renderCtx, const glu::ContextInfo& contextInfo)
134 {
135 	DE_UNREF(renderCtx);
136 
137 	switch (m_type)
138 	{
139 		case REQUIREMENTTYPE_EXTENSION:
140 		{
141 			for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx)
142 			{
143 				if (contextInfo.isExtensionSupported(m_extensions[ndx].c_str()))
144 				{
145 					m_supportedExtensionNdx = ndx;
146 					return;
147 				}
148 			}
149 
150 			// no extension(s). Make a nice output
151 			{
152 				std::ostringstream extensionList;
153 
154 				for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx)
155 				{
156 					if (!extensionList.str().empty())
157 						extensionList << ", ";
158 					extensionList << m_extensions[ndx];
159 				}
160 
161 				if (m_extensions.size() == 1)
162 					throw tcu::NotSupportedError("Test requires extension " + extensionList.str());
163 				else
164 					throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str());
165 			}
166 
167 			// cannot be reached
168 		}
169 
170 		case REQUIREMENTTYPE_IMPLEMENTATION_LIMIT:
171 		{
172 			const glw::Functions&	gl		= renderCtx.getFunctions();
173 			glw::GLint				value	= 0;
174 			glw::GLenum				error;
175 
176 			gl.getIntegerv(m_enumName, &value);
177 			error = gl.getError();
178 
179 			if (error != GL_NO_ERROR)
180 				throw tcu::TestError("Query for " + de::toString(glu::getGettableStateStr(m_enumName)) +  " generated " + de::toString(glu::getErrorStr(error)));
181 
182 			if (!(value > m_referenceValue))
183 				throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(m_enumName)) + " (" + de::toString(value) + ") > " + de::toString(m_referenceValue));
184 
185 			return;
186 		}
187 
188 		case REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC:
189 		{
190 			// cannot be queried
191 			return;
192 		}
193 
194 		default:
195 			DE_ASSERT(false);
196 	}
197 }
198 
ShaderCaseSpecification(void)199 ShaderCase::ShaderCaseSpecification::ShaderCaseSpecification (void)
200 	: expectResult	(EXPECT_LAST)
201 	, targetVersion	(glu::GLSL_VERSION_LAST)
202 	, caseType		(CASETYPE_COMPLETE)
203 {
204 }
205 
generateSharedSourceVertexCase(ExpectResult expectResult_,glu::GLSLVersion targetVersion_,const std::vector<ValueBlock> & values,const std::string & sharedSource)206 ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource)
207 {
208 	ShaderCaseSpecification retVal;
209 	retVal.expectResult		= expectResult_;
210 	retVal.targetVersion	= targetVersion_;
211 	retVal.caseType			= CASETYPE_VERTEX_ONLY;
212 	retVal.valueBlocks		= values;
213 	retVal.vertexSources.push_back(sharedSource);
214 	return retVal;
215 }
216 
generateSharedSourceFragmentCase(ExpectResult expectResult_,glu::GLSLVersion targetVersion_,const std::vector<ValueBlock> & values,const std::string & sharedSource)217 ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource)
218 {
219 	ShaderCaseSpecification retVal;
220 	retVal.expectResult		= expectResult_;
221 	retVal.targetVersion	= targetVersion_;
222 	retVal.caseType			= CASETYPE_FRAGMENT_ONLY;
223 	retVal.valueBlocks		= values;
224 	retVal.fragmentSources.push_back(sharedSource);
225 	return retVal;
226 }
227 
228 class BeforeDrawValidator : public glu::DrawUtilCallback
229 {
230 public:
231 	enum TargetType
232 	{
233 		TARGETTYPE_PROGRAM = 0,
234 		TARGETTYPE_PIPELINE,
235 
236 		TARGETTYPE_LAST
237 	};
238 
239 							BeforeDrawValidator	(const glw::Functions& gl, glw::GLuint target, TargetType targetType);
240 
241 	void					beforeDrawCall		(void);
242 
243 	const std::string&		getInfoLog			(void) const;
244 	glw::GLint				getValidateStatus	(void) const;
245 
246 private:
247 	const glw::Functions&	m_gl;
248 	const glw::GLuint		m_target;
249 	const TargetType		m_targetType;
250 
251 	glw::GLint				m_validateStatus;
252 	std::string				m_logMessage;
253 };
254 
BeforeDrawValidator(const glw::Functions & gl,glw::GLuint target,TargetType targetType)255 BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType)
256 	: m_gl				(gl)
257 	, m_target			(target)
258 	, m_targetType		(targetType)
259 	, m_validateStatus	(-1)
260 {
261 	DE_ASSERT(targetType < TARGETTYPE_LAST);
262 }
263 
beforeDrawCall(void)264 void BeforeDrawValidator::beforeDrawCall (void)
265 {
266 	glw::GLint					bytesWritten	= 0;
267 	glw::GLint					infoLogLength;
268 	std::vector<glw::GLchar>	logBuffer;
269 	int							stringLength;
270 
271 	// validate
272 	if (m_targetType == TARGETTYPE_PROGRAM)
273 		m_gl.validateProgram(m_target);
274 	else if (m_targetType == TARGETTYPE_PIPELINE)
275 		m_gl.validateProgramPipeline(m_target);
276 	else
277 		DE_ASSERT(false);
278 
279 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate");
280 
281 	// check status
282 	m_validateStatus = -1;
283 
284 	if (m_targetType == TARGETTYPE_PROGRAM)
285 		m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
286 	else if (m_targetType == TARGETTYPE_PIPELINE)
287 		m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
288 	else
289 		DE_ASSERT(false);
290 
291 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status");
292 	TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE);
293 
294 	// read log
295 
296 	infoLogLength = 0;
297 
298 	if (m_targetType == TARGETTYPE_PROGRAM)
299 		m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
300 	else if (m_targetType == TARGETTYPE_PIPELINE)
301 		m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
302 	else
303 		DE_ASSERT(false);
304 
305 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length");
306 
307 	if (infoLogLength <= 0)
308 	{
309 		m_logMessage.clear();
310 		return;
311 	}
312 
313 	logBuffer.resize(infoLogLength + 2, '0'); // +1 for zero terminator (infoLogLength should include it, but better play it safe), +1 to make sure buffer is always larger
314 
315 	if (m_targetType == TARGETTYPE_PROGRAM)
316 		m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
317 	else if (m_targetType == TARGETTYPE_PIPELINE)
318 		m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
319 	else
320 		DE_ASSERT(false);
321 
322 	// just ignore bytesWritten to be safe, find the null terminator
323 	stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin());
324 	m_logMessage.assign(&logBuffer[0], stringLength);
325 }
326 
getInfoLog(void) const327 const std::string& BeforeDrawValidator::getInfoLog (void) const
328 {
329 	return m_logMessage;
330 }
331 
getValidateStatus(void) const332 glw::GLint BeforeDrawValidator::getValidateStatus (void) const
333 {
334 	return m_validateStatus;
335 }
336 
337 // ShaderCase.
338 
ShaderCase(tcu::TestContext & testCtx,RenderContext & renderCtx,const glu::ContextInfo & contextInfo,const char * name,const char * description,const ShaderCaseSpecification & specification)339 ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification)
340 	: tcu::TestCase				(testCtx, name, description)
341 	, m_renderCtx				(renderCtx)
342 	, m_contextInfo				(contextInfo)
343 	, m_caseType				(specification.caseType)
344 	, m_expectResult			(specification.expectResult)
345 	, m_targetVersion			(specification.targetVersion)
346 	, m_separatePrograms		(false)
347 	, m_valueBlocks				(specification.valueBlocks)
348 {
349 	if (m_caseType == CASETYPE_VERTEX_ONLY)
350 	{
351 		// case generated from "both" target, vertex case
352 		DE_ASSERT(specification.vertexSources.size() == 1);
353 		DE_ASSERT(specification.fragmentSources.empty());
354 		DE_ASSERT(specification.tessCtrlSources.empty());
355 		DE_ASSERT(specification.tessEvalSources.empty());
356 		DE_ASSERT(specification.geometrySources.empty());
357 	}
358 	else if (m_caseType == CASETYPE_FRAGMENT_ONLY)
359 	{
360 		// case generated from "both" target, fragment case
361 		DE_ASSERT(specification.vertexSources.empty());
362 		DE_ASSERT(specification.fragmentSources.size() == 1);
363 		DE_ASSERT(specification.tessCtrlSources.empty());
364 		DE_ASSERT(specification.tessEvalSources.empty());
365 		DE_ASSERT(specification.geometrySources.empty());
366 	}
367 
368 	if (m_expectResult == EXPECT_BUILD_SUCCESSFUL)
369 	{
370 		// Shader is never executed. Presense of input/output values is likely an error
371 		DE_ASSERT(m_valueBlocks.empty());
372 	}
373 
374 	// single program object
375 	{
376 		ProgramObject program;
377 		program.spec.requirements		= specification.requirements;
378 		program.spec.vertexSources		= specification.vertexSources;
379 		program.spec.fragmentSources	= specification.fragmentSources;
380 		program.spec.tessCtrlSources	= specification.tessCtrlSources;
381 		program.spec.tessEvalSources	= specification.tessEvalSources;
382 		program.spec.geometrySources	= specification.geometrySources;
383 
384 		m_programs.push_back(program);
385 	}
386 }
387 
ShaderCase(tcu::TestContext & testCtx,RenderContext & renderCtx,const glu::ContextInfo & contextInfo,const char * name,const char * description,const PipelineCaseSpecification & specification)388 ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const PipelineCaseSpecification& specification)
389 	: tcu::TestCase				(testCtx, name, description)
390 	, m_renderCtx				(renderCtx)
391 	, m_contextInfo				(contextInfo)
392 	, m_caseType				(specification.caseType)
393 	, m_expectResult			(specification.expectResult)
394 	, m_targetVersion			(specification.targetVersion)
395 	, m_separatePrograms		(true)
396 	, m_valueBlocks				(specification.valueBlocks)
397 {
398 	deUint32 totalActiveMask = 0;
399 
400 	DE_ASSERT(m_caseType == CASETYPE_COMPLETE);
401 
402 	// validate
403 
404 	for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx)
405 	{
406 		// program with an active stage must contain executable code for that stage
407 		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_VERTEX))						== 0) || !specification.programs[pipelineProgramNdx].vertexSources.empty());
408 		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_FRAGMENT))					== 0) || !specification.programs[pipelineProgramNdx].fragmentSources.empty());
409 		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_CONTROL))		== 0) || !specification.programs[pipelineProgramNdx].tessCtrlSources.empty());
410 		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION))	== 0) || !specification.programs[pipelineProgramNdx].tessEvalSources.empty());
411 		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_GEOMETRY))					== 0) || !specification.programs[pipelineProgramNdx].geometrySources.empty());
412 
413 		// no two programs with with the same stage active
414 		DE_ASSERT((totalActiveMask & specification.programs[pipelineProgramNdx].activeStageBits) == 0);
415 		totalActiveMask |= specification.programs[pipelineProgramNdx].activeStageBits;
416 	}
417 
418 	// create ProgramObjects
419 
420 	for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx)
421 	{
422 		ProgramObject program;
423 		program.spec = specification.programs[pipelineProgramNdx];
424 		m_programs.push_back(program);
425 	}
426 }
427 
~ShaderCase(void)428 ShaderCase::~ShaderCase (void)
429 {
430 }
431 
init(void)432 void ShaderCase::init (void)
433 {
434 	// If no value blocks given, use an empty one.
435 	if (m_valueBlocks.empty())
436 		m_valueBlocks.push_back(ValueBlock());
437 
438 	// Use first value block to specialize shaders.
439 	const ValueBlock& valueBlock = m_valueBlocks[0];
440 
441 	// \todo [2010-04-01 petri] Check that all value blocks have matching values.
442 
443 	// prepare programs
444 	for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
445 	{
446 		// Check requirements
447 		for (int ndx = 0; ndx < (int)m_programs[programNdx].spec.requirements.size(); ++ndx)
448 			m_programs[programNdx].spec.requirements[ndx].checkRequirements(m_renderCtx, m_contextInfo);
449 
450 		// Generate specialized shader sources.
451 		if (m_caseType == CASETYPE_COMPLETE)
452 		{
453 			// all shaders specified separately
454 			specializeVertexShaders		(m_programs[programNdx].programSources,	m_programs[programNdx].spec.vertexSources,		valueBlock,	m_programs[programNdx].spec.requirements);
455 			specializeFragmentShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.fragmentSources,	valueBlock,	m_programs[programNdx].spec.requirements);
456 			specializeGeometryShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.geometrySources,	valueBlock,	m_programs[programNdx].spec.requirements);
457 			specializeTessControlShaders(m_programs[programNdx].programSources,	m_programs[programNdx].spec.tessCtrlSources,	valueBlock,	m_programs[programNdx].spec.requirements);
458 			specializeTessEvalShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.tessEvalSources,	valueBlock,	m_programs[programNdx].spec.requirements);
459 		}
460 		else if (m_caseType == CASETYPE_VERTEX_ONLY)
461 		{
462 			DE_ASSERT(m_programs.size() == 1);
463 			DE_ASSERT(!m_separatePrograms);
464 
465 			// case generated from "both" target, vertex case
466 			m_programs[0].programSources << glu::VertexSource(specializeVertexShader(m_programs[0].spec.vertexSources[0].c_str(), valueBlock));
467 			m_programs[0].programSources << glu::FragmentSource(genFragmentShader(valueBlock));
468 		}
469 		else if (m_caseType == CASETYPE_FRAGMENT_ONLY)
470 		{
471 			DE_ASSERT(m_programs.size() == 1);
472 			DE_ASSERT(!m_separatePrograms);
473 
474 			// case generated from "both" target, fragment case
475 			m_programs[0].programSources << glu::VertexSource(genVertexShader(valueBlock));
476 			m_programs[0].programSources << glu::FragmentSource(specializeFragmentShader(m_programs[0].spec.fragmentSources[0].c_str(), valueBlock));
477 		}
478 
479 		m_programs[programNdx].programSources << glu::ProgramSeparable(m_separatePrograms);
480 	}
481 
482 	// log the expected result
483 	switch (m_expectResult)
484 	{
485 		case EXPECT_PASS:
486 			// Don't write anything
487 			break;
488 
489 		case EXPECT_COMPILE_FAIL:
490 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
491 			break;
492 
493 		case EXPECT_LINK_FAIL:
494 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
495 			break;
496 
497 		case EXPECT_COMPILE_LINK_FAIL:
498 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
499 			break;
500 
501 		case EXPECT_VALIDATION_FAIL:
502 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
503 			break;
504 
505 		case EXPECT_BUILD_SUCCESSFUL:
506 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
507 			break;
508 
509 		default:
510 			DE_ASSERT(false);
511 			break;
512 	}
513 
514 	// sanity of arguments
515 
516 	if (anyProgramRequiresFullGLSLES100Specification())
517 	{
518 		// makes only sense in tests where shader compiles
519 		DE_ASSERT(m_expectResult == EXPECT_PASS				||
520 				  m_expectResult == EXPECT_VALIDATION_FAIL	||
521 				  m_expectResult == EXPECT_BUILD_SUCCESSFUL);
522 
523 		// only makes sense for ES 100 programs
524 		DE_ASSERT(m_targetVersion == glu::GLSL_VERSION_100_ES);
525 	}
526 }
527 
setUniformValue(const glw::Functions & gl,const std::vector<deUint32> & pipelinePrograms,const std::string & name,const ShaderCase::Value & val,int arrayNdx,tcu::TestLog & log)528 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const ShaderCase::Value& val, int arrayNdx, tcu::TestLog& log)
529 {
530 	bool foundAnyMatch = false;
531 
532 	for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
533 	{
534 		const int scalarSize	= getDataTypeScalarSize(val.dataType);
535 		const int loc			= gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
536 		const int elemNdx		= (val.arrayLength == 1) ? (0) : (arrayNdx * scalarSize);
537 
538 		if (loc == -1)
539 			continue;
540 
541 		foundAnyMatch = true;
542 
543 		DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat));
544 		DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint));
545 
546 		gl.useProgram(pipelinePrograms[programNdx]);
547 
548 		switch (val.dataType)
549 		{
550 			case TYPE_FLOAT:		gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);						break;
551 			case TYPE_FLOAT_VEC2:	gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);						break;
552 			case TYPE_FLOAT_VEC3:	gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);						break;
553 			case TYPE_FLOAT_VEC4:	gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);						break;
554 			case TYPE_FLOAT_MAT2:	gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
555 			case TYPE_FLOAT_MAT3:	gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
556 			case TYPE_FLOAT_MAT4:	gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
557 			case TYPE_INT:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
558 			case TYPE_INT_VEC2:		gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
559 			case TYPE_INT_VEC3:		gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
560 			case TYPE_INT_VEC4:		gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
561 			case TYPE_BOOL:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
562 			case TYPE_BOOL_VEC2:	gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
563 			case TYPE_BOOL_VEC3:	gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
564 			case TYPE_BOOL_VEC4:	gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
565 			case TYPE_UINT:			gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
566 			case TYPE_UINT_VEC2:	gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
567 			case TYPE_UINT_VEC3:	gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
568 			case TYPE_UINT_VEC4:	gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
569 			case TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
570 			case TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
571 			case TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
572 			case TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
573 			case TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
574 			case TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
575 
576 			case TYPE_SAMPLER_2D:
577 			case TYPE_SAMPLER_CUBE:
578 				DE_ASSERT(!"implement!");
579 				break;
580 
581 			default:
582 				DE_ASSERT(false);
583 		}
584 	}
585 
586 	if (!foundAnyMatch)
587 		log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
588 }
589 
isTessellationPresent(void) const590 bool ShaderCase::isTessellationPresent (void) const
591 {
592 	if (m_separatePrograms)
593 	{
594 		const deUint32 tessellationBits =	(1 << glu::SHADERTYPE_TESSELLATION_CONTROL)		|
595 											(1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
596 
597 		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
598 			if (m_programs[programNdx].spec.activeStageBits & tessellationBits)
599 				return true;
600 		return false;
601 	}
602 	else
603 		return	!m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
604 				!m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
605 }
606 
anyProgramRequiresFullGLSLES100Specification(void) const607 bool ShaderCase::anyProgramRequiresFullGLSLES100Specification (void) const
608 {
609 	for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
610 	for (int requirementNdx = 0; requirementNdx < (int)m_programs[programNdx].spec.requirements.size(); ++requirementNdx)
611 	{
612 		if (m_programs[programNdx].spec.requirements[requirementNdx].getType() == CaseRequirement::REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC)
613 			return true;
614 	}
615 	return false;
616 }
617 
checkPixels(Surface & surface,int minX,int maxX,int minY,int maxY)618 bool ShaderCase::checkPixels (Surface& surface, int minX, int maxX, int minY, int maxY)
619 {
620 	TestLog&	log				= m_testCtx.getLog();
621 	bool		allWhite		= true;
622 	bool		allBlack		= true;
623 	bool		anyUnexpected	= false;
624 
625 	DE_ASSERT((maxX > minX) && (maxY > minY));
626 
627 	for (int y = minY; y <= maxY; y++)
628 	{
629 		for (int x = minX; x <= maxX; x++)
630 		{
631 			RGBA		pixel		 = surface.getPixel(x, y);
632 			// Note: we really do not want to involve alpha in the check comparison
633 			// \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
634 			bool		isWhite		 = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255);
635 			bool		isBlack		 = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0);
636 
637 			allWhite		= allWhite && isWhite;
638 			allBlack		= allBlack && isBlack;
639 			anyUnexpected	= anyUnexpected || (!isWhite && !isBlack);
640 		}
641 	}
642 
643 	if (!allWhite)
644 	{
645 		if (anyUnexpected)
646 			log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
647 		else if (!allBlack)
648 			log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
649 
650 		return false;
651 	}
652 	return true;
653 }
654 
execute(void)655 bool ShaderCase::execute (void)
656 {
657 	const float										quadSize				= 1.0f;
658 	static const float								s_positions[4*4]		=
659 	{
660 		-quadSize, -quadSize, 0.0f, 1.0f,
661 		-quadSize, +quadSize, 0.0f, 1.0f,
662 		+quadSize, -quadSize, 0.0f, 1.0f,
663 		+quadSize, +quadSize, 0.0f, 1.0f
664 	};
665 
666 	static const deUint16							s_indices[2*3]			=
667 	{
668 		0, 1, 2,
669 		1, 3, 2
670 	};
671 
672 	TestLog&										log						= m_testCtx.getLog();
673 	const glw::Functions&							gl						= m_renderCtx.getFunctions();
674 
675 	// Compute viewport.
676 	const tcu::RenderTarget&						renderTarget			= m_renderCtx.getRenderTarget();
677 	de::Random										rnd						(deStringHash(getName()));
678 	const int										width					= deMin32(renderTarget.getWidth(),	VIEWPORT_WIDTH);
679 	const int										height					= deMin32(renderTarget.getHeight(),	VIEWPORT_HEIGHT);
680 	const int										viewportX				= rnd.getInt(0, renderTarget.getWidth()  - width);
681 	const int										viewportY				= rnd.getInt(0, renderTarget.getHeight() - height);
682 	const int										numVerticesPerDraw		= 4;
683 	const bool										tessellationPresent		= isTessellationPresent();
684 	const bool										requiresFullGLSLES100	= anyProgramRequiresFullGLSLES100Specification();
685 
686 	bool											allCompilesOk			= true;
687 	bool											allLinksOk				= true;
688 	const char*										failReason				= DE_NULL;
689 
690 	deUint32										vertexProgramID			= -1;
691 	std::vector<deUint32>							pipelineProgramIDs;
692 	std::vector<de::SharedPtr<glu::ShaderProgram> >	programs;
693 	de::SharedPtr<glu::ProgramPipeline>				programPipeline;
694 
695 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
696 
697 	if (!m_separatePrograms)
698 	{
699 		de::SharedPtr<glu::ShaderProgram>	program		(new glu::ShaderProgram(m_renderCtx, m_programs[0].programSources));
700 
701 		vertexProgramID = program->getProgram();
702 		pipelineProgramIDs.push_back(program->getProgram());
703 		programs.push_back(program);
704 
705 		// Check that compile/link results are what we expect.
706 
707 		DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
708 		for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
709 			if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
710 				allCompilesOk = false;
711 
712 		if (!program->getProgramInfo().linkOk)
713 			allLinksOk = false;
714 
715 		log << *program;
716 	}
717 	else
718 	{
719 		// Separate programs
720 		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
721 		{
722 			de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, m_programs[programNdx].programSources));
723 
724 			if (m_programs[programNdx].spec.activeStageBits & (1 << glu::SHADERTYPE_VERTEX))
725 				vertexProgramID = program->getProgram();
726 
727 			pipelineProgramIDs.push_back(program->getProgram());
728 			programs.push_back(program);
729 
730 			// Check that compile/link results are what we expect.
731 
732 			DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
733 			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
734 				if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
735 					allCompilesOk = false;
736 
737 			if (!program->getProgramInfo().linkOk)
738 				allLinksOk = false;
739 
740 			// Log program and active stages
741 			{
742 				const tcu::ScopedLogSection	section		(log, "Program", "Program " + de::toString(programNdx+1));
743 				tcu::MessageBuilder			builder		(&log);
744 				bool						firstStage	= true;
745 
746 				builder << "Pipeline uses stages: ";
747 				for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
748 				{
749 					if (m_programs[programNdx].spec.activeStageBits & (1 << stage))
750 					{
751 						if (!firstStage)
752 							builder << ", ";
753 						builder << glu::getShaderTypeName((glu::ShaderType)stage);
754 						firstStage = true;
755 					}
756 				}
757 				builder << tcu::TestLog::EndMessage;
758 
759 				log << *program;
760 			}
761 		}
762 	}
763 
764 	switch (m_expectResult)
765 	{
766 		case EXPECT_PASS:
767 		case EXPECT_VALIDATION_FAIL:
768 		case EXPECT_BUILD_SUCCESSFUL:
769 			if (!allCompilesOk)
770 				failReason = "expected shaders to compile and link properly, but failed to compile.";
771 			else if (!allLinksOk)
772 				failReason = "expected shaders to compile and link properly, but failed to link.";
773 			break;
774 
775 		case EXPECT_COMPILE_FAIL:
776 			if (allCompilesOk && !allLinksOk)
777 				failReason = "expected compilation to fail, but shaders compiled and link failed.";
778 			else if (allCompilesOk)
779 				failReason = "expected compilation to fail, but shaders compiled correctly.";
780 			break;
781 
782 		case EXPECT_LINK_FAIL:
783 			if (!allCompilesOk)
784 				failReason = "expected linking to fail, but unable to compile.";
785 			else if (allLinksOk)
786 				failReason = "expected linking to fail, but passed.";
787 			break;
788 
789 		case EXPECT_COMPILE_LINK_FAIL:
790 			if (allCompilesOk && allLinksOk)
791 				failReason = "expected compile or link to fail, but passed.";
792 			break;
793 
794 		default:
795 			DE_ASSERT(false);
796 			return false;
797 	}
798 
799 	if (failReason != DE_NULL)
800 	{
801 		// \todo [2010-06-07 petri] These should be handled in the test case?
802 		log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
803 
804 		if (requiresFullGLSLES100)
805 		{
806 			log	<< TestLog::Message
807 				<< "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
808 				<< TestLog::EndMessage;
809 
810 			if (allCompilesOk && !allLinksOk)
811 			{
812 				// Used features are detectable at compile time. If implementation parses shader
813 				// at link time, report it as quality warning.
814 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
815 			}
816 			else
817 				m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
818 		}
819 		else if (m_expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
820 		{
821 			// If implementation parses shader at link time, report it as quality warning.
822 			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
823 		}
824 		else
825 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
826 		return false;
827 	}
828 
829 	// Return if shader is not intended to be run
830 	if (m_expectResult == EXPECT_COMPILE_FAIL		||
831 		m_expectResult == EXPECT_COMPILE_LINK_FAIL	||
832 		m_expectResult == EXPECT_LINK_FAIL			||
833 		m_expectResult == EXPECT_BUILD_SUCCESSFUL)
834 		return true;
835 
836 	// Setup viewport.
837 	gl.viewport(viewportX, viewportY, width, height);
838 
839 	if (m_separatePrograms)
840 	{
841 		programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
842 
843 		// Setup pipeline
844 		gl.bindProgramPipeline(programPipeline->getPipeline());
845 		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
846 		{
847 			deUint32 shaderFlags = 0;
848 			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
849 				if (m_programs[programNdx].spec.activeStageBits & (1 << stage))
850 					shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
851 
852 			programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
853 		}
854 
855 		programPipeline->activeShaderProgram(vertexProgramID);
856 		GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
857 	}
858 	else
859 	{
860 		// Start using program
861 		gl.useProgram(vertexProgramID);
862 		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
863 	}
864 
865 	// Fetch location for positions positions.
866 	int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
867 	if (positionLoc == -1)
868 	{
869 		string errStr = string("no location found for attribute 'dEQP_Position'");
870 		TCU_FAIL(errStr.c_str());
871 	}
872 
873 	// Iterate all value blocks.
874 	for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++)
875 	{
876 		const ValueBlock&	valueBlock		= m_valueBlocks[blockNdx];
877 
878 		// always render at least one pass even if there is no input/output data
879 		const int			numRenderPasses	= (valueBlock.arrayLength == 0) ? (1) : (valueBlock.arrayLength);
880 
881 		// Iterate all array sub-cases.
882 		for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
883 		{
884 			int							numValues			= (int)valueBlock.values.size();
885 			vector<VertexArrayBinding>	vertexArrays;
886 			int							attribValueNdx		= 0;
887 			vector<vector<float> >		attribValues		(numValues);
888 			glw::GLenum					postDrawError;
889 			BeforeDrawValidator			beforeDrawValidator	(gl,
890 															 (m_separatePrograms) ? (programPipeline->getPipeline())			: (vertexProgramID),
891 															 (m_separatePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE)	: (BeforeDrawValidator::TARGETTYPE_PROGRAM));
892 
893 			vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
894 
895 			// Collect VA pointer for inputs
896 			for (int valNdx = 0; valNdx < numValues; valNdx++)
897 			{
898 				const ShaderCase::Value&	val			= valueBlock.values[valNdx];
899 				const char* const			valueName	= val.valueName.c_str();
900 				const DataType				dataType	= val.dataType;
901 				const int					scalarSize	= getDataTypeScalarSize(val.dataType);
902 
903 				if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
904 				{
905 					// Replicate values four times.
906 					std::vector<float>& scalars = attribValues[attribValueNdx++];
907 					scalars.resize(numVerticesPerDraw * scalarSize);
908 					if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
909 					{
910 						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
911 							for (int ndx = 0; ndx < scalarSize; ndx++)
912 								scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
913 					}
914 					else
915 					{
916 						// convert to floats.
917 						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
918 						{
919 							for (int ndx = 0; ndx < scalarSize; ndx++)
920 							{
921 								float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
922 								DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
923 								scalars[repNdx*scalarSize + ndx] = v;
924 							}
925 						}
926 					}
927 
928 					// Attribute name prefix.
929 					string attribPrefix = "";
930 					// \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
931 					if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
932 						attribPrefix = "a_";
933 
934 					// Input always given as attribute.
935 					string attribName = attribPrefix + valueName;
936 					int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
937 					if (attribLoc == -1)
938 					{
939 						log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
940 						continue;
941 					}
942 
943 					if (isDataTypeMatrix(dataType))
944 					{
945 						int numCols = getDataTypeMatrixNumColumns(dataType);
946 						int numRows = getDataTypeMatrixNumRows(dataType);
947 						DE_ASSERT(scalarSize == numCols*numRows);
948 
949 						for (int i = 0; i < numCols; i++)
950 							vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*sizeof(float), &scalars[i * numRows]));
951 					}
952 					else
953 					{
954 						DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
955 						vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
956 					}
957 
958 					GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
959 				}
960 			}
961 
962 			GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
963 
964 			// set uniform values for outputs (refs).
965 			for (int valNdx = 0; valNdx < numValues; valNdx++)
966 			{
967 				const ShaderCase::Value&	val			= valueBlock.values[valNdx];
968 				const char* const			valueName	= val.valueName.c_str();
969 
970 				if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
971 				{
972 					// Set reference value.
973 					string refName = string("ref_") + valueName;
974 					setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
975 					GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
976 				}
977 				else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM)
978 				{
979 					setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
980 					GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
981 				}
982 			}
983 
984 			// Clear.
985 			gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
986 			gl.clear(GL_COLOR_BUFFER_BIT);
987 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
988 
989 			// Use program or pipeline
990 			if (m_separatePrograms)
991 				gl.useProgram(0);
992 			else
993 				gl.useProgram(vertexProgramID);
994 
995 			// Draw.
996 			if (tessellationPresent)
997 			{
998 				gl.patchParameteri(GL_PATCH_VERTICES, 3);
999 				GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
1000 			}
1001 
1002 			draw(m_renderCtx,
1003 				 vertexProgramID,
1004 				 (int)vertexArrays.size(),
1005 				 &vertexArrays[0],
1006 				 (tessellationPresent) ?
1007 					(pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
1008 					(pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
1009 				 (m_expectResult == EXPECT_VALIDATION_FAIL) ?
1010 					(&beforeDrawValidator) :
1011 					(DE_NULL));
1012 
1013 			postDrawError = gl.getError();
1014 
1015 			if (m_expectResult == EXPECT_PASS)
1016 			{
1017 				// Read back results.
1018 				Surface			surface			(width, height);
1019 				const float		w				= s_positions[3];
1020 				const int		minY			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * height + 1.0f);
1021 				const int		maxY			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * height - 0.5f);
1022 				const int		minX			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * width + 1.0f);
1023 				const int		maxX			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * width - 0.5f);
1024 
1025 				GLU_EXPECT_NO_ERROR(postDrawError, "draw");
1026 
1027 				glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
1028 				GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
1029 
1030 				if (!checkPixels(surface, minX, maxX, minY, maxY))
1031 				{
1032 					log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx+1) << " of " <<  (int)m_valueBlocks.size()
1033 											<< ", sub-case " << arrayNdx+1 << " of " << valueBlock.arrayLength << "):"
1034 						<< TestLog::EndMessage;
1035 
1036 					log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
1037 					dumpValues(valueBlock, arrayNdx);
1038 
1039 					// Dump image on failure.
1040 					log << TestLog::Image("Result", "Rendered result image", surface);
1041 
1042 					gl.useProgram(0);
1043 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1044 					return false;
1045 				}
1046 			}
1047 			else if (m_expectResult == EXPECT_VALIDATION_FAIL)
1048 			{
1049 				log	<< TestLog::Message
1050 					<< "Draw call generated error: "
1051 					<< glu::getErrorStr(postDrawError) << " "
1052 					<< ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
1053 					<< "Validate status: "
1054 					<< glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
1055 					<< ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
1056 					<< "Info log: "
1057 					<< ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
1058 					<< TestLog::EndMessage;
1059 
1060 				// test result
1061 
1062 				if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
1063 				{
1064 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
1065 					return false;
1066 				}
1067 
1068 				if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
1069 				{
1070 					if (postDrawError == GL_NO_ERROR)
1071 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
1072 					else if (postDrawError == GL_INVALID_OPERATION)
1073 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
1074 					else
1075 						DE_ASSERT(false);
1076 					return false;
1077 				}
1078 				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
1079 				{
1080 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
1081 					return false;
1082 				}
1083 				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
1084 				{
1085 					// Validation does not depend on input values, no need to test all values
1086 					return true;
1087 				}
1088 				else
1089 					DE_ASSERT(false);
1090 			}
1091 			else
1092 				DE_ASSERT(false);
1093 		}
1094 	}
1095 
1096 	gl.useProgram(0);
1097 	if (m_separatePrograms)
1098 		gl.bindProgramPipeline(0);
1099 
1100 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
1101 	return true;
1102 }
1103 
iterate(void)1104 TestCase::IterateResult ShaderCase::iterate (void)
1105 {
1106 	// Initialize state to pass.
1107 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1108 
1109 	bool executeOk = execute();
1110 
1111 	DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
1112 	DE_UNREF(executeOk);
1113 	return TestCase::STOP;
1114 }
1115 
generateExtensionStatements(std::ostringstream & buf,const std::vector<ShaderCase::CaseRequirement> & requirements,glu::ShaderType type)1116 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<ShaderCase::CaseRequirement>& requirements, glu::ShaderType type)
1117 {
1118 	for (int ndx = 0; ndx < (int)requirements.size(); ++ndx)
1119 		if (requirements[ndx].getType() == ShaderCase::CaseRequirement::REQUIREMENTTYPE_EXTENSION &&
1120 			(requirements[ndx].getAffectedExtensionStageFlags() & (1 << (deUint32)type)) != 0)
1121 			buf << "#extension " << requirements[ndx].getSupportedExtension() << " : require\n";
1122 }
1123 
1124 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations
injectExtensionRequirements(const std::string & baseCode,glu::ShaderType shaderType,const std::vector<ShaderCase::CaseRequirement> & requirements)1125 static std::string injectExtensionRequirements (const std::string& baseCode, glu::ShaderType shaderType, const std::vector<ShaderCase::CaseRequirement>& requirements)
1126 {
1127 	std::istringstream	baseCodeBuf(baseCode);
1128 	std::ostringstream	resultBuf;
1129 	std::string			line;
1130 	bool				firstNonPreprocessorLine = true;
1131 	std::ostringstream	extensions;
1132 
1133 	generateExtensionStatements(extensions, requirements, shaderType);
1134 
1135 	// skip if no requirements
1136 	if (extensions.str().empty())
1137 		return baseCode;
1138 
1139 	while (std::getline(baseCodeBuf, line))
1140 	{
1141 		// begins with '#'?
1142 		const std::string::size_type	firstNonWhitespace		= line.find_first_not_of("\t ");
1143 		const bool						isPreprocessorDirective	= (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#');
1144 
1145 		// Inject #extensions
1146 		if (!isPreprocessorDirective && firstNonPreprocessorLine)
1147 		{
1148 			firstNonPreprocessorLine = false;
1149 			resultBuf << extensions.str();
1150 		}
1151 
1152 		resultBuf << line << "\n";
1153 	}
1154 
1155 	return resultBuf.str();
1156 }
1157 
1158 // This functions builds a matching vertex shader for a 'both' case, when
1159 // the fragment shader is being tested.
1160 // We need to build attributes and varyings for each 'input'.
genVertexShader(const ValueBlock & valueBlock) const1161 string ShaderCase::genVertexShader (const ValueBlock& valueBlock) const
1162 {
1163 	ostringstream	res;
1164 	const bool		usesInout	= usesShaderInoutQualifiers(m_targetVersion);
1165 	const char*		vtxIn		= usesInout ? "in"	: "attribute";
1166 	const char*		vtxOut		= usesInout ? "out"	: "varying";
1167 
1168 	res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
1169 
1170 	// Declarations (position + attribute/varying for each input).
1171 	res << "precision highp float;\n";
1172 	res << "precision highp int;\n";
1173 	res << "\n";
1174 	res << vtxIn << " highp vec4 dEQP_Position;\n";
1175 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1176 	{
1177 		const ShaderCase::Value& val = valueBlock.values[ndx];
1178 		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1179 		{
1180 			DataType	floatType	= getDataTypeFloatScalars(val.dataType);
1181 			const char*	typeStr		= getDataTypeName(floatType);
1182 			res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n";
1183 
1184 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1185 				res << vtxOut << " " << typeStr << " " << val.valueName << ";\n";
1186 			else
1187 				res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n";
1188 		}
1189 	}
1190 	res << "\n";
1191 
1192 	// Main function.
1193 	// - gl_Position = dEQP_Position;
1194 	// - for each input: write attribute directly to varying
1195 	res << "void main()\n";
1196 	res << "{\n";
1197 	res << "	gl_Position = dEQP_Position;\n";
1198 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1199 	{
1200 		const ShaderCase::Value& val = valueBlock.values[ndx];
1201 		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1202 		{
1203 			const string& name = val.valueName;
1204 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1205 				res << "	" << name << " = a_" << name << ";\n";
1206 			else
1207 				res << "	v_" << name << " = a_" << name << ";\n";
1208 		}
1209 	}
1210 
1211 	res << "}\n";
1212 	return res.str();
1213 }
1214 
genCompareFunctions(ostringstream & stream,const ShaderCase::ValueBlock & valueBlock,bool useFloatTypes)1215 static void genCompareFunctions (ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes)
1216 {
1217 	bool cmpTypeFound[TYPE_LAST];
1218 	for (int i = 0; i < TYPE_LAST; i++)
1219 		cmpTypeFound[i] = false;
1220 
1221 	for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
1222 	{
1223 		const ShaderCase::Value& val = valueBlock.values[valueNdx];
1224 		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1225 			cmpTypeFound[(int)val.dataType] = true;
1226 	}
1227 
1228 	if (useFloatTypes)
1229 	{
1230 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
1231 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
1232 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
1233 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
1234 		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (float a, int b)  { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n";
1235 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
1236 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
1237 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
1238 		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n";
1239 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
1240 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
1241 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
1242 	}
1243 	else
1244 	{
1245 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (bool a, bool b)   { return (a == b); }\n";
1246 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
1247 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
1248 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
1249 		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (int a, int b)     { return (a == b); }\n";
1250 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
1251 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
1252 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
1253 		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (uint a, uint b)   { return (a == b); }\n";
1254 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
1255 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
1256 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
1257 	}
1258 
1259 	if (cmpTypeFound[TYPE_FLOAT])		stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
1260 	if (cmpTypeFound[TYPE_FLOAT_VEC2])	stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1261 	if (cmpTypeFound[TYPE_FLOAT_VEC3])	stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1262 	if (cmpTypeFound[TYPE_FLOAT_VEC4])	stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1263 
1264 	if (cmpTypeFound[TYPE_FLOAT_MAT2])		stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1265 	if (cmpTypeFound[TYPE_FLOAT_MAT2X3])	stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1266 	if (cmpTypeFound[TYPE_FLOAT_MAT2X4])	stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1267 	if (cmpTypeFound[TYPE_FLOAT_MAT3X2])	stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1268 	if (cmpTypeFound[TYPE_FLOAT_MAT3])		stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1269 	if (cmpTypeFound[TYPE_FLOAT_MAT3X4])	stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1270 	if (cmpTypeFound[TYPE_FLOAT_MAT4X2])	stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
1271 	if (cmpTypeFound[TYPE_FLOAT_MAT4X3])	stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
1272 	if (cmpTypeFound[TYPE_FLOAT_MAT4])		stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";
1273 }
1274 
genCompareOp(ostringstream & output,const char * dstVec4Var,const ShaderCase::ValueBlock & valueBlock,const char * nonFloatNamePrefix,const char * checkVarName)1275 static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName)
1276 {
1277 	bool isFirstOutput = true;
1278 
1279 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1280 	{
1281 		const ShaderCase::Value&	val			= valueBlock.values[ndx];
1282 		const char*					valueName	= val.valueName.c_str();
1283 
1284 		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1285 		{
1286 			// Check if we're only interested in one variable (then skip if not the right one).
1287 			if (checkVarName && !deStringEqual(valueName, checkVarName))
1288 				continue;
1289 
1290 			// Prefix.
1291 			if (isFirstOutput)
1292 			{
1293 				output << "bool RES = ";
1294 				isFirstOutput = false;
1295 			}
1296 			else
1297 				output << "RES = RES && ";
1298 
1299 			// Generate actual comparison.
1300 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1301 				output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n";
1302 			else
1303 				output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n";
1304 		}
1305 		// \note Uniforms are already declared in shader.
1306 	}
1307 
1308 	if (isFirstOutput)
1309 		output << dstVec4Var << " = vec4(1.0);\n";	// \todo [petri] Should we give warning if not expect-failure case?
1310 	else
1311 		output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
1312 }
1313 
genFragmentShader(const ValueBlock & valueBlock) const1314 string ShaderCase::genFragmentShader (const ValueBlock& valueBlock) const
1315 {
1316 	ostringstream	shader;
1317 	const bool		usesInout		= usesShaderInoutQualifiers(m_targetVersion);
1318 	const bool		customColorOut	= usesInout;
1319 	const char*		fragIn			= usesInout ? "in" : "varying";
1320 	const char*		prec			= supportsFragmentHighp(m_targetVersion) ? "highp" : "mediump";
1321 
1322 	shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
1323 
1324 	shader << "precision " << prec << " float;\n";
1325 	shader << "precision " << prec << " int;\n";
1326 	shader << "\n";
1327 
1328 	if (customColorOut)
1329 	{
1330 		shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1331 		shader << "\n";
1332 	}
1333 
1334 	genCompareFunctions(shader, valueBlock, true);
1335 	shader << "\n";
1336 
1337 	// Declarations (varying, reference for each output).
1338 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1339 	{
1340 		const ShaderCase::Value& val = valueBlock.values[ndx];
1341 		DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1342 		const char*	floatTypeStr	= getDataTypeName(floatType);
1343 		const char*	refTypeStr		= getDataTypeName(val.dataType);
1344 
1345 		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1346 		{
1347 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1348 				shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n";
1349 			else
1350 				shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n";
1351 
1352 			shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n";
1353 		}
1354 	}
1355 
1356 	shader << "\n";
1357 	shader << "void main()\n";
1358 	shader << "{\n";
1359 
1360 	shader << "	";
1361 	genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL);
1362 
1363 	shader << "}\n";
1364 	return shader.str();
1365 }
1366 
1367 // Specialize a shader for the vertex shader test case.
specializeVertexShader(const char * src,const ValueBlock & valueBlock) const1368 string ShaderCase::specializeVertexShader (const char* src, const ValueBlock& valueBlock) const
1369 {
1370 	ostringstream	decl;
1371 	ostringstream	setup;
1372 	ostringstream	output;
1373 	const bool		usesInout	= usesShaderInoutQualifiers(m_targetVersion);
1374 	const char*		vtxIn		= usesInout ? "in"	: "attribute";
1375 	const char*		vtxOut		= usesInout ? "out"	: "varying";
1376 
1377 	// generated from "both" case
1378 	DE_ASSERT(m_caseType == CASETYPE_VERTEX_ONLY);
1379 
1380 	// Output (write out position).
1381 	output << "gl_Position = dEQP_Position;\n";
1382 
1383 	// Declarations (position + attribute for each input, varying for each output).
1384 	decl << vtxIn << " highp vec4 dEQP_Position;\n";
1385 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1386 	{
1387 		const ShaderCase::Value& val = valueBlock.values[ndx];
1388 		const char*	valueName		= val.valueName.c_str();
1389 		DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1390 		const char*	floatTypeStr	= getDataTypeName(floatType);
1391 		const char*	refTypeStr		= getDataTypeName(val.dataType);
1392 
1393 		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1394 		{
1395 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1396 			{
1397 				decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n";
1398 			}
1399 			else
1400 			{
1401 				decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n";
1402 				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n";
1403 			}
1404 		}
1405 		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1406 		{
1407 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1408 				decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n";
1409 			else
1410 			{
1411 				decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n";
1412 				decl << refTypeStr << " " << valueName << ";\n";
1413 
1414 				output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n";
1415 			}
1416 		}
1417 	}
1418 
1419 	// Shader specialization.
1420 	map<string, string> params;
1421 	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
1422 	params.insert(pair<string, string>("SETUP", setup.str()));
1423 	params.insert(pair<string, string>("OUTPUT", output.str()));
1424 	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
1425 
1426 	StringTemplate	tmpl	(src);
1427 	const string	baseSrc	= tmpl.specialize(params);
1428 	const string	withExt	= injectExtensionRequirements(baseSrc, SHADERTYPE_VERTEX, m_programs[0].spec.requirements);
1429 
1430 	return withExt;
1431 }
1432 
1433 // Specialize a shader for the fragment shader test case.
specializeFragmentShader(const char * src,const ValueBlock & valueBlock) const1434 string ShaderCase::specializeFragmentShader (const char* src, const ValueBlock& valueBlock) const
1435 {
1436 	ostringstream	decl;
1437 	ostringstream	setup;
1438 	ostringstream	output;
1439 
1440 	const bool		usesInout		= usesShaderInoutQualifiers(m_targetVersion);
1441 	const bool		customColorOut	= usesInout;
1442 	const char*		fragIn			= usesInout			? "in"				: "varying";
1443 	const char*		fragColor		= customColorOut	? "dEQP_FragColor"	: "gl_FragColor";
1444 
1445 	// generated from "both" case
1446 	DE_ASSERT(m_caseType == CASETYPE_FRAGMENT_ONLY);
1447 
1448 	genCompareFunctions(decl, valueBlock, false);
1449 	genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
1450 
1451 	if (customColorOut)
1452 		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1453 
1454 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1455 	{
1456 		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1457 		const char*					valueName		= val.valueName.c_str();
1458 		DataType					floatType		= getDataTypeFloatScalars(val.dataType);
1459 		const char*					floatTypeStr	= getDataTypeName(floatType);
1460 		const char*					refTypeStr		= getDataTypeName(val.dataType);
1461 
1462 		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1463 		{
1464 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1465 				decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n";
1466 			else
1467 			{
1468 				decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n";
1469 				std::string offset = isDataTypeIntOrIVec(val.dataType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
1470 				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset << ");\n";
1471 			}
1472 		}
1473 		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1474 		{
1475 			decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
1476 			decl << refTypeStr << " " << valueName << ";\n";
1477 		}
1478 	}
1479 
1480 	/* \todo [2010-04-01 petri] Check all outputs. */
1481 
1482 	// Shader specialization.
1483 	map<string, string> params;
1484 	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
1485 	params.insert(pair<string, string>("SETUP", setup.str()));
1486 	params.insert(pair<string, string>("OUTPUT", output.str()));
1487 	params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
1488 
1489 	StringTemplate	tmpl	(src);
1490 	const string	baseSrc	= tmpl.specialize(params);
1491 	const string	withExt	= injectExtensionRequirements(baseSrc, SHADERTYPE_FRAGMENT, m_programs[0].spec.requirements);
1492 
1493 	return withExt;
1494 }
1495 
generateVertexSpecialization(glu::GLSLVersion targetVersion,const ShaderCase::ValueBlock & valueBlock)1496 static map<string, string> generateVertexSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1497 {
1498 	const bool				usesInout	= usesShaderInoutQualifiers(targetVersion);
1499 	const char*				vtxIn		= usesInout ? "in" : "attribute";
1500 	ostringstream			decl;
1501 	ostringstream			setup;
1502 	map<string, string>		params;
1503 
1504 	decl << vtxIn << " highp vec4 dEQP_Position;\n";
1505 
1506 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1507 	{
1508 		const ShaderCase::Value&	val		= valueBlock.values[ndx];
1509 		const char*					typeStr	= getDataTypeName(val.dataType);
1510 
1511 		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1512 		{
1513 			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1514 			{
1515 				decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n";
1516 			}
1517 			else
1518 			{
1519 				DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1520 				const char*	floatTypeStr	= getDataTypeName(floatType);
1521 
1522 				decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n";
1523 				setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n";
1524 			}
1525 		}
1526 		else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1527 					val.valueName.find('.') == string::npos)
1528 			decl << "uniform " << typeStr << " " << val.valueName << ";\n";
1529 	}
1530 
1531 	params.insert(pair<string, string>("VERTEX_DECLARATIONS",		decl.str()));
1532 	params.insert(pair<string, string>("VERTEX_SETUP",				setup.str()));
1533 	params.insert(pair<string, string>("VERTEX_OUTPUT",				string("gl_Position = dEQP_Position;\n")));
1534 	return params;
1535 }
1536 
generateFragmentSpecialization(glu::GLSLVersion targetVersion,const ShaderCase::ValueBlock & valueBlock)1537 static map<string, string> generateFragmentSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1538 {
1539 	const bool			usesInout		= usesShaderInoutQualifiers(targetVersion);
1540 	const bool			customColorOut	= usesInout;
1541 	const char*			fragColor		= customColorOut ? "dEQP_FragColor"	: "gl_FragColor";
1542 	ostringstream		decl;
1543 	ostringstream		output;
1544 	map<string, string>	params;
1545 
1546 	genCompareFunctions(decl, valueBlock, false);
1547 	genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
1548 
1549 	if (customColorOut)
1550 		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1551 
1552 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1553 	{
1554 		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1555 		const char*					valueName		= val.valueName.c_str();
1556 		const char*					refTypeStr		= getDataTypeName(val.dataType);
1557 
1558 		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1559 		{
1560 			decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
1561 			decl << refTypeStr << " " << valueName << ";\n";
1562 		}
1563 		else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1564 					val.valueName.find('.') == string::npos)
1565 		{
1566 			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1567 		}
1568 	}
1569 
1570 	params.insert(pair<string, string>("FRAGMENT_DECLARATIONS",		decl.str()));
1571 	params.insert(pair<string, string>("FRAGMENT_OUTPUT",			output.str()));
1572 	params.insert(pair<string, string>("FRAG_COLOR",				fragColor));
1573 	return params;
1574 }
1575 
generateGeometrySpecialization(glu::GLSLVersion targetVersion,const ShaderCase::ValueBlock & valueBlock)1576 static map<string, string> generateGeometrySpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1577 {
1578 	ostringstream		decl;
1579 	map<string, string>	params;
1580 
1581 	DE_UNREF(targetVersion);
1582 
1583 	decl << "layout (triangles) in;\n";
1584 	decl << "layout (triangle_strip, max_vertices=3) out;\n";
1585 	decl << "\n";
1586 
1587 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1588 	{
1589 		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1590 		const char*					valueName		= val.valueName.c_str();
1591 		const char*					refTypeStr		= getDataTypeName(val.dataType);
1592 
1593 		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1594 			val.valueName.find('.') == string::npos)
1595 		{
1596 			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1597 		}
1598 	}
1599 
1600 	params.insert(pair<string, string>("GEOMETRY_DECLARATIONS",		decl.str()));
1601 	return params;
1602 }
1603 
generateTessControlSpecialization(glu::GLSLVersion targetVersion,const ShaderCase::ValueBlock & valueBlock)1604 static map<string, string> generateTessControlSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1605 {
1606 	ostringstream		decl;
1607 	ostringstream		output;
1608 	map<string, string>	params;
1609 
1610 	DE_UNREF(targetVersion);
1611 
1612 	decl << "layout (vertices=3) out;\n";
1613 	decl << "\n";
1614 
1615 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1616 	{
1617 		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1618 		const char*					valueName		= val.valueName.c_str();
1619 		const char*					refTypeStr		= getDataTypeName(val.dataType);
1620 
1621 		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1622 			val.valueName.find('.') == string::npos)
1623 		{
1624 			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1625 		}
1626 	}
1627 
1628 	output <<	"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1629 				"gl_TessLevelInner[0] = 2.0;\n"
1630 				"gl_TessLevelInner[1] = 2.0;\n"
1631 				"gl_TessLevelOuter[0] = 2.0;\n"
1632 				"gl_TessLevelOuter[1] = 2.0;\n"
1633 				"gl_TessLevelOuter[2] = 2.0;\n"
1634 				"gl_TessLevelOuter[3] = 2.0;";
1635 
1636 	params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS",	decl.str()));
1637 	params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT",		output.str()));
1638 	return params;
1639 }
1640 
generateTessEvalSpecialization(glu::GLSLVersion targetVersion,const ShaderCase::ValueBlock & valueBlock)1641 static map<string, string> generateTessEvalSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1642 {
1643 	ostringstream		decl;
1644 	ostringstream		output;
1645 	map<string, string>	params;
1646 
1647 	DE_UNREF(targetVersion);
1648 
1649 	decl << "layout (triangles) in;\n";
1650 	decl << "\n";
1651 
1652 	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1653 	{
1654 		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1655 		const char*					valueName		= val.valueName.c_str();
1656 		const char*					refTypeStr		= getDataTypeName(val.dataType);
1657 
1658 		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1659 			val.valueName.find('.') == string::npos)
1660 		{
1661 			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1662 		}
1663 	}
1664 
1665 	output <<	"gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n";
1666 
1667 	params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS",	decl.str()));
1668 	params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT",		output.str()));
1669 	return params;
1670 }
1671 
specializeShaders(glu::ProgramSources & dst,glu::ShaderType shaderType,const std::vector<std::string> & sources,const ShaderCase::ValueBlock & valueBlock,glu::GLSLVersion targetVersion,const std::vector<ShaderCase::CaseRequirement> & requirements,std::map<std::string,std::string> (* specializationGenerator)(glu::GLSLVersion,const ShaderCase::ValueBlock &))1672 static void specializeShaders (glu::ProgramSources& dst, glu::ShaderType shaderType, const std::vector<std::string>& sources, const ShaderCase::ValueBlock& valueBlock, glu::GLSLVersion targetVersion, const std::vector<ShaderCase::CaseRequirement>& requirements, std::map<std::string, std::string> (*specializationGenerator)(glu::GLSLVersion, const ShaderCase::ValueBlock&))
1673 {
1674 	if (!sources.empty())
1675 	{
1676 		const std::map<std::string, std::string> specializationParams = specializationGenerator(targetVersion, valueBlock);
1677 
1678 		for (int ndx = 0; ndx < (int)sources.size(); ++ndx)
1679 		{
1680 			const StringTemplate	tmpl			(sources[ndx]);
1681 			const std::string		baseGLSLCode	= tmpl.specialize(specializationParams);
1682 			const std::string		glslSource		= injectExtensionRequirements(baseGLSLCode, shaderType, requirements);
1683 
1684 			dst << glu::ShaderSource(shaderType, glslSource);
1685 		}
1686 	}
1687 }
1688 
specializeVertexShaders(glu::ProgramSources & dst,const std::vector<std::string> & sources,const ValueBlock & valueBlock,const std::vector<ShaderCase::CaseRequirement> & requirements) const1689 void ShaderCase::specializeVertexShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1690 {
1691 	specializeShaders(dst, glu::SHADERTYPE_VERTEX, sources, valueBlock, m_targetVersion, requirements, generateVertexSpecialization);
1692 }
1693 
specializeFragmentShaders(glu::ProgramSources & dst,const std::vector<std::string> & sources,const ValueBlock & valueBlock,const std::vector<ShaderCase::CaseRequirement> & requirements) const1694 void ShaderCase::specializeFragmentShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1695 {
1696 	specializeShaders(dst, glu::SHADERTYPE_FRAGMENT, sources, valueBlock, m_targetVersion, requirements, generateFragmentSpecialization);
1697 }
1698 
specializeGeometryShaders(glu::ProgramSources & dst,const std::vector<std::string> & sources,const ValueBlock & valueBlock,const std::vector<ShaderCase::CaseRequirement> & requirements) const1699 void ShaderCase::specializeGeometryShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1700 {
1701 	specializeShaders(dst, glu::SHADERTYPE_GEOMETRY, sources, valueBlock, m_targetVersion, requirements, generateGeometrySpecialization);
1702 }
1703 
specializeTessControlShaders(glu::ProgramSources & dst,const std::vector<std::string> & sources,const ValueBlock & valueBlock,const std::vector<ShaderCase::CaseRequirement> & requirements) const1704 void ShaderCase::specializeTessControlShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1705 {
1706 	specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_CONTROL, sources, valueBlock, m_targetVersion, requirements, generateTessControlSpecialization);
1707 }
1708 
specializeTessEvalShaders(glu::ProgramSources & dst,const std::vector<std::string> & sources,const ValueBlock & valueBlock,const std::vector<ShaderCase::CaseRequirement> & requirements) const1709 void ShaderCase::specializeTessEvalShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1710 {
1711 	specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_EVALUATION, sources, valueBlock, m_targetVersion, requirements, generateTessEvalSpecialization);
1712 }
1713 
dumpValues(const ValueBlock & valueBlock,int arrayNdx)1714 void ShaderCase::dumpValues (const ValueBlock& valueBlock, int arrayNdx)
1715 {
1716 	int numValues = (int)valueBlock.values.size();
1717 	for (int valNdx = 0; valNdx < numValues; valNdx++)
1718 	{
1719 		const ShaderCase::Value&	val				= valueBlock.values[valNdx];
1720 		const char*					valueName		= val.valueName.c_str();
1721 		DataType					dataType		= val.dataType;
1722 		int							scalarSize		= getDataTypeScalarSize(val.dataType);
1723 		ostringstream				result;
1724 
1725 		result << "    ";
1726 		if (val.storageType == Value::STORAGE_INPUT)
1727 			result << "input ";
1728 		else if (val.storageType == Value::STORAGE_UNIFORM)
1729 			result << "uniform ";
1730 		else if (val.storageType == Value::STORAGE_OUTPUT)
1731 			result << "expected ";
1732 
1733 		result << getDataTypeName(dataType) << " " << valueName << ":";
1734 
1735 		if (isDataTypeScalar(dataType))
1736 			result << " ";
1737 		if (isDataTypeVector(dataType))
1738 			result << " [ ";
1739 		else if (isDataTypeMatrix(dataType))
1740 			result << "\n";
1741 
1742 		if (isDataTypeScalarOrVector(dataType))
1743 		{
1744 			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1745 			{
1746 				int						elemNdx	= (val.arrayLength == 1) ? 0 : arrayNdx;
1747 				const Value::Element&	e		= val.elements[elemNdx*scalarSize + scalarNdx];
1748 				result << ((scalarNdx != 0) ? ", " : "");
1749 
1750 				if (isDataTypeFloatOrVec(dataType))
1751 					result << e.float32;
1752 				else if (isDataTypeIntOrIVec(dataType))
1753 					result << e.int32;
1754 				else if (isDataTypeUintOrUVec(dataType))
1755 					result << (deUint32)e.int32;
1756 				else if (isDataTypeBoolOrBVec(dataType))
1757 					result << (e.bool32 ? "true" : "false");
1758 			}
1759 		}
1760 		else if (isDataTypeMatrix(dataType))
1761 		{
1762 			int numRows = getDataTypeMatrixNumRows(dataType);
1763 			int numCols = getDataTypeMatrixNumColumns(dataType);
1764 			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1765 			{
1766 				result << "       [ ";
1767 				for (int colNdx = 0; colNdx < numCols; colNdx++)
1768 				{
1769 					int		elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
1770 					float	v		= val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32;
1771 					result << ((colNdx==0) ? "" : ", ") << v;
1772 				}
1773 				result << " ]\n";
1774 			}
1775 		}
1776 
1777 		if (isDataTypeScalar(dataType))
1778 			result << "\n";
1779 		else if (isDataTypeVector(dataType))
1780 			result << " ]\n";
1781 
1782 		m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage;
1783 	}
1784 }
1785 
1786 } // sl
1787 } // gls
1788 } // deqp
1789