GetDevices: Also allow `\.` to be part of the host name
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsShaderLibraryCase.cpp
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
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
83 static inline bool supportsFragmentHighp (glu::GLSLVersion version)
84 {
85         return version != glu::GLSL_VERSION_100_ES;
86 }
87
88 ShaderCase::ValueBlock::ValueBlock (void)
89         : arrayLength(0)
90 {
91 }
92
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
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
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
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
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
199 ShaderCase::ShaderCaseSpecification::ShaderCaseSpecification (void)
200         : expectResult  (EXPECT_LAST)
201         , targetVersion (glu::GLSL_VERSION_LAST)
202         , caseType              (CASETYPE_COMPLETE)
203 {
204 }
205
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
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
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
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
327 const std::string& BeforeDrawValidator::getInfoLog (void) const
328 {
329         return m_logMessage;
330 }
331
332 glw::GLint BeforeDrawValidator::getValidateStatus (void) const
333 {
334         return m_validateStatus;
335 }
336
337 // ShaderCase.
338
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
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
428 ShaderCase::~ShaderCase (void)
429 {
430 }
431
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
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
590 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
607 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
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
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
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
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
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'.
1161 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
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
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
1314 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.
1368 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.
1434 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
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
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
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
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
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
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
1689 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
1694 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
1699 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
1704 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
1709 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
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