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