Fix invalid_assign_to_1 fragdata tests
[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 #include "tcuTextureUtil.hpp"
29 #include "tcuSurface.hpp"
30
31 #include "tcuStringTemplate.hpp"
32 #include "gluShaderProgram.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluDrawUtil.hpp"
35 #include "gluContextInfo.hpp"
36 #include "gluStrUtil.hpp"
37
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40
41 #include "deRandom.hpp"
42 #include "deInt32.h"
43 #include "deMath.h"
44 #include "deString.h"
45 #include "deStringUtil.hpp"
46 #include "deSharedPtr.hpp"
47
48 #include <map>
49 #include <vector>
50 #include <string>
51 #include <sstream>
52
53 namespace deqp
54 {
55 namespace gls
56 {
57
58 using namespace tcu;
59 using namespace glu;
60 using namespace glu::sl;
61
62 using std::vector;
63 using std::string;
64 using std::ostringstream;
65 using std::map;
66 using std::pair;
67
68 using de::SharedPtr;
69
70 // OpenGL-specific specialization utils
71
72 static vector<RequiredExtension> checkAndSpecializeExtensions (const vector<RequiredExtension>& src,
73                                                                                                                            const ContextInfo&                           ctxInfo)
74 {
75         vector<RequiredExtension>       specialized;
76
77         for (size_t extNdx = 0; extNdx < src.size(); ++extNdx)
78         {
79                 const RequiredExtension&        extension               = src[extNdx];
80                 int                                                     supportedAltNdx = -1;
81
82                 for (size_t alternativeNdx = 0; alternativeNdx < extension.alternatives.size(); ++alternativeNdx)
83                 {
84                         if (ctxInfo.isExtensionSupported(extension.alternatives[alternativeNdx].c_str()))
85                         {
86                                 supportedAltNdx = (int)alternativeNdx;
87                                 break;
88                         }
89                 }
90
91                 if (supportedAltNdx >= 0)
92                 {
93                         specialized.push_back(RequiredExtension(extension.alternatives[supportedAltNdx], extension.effectiveStages));
94                 }
95                 else
96                 {
97                         // no extension(s). Make a nice output
98                         std::ostringstream extensionList;
99
100                         for (size_t ndx = 0; ndx < extension.alternatives.size(); ++ndx)
101                         {
102                                 if (!extensionList.str().empty())
103                                         extensionList << ", ";
104                                 extensionList << extension.alternatives[ndx];
105                         }
106
107                         if (extension.alternatives.size() == 1)
108                                 throw tcu::NotSupportedError("Test requires extension " + extensionList.str());
109                         else
110                                 throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str());
111                 }
112         }
113
114         return specialized;
115 }
116
117 static void checkImplementationLimits (const vector<RequiredCapability>&        requiredCaps,
118                                                                            const ContextInfo&                                   ctxInfo)
119 {
120         for (size_t capNdx = 0; capNdx < requiredCaps.size(); ++capNdx)
121         {
122                 const RequiredCapability& capability = requiredCaps[capNdx];
123                 if (capability.type != CAPABILITY_LIMIT)
124                         continue;
125
126                 const deUint32  pname                   = capability.enumName;
127                 const int               requiredValue   = capability.referenceValue;
128                 const int               supportedValue  = ctxInfo.getInt((int)pname);
129
130                 if (supportedValue <= requiredValue)
131                         throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " (" + de::toString(supportedValue) + ") >= " + de::toString(requiredValue));
132         }
133 }
134
135 // Shader source specialization
136
137 // This functions builds a matching vertex shader for a 'both' case, when
138 // the fragment shader is being tested.
139 // We need to build attributes and varyings for each 'input'.
140 static string genVertexShader (const ShaderCaseSpecification& spec)
141 {
142         ostringstream           res;
143         const bool                      usesInout       = glslVersionUsesInOutQualifiers(spec.targetVersion);
144         const char* const       vtxIn           = usesInout ? "in"      : "attribute";
145         const char* const       vtxOut          = usesInout ? "out"     : "varying";
146
147         res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
148
149         // Declarations (position + attribute/varying for each input).
150         res << "precision highp float;\n";
151         res << "precision highp int;\n";
152         res << "\n";
153         res << vtxIn << " highp vec4 dEQP_Position;\n";
154
155         for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
156         {
157                 const Value&            val                     = spec.values.inputs[ndx];
158                 const DataType          basicType       = val.type.getBasicType();
159                 const DataType          floatType       = getDataTypeFloatScalars(basicType);
160                 const char* const       typeStr         = getDataTypeName(floatType);
161
162                 res << vtxIn << " " << typeStr << " a_" << val.name << ";\n";
163
164                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
165                         res << vtxOut << " " << typeStr << " " << val.name << ";\n";
166                 else
167                         res << vtxOut << " " << typeStr << " v_" << val.name << ";\n";
168         }
169         res << "\n";
170
171         // Main function.
172         // - gl_Position = dEQP_Position;
173         // - for each input: write attribute directly to varying
174         res << "void main()\n";
175         res << "{\n";
176         res << "        gl_Position = dEQP_Position;\n";
177         for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
178         {
179                 const Value&    val             = spec.values.inputs[ndx];
180                 const string&   name    = val.name;
181
182                 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
183                         res << "        " << name << " = a_" << name << ";\n";
184                 else
185                         res << "        v_" << name << " = a_" << name << ";\n";
186         }
187
188         res << "}\n";
189         return res.str();
190 }
191
192 static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName)
193 {
194         bool isFirstOutput = true;
195
196         for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++)
197         {
198                 const Value&    val             = valueBlock.outputs[ndx];
199
200                 // Check if we're only interested in one variable (then skip if not the right one).
201                 if (checkVarName && val.name != checkVarName)
202                         continue;
203
204                 // Prefix.
205                 if (isFirstOutput)
206                 {
207                         output << "bool RES = ";
208                         isFirstOutput = false;
209                 }
210                 else
211                         output << "RES = RES && ";
212
213                 // Generate actual comparison.
214                 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
215                         output << "isOk(" << val.name << ", ref_" << val.name << ", 0.05);\n";
216                 else
217                         output << "isOk(" << nonFloatNamePrefix << val.name << ", ref_" << val.name << ");\n";
218         }
219
220         if (isFirstOutput)
221                 output << dstVec4Var << " = vec4(1.0);\n";      // \todo [petri] Should we give warning if not expect-failure case?
222         else
223                 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
224 }
225
226 static inline bool supportsFragmentHighp (glu::GLSLVersion version)
227 {
228         return version != glu::GLSL_VERSION_100_ES;
229 }
230
231 static string genFragmentShader (const ShaderCaseSpecification& spec)
232 {
233         ostringstream           shader;
234         const bool                      usesInout               = glslVersionUsesInOutQualifiers(spec.targetVersion);
235         const bool                      customColorOut  = usesInout;
236         const char*     const   fragIn                  = usesInout ? "in" : "varying";
237         const char*     const   prec                    = supportsFragmentHighp(spec.targetVersion) ? "highp" : "mediump";
238
239         shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
240
241         shader << "precision " << prec << " float;\n";
242         shader << "precision " << prec << " int;\n";
243         shader << "\n";
244
245         if (customColorOut)
246         {
247                 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
248                 shader << "\n";
249         }
250
251         genCompareFunctions(shader, spec.values, true);
252         shader << "\n";
253
254         // Declarations (varying, reference for each output).
255         for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
256         {
257                 const Value&            val                             = spec.values.outputs[ndx];
258                 const DataType          basicType               = val.type.getBasicType();
259                 const DataType          floatType               = getDataTypeFloatScalars(basicType);
260                 const char* const       floatTypeStr    = getDataTypeName(floatType);
261                 const char* const       refTypeStr              = getDataTypeName(basicType);
262
263                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
264                         shader << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
265                 else
266                         shader << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
267
268                 shader << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
269         }
270
271         shader << "\n";
272         shader << "void main()\n";
273         shader << "{\n";
274
275         shader << "     ";
276         genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", spec.values, "v_", DE_NULL);
277
278         shader << "}\n";
279         return shader.str();
280 }
281
282 // Specialize a shader for the vertex shader test case.
283 static string specializeVertexShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
284 {
285         ostringstream           decl;
286         ostringstream           setup;
287         ostringstream           output;
288         const bool                      usesInout       = glslVersionUsesInOutQualifiers(spec.targetVersion);
289         const char* const       vtxIn           = usesInout ? "in"      : "attribute";
290         const char* const       vtxOut          = usesInout ? "out"     : "varying";
291
292         // generated from "both" case
293         DE_ASSERT(spec.caseType == CASETYPE_VERTEX_ONLY);
294
295         // Output (write out position).
296         output << "gl_Position = dEQP_Position;\n";
297
298         // Declarations (position + attribute for each input, varying for each output).
299         decl << vtxIn << " highp vec4 dEQP_Position;\n";
300
301         for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
302         {
303                 const Value&            val                             = spec.values.inputs[ndx];
304                 const DataType          basicType               = val.type.getBasicType();
305                 const DataType          floatType               = getDataTypeFloatScalars(basicType);
306                 const char* const       floatTypeStr    = getDataTypeName(floatType);
307                 const char* const       refTypeStr              = getDataTypeName(basicType);
308
309                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
310                 {
311                         decl << vtxIn << " " << floatTypeStr << " " << val.name << ";\n";
312                 }
313                 else
314                 {
315                         decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
316                         setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(a_" << val.name << ");\n";
317                 }
318         }
319
320         // \todo [2015-07-24 pyry] Why are uniforms missing?
321
322         for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
323         {
324                 const Value&            val                             = spec.values.outputs[ndx];
325                 const DataType          basicType               = val.type.getBasicType();
326                 const DataType          floatType               = getDataTypeFloatScalars(basicType);
327                 const char* const       floatTypeStr    = getDataTypeName(floatType);
328                 const char* const       refTypeStr              = getDataTypeName(basicType);
329
330                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
331                         decl << vtxOut << " " << floatTypeStr << " " << val.name << ";\n";
332                 else
333                 {
334                         decl << vtxOut << " " << floatTypeStr << " v_" << val.name << ";\n";
335                         decl << refTypeStr << " " << val.name << ";\n";
336
337                         output << "v_" << val.name << " = " << floatTypeStr << "(" << val.name << ");\n";
338                 }
339         }
340
341         // Shader specialization.
342         map<string, string> params;
343         params.insert(pair<string, string>("DECLARATIONS", decl.str()));
344         params.insert(pair<string, string>("SETUP", setup.str()));
345         params.insert(pair<string, string>("OUTPUT", output.str()));
346         params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
347
348         StringTemplate  tmpl    (src);
349         const string    baseSrc = tmpl.specialize(params);
350         const string    withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_VERTEX);
351
352         return withExt;
353 }
354
355 // Specialize a shader for the fragment shader test case.
356 static string specializeFragmentShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
357 {
358         ostringstream           decl;
359         ostringstream           setup;
360         ostringstream           output;
361
362         const bool                      usesInout               = glslVersionUsesInOutQualifiers(spec.targetVersion);
363         const bool                      customColorOut  = usesInout;
364         const char* const       fragIn                  = usesInout                     ? "in"                          : "varying";
365         const char* const       fragColor               = customColorOut        ? "dEQP_FragColor"      : "gl_FragColor";
366
367         // generated from "both" case
368         DE_ASSERT(spec.caseType == CASETYPE_FRAGMENT_ONLY);
369
370         genCompareFunctions(decl, spec.values, false);
371         genCompareOp(output, fragColor, spec.values, "", DE_NULL);
372
373         if (customColorOut)
374                 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
375
376         for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
377         {
378                 const Value&            val                             = spec.values.inputs[ndx];
379                 const DataType          basicType               = val.type.getBasicType();
380                 const DataType          floatType               = getDataTypeFloatScalars(basicType);
381                 const char* const       floatTypeStr    = getDataTypeName(floatType);
382                 const char* const       refTypeStr              = getDataTypeName(basicType);
383
384                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
385                         decl << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
386                 else
387                 {
388                         decl << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
389                         std::string offset = isDataTypeIntOrIVec(basicType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
390                         setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(v_" << val.name << offset << ");\n";
391                 }
392         }
393
394         // \todo [2015-07-24 pyry] Why are uniforms missing?
395
396         for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
397         {
398                 const Value&            val                             = spec.values.outputs[ndx];
399                 const DataType          basicType               = val.type.getBasicType();
400                 const char* const       refTypeStr              = getDataTypeName(basicType);
401
402                 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
403                 decl << refTypeStr << " " << val.name << ";\n";
404         }
405
406         /* \todo [2010-04-01 petri] Check all outputs. */
407
408         // Shader specialization.
409         map<string, string> params;
410         params.insert(pair<string, string>("DECLARATIONS", decl.str()));
411         params.insert(pair<string, string>("SETUP", setup.str()));
412         params.insert(pair<string, string>("OUTPUT", output.str()));
413         params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
414
415         StringTemplate  tmpl    (src);
416         const string    baseSrc = tmpl.specialize(params);
417         const string    withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_FRAGMENT);
418
419         return withExt;
420 }
421
422 static void generateUniformDeclarations (std::ostream& dst, const ValueBlock& valueBlock)
423 {
424         for (size_t ndx = 0; ndx < valueBlock.uniforms.size(); ndx++)
425         {
426                 const Value&            val             = valueBlock.uniforms[ndx];
427                 const char* const       typeStr = getDataTypeName(val.type.getBasicType());
428
429                 if (val.name.find('.') == string::npos)
430                         dst << "uniform " << typeStr << " " << val.name << ";\n";
431         }
432 }
433
434 static map<string, string> generateVertexSpecialization (const ProgramSpecializationParams& specParams)
435 {
436         const bool                              usesInout       = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
437         const char*                             vtxIn           = usesInout ? "in" : "attribute";
438         ostringstream                   decl;
439         ostringstream                   setup;
440         map<string, string>             params;
441
442         decl << vtxIn << " highp vec4 dEQP_Position;\n";
443
444         for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++)
445         {
446                 const Value&            val                     = specParams.caseSpec.values.inputs[ndx];
447                 const DataType          basicType       = val.type.getBasicType();
448                 const char* const       typeStr         = getDataTypeName(val.type.getBasicType());
449
450                 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
451                 {
452                         decl << vtxIn << " " << typeStr << " " << val.name << ";\n";
453                 }
454                 else
455                 {
456                         const DataType          floatType               = getDataTypeFloatScalars(basicType);
457                         const char* const       floatTypeStr    = getDataTypeName(floatType);
458
459                         decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
460                         setup << typeStr << " " << val.name << " = " << typeStr << "(a_" << val.name << ");\n";
461                 }
462         }
463
464         generateUniformDeclarations(decl, specParams.caseSpec.values);
465
466         params.insert(pair<string, string>("VERTEX_DECLARATIONS",       decl.str()));
467         params.insert(pair<string, string>("VERTEX_SETUP",                      setup.str()));
468         params.insert(pair<string, string>("VERTEX_OUTPUT",                     string("gl_Position = dEQP_Position;\n")));
469
470         return params;
471 }
472
473 static map<string, string> generateFragmentSpecialization (const ProgramSpecializationParams& specParams)
474 {
475         const bool                      usesInout               = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
476         const bool                      customColorOut  = usesInout;
477         const char* const       fragColor               = customColorOut ? "dEQP_FragColor"     : "gl_FragColor";
478         ostringstream           decl;
479         ostringstream           output;
480         map<string, string>     params;
481
482         genCompareFunctions(decl, specParams.caseSpec.values, false);
483         genCompareOp(output, fragColor, specParams.caseSpec.values, "", DE_NULL);
484
485         if (customColorOut)
486                 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
487
488         for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++)
489         {
490                 const Value&            val                     = specParams.caseSpec.values.outputs[ndx];
491                 const char*     const   refTypeStr      = getDataTypeName(val.type.getBasicType());
492
493                 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
494                 decl << refTypeStr << " " << val.name << ";\n";
495         }
496
497         generateUniformDeclarations(decl, specParams.caseSpec.values);
498
499         params.insert(pair<string, string>("FRAGMENT_DECLARATIONS",     decl.str()));
500         params.insert(pair<string, string>("FRAGMENT_OUTPUT",           output.str()));
501         params.insert(pair<string, string>("FRAG_COLOR",                        fragColor));
502
503         return params;
504 }
505
506 static map<string, string> generateGeometrySpecialization (const ProgramSpecializationParams& specParams)
507 {
508         ostringstream           decl;
509         map<string, string>     params;
510
511         decl << "layout (triangles) in;\n";
512         decl << "layout (triangle_strip, max_vertices=3) out;\n";
513         decl << "\n";
514
515         generateUniformDeclarations(decl, specParams.caseSpec.values);
516
517         params.insert(pair<string, string>("GEOMETRY_DECLARATIONS",             decl.str()));
518
519         return params;
520 }
521
522 static map<string, string> generateTessControlSpecialization (const ProgramSpecializationParams& specParams)
523 {
524         ostringstream           decl;
525         ostringstream           output;
526         map<string, string>     params;
527
528         decl << "layout (vertices=3) out;\n";
529         decl << "\n";
530
531         generateUniformDeclarations(decl, specParams.caseSpec.values);
532
533         output <<       "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
534                                 "gl_TessLevelInner[0] = 2.0;\n"
535                                 "gl_TessLevelInner[1] = 2.0;\n"
536                                 "gl_TessLevelOuter[0] = 2.0;\n"
537                                 "gl_TessLevelOuter[1] = 2.0;\n"
538                                 "gl_TessLevelOuter[2] = 2.0;\n"
539                                 "gl_TessLevelOuter[3] = 2.0;";
540
541         params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS", decl.str()));
542         params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT",               output.str()));
543         params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",                             de::toString(specParams.maxPatchVertices)));
544
545         return params;
546 }
547
548 static map<string, string> generateTessEvalSpecialization (const ProgramSpecializationParams& specParams)
549 {
550         ostringstream           decl;
551         ostringstream           output;
552         map<string, string>     params;
553
554         decl << "layout (triangles) in;\n";
555         decl << "\n";
556
557         generateUniformDeclarations(decl, specParams.caseSpec.values);
558
559         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";
560
561         params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS",      decl.str()));
562         params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT",            output.str()));
563         params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",                                     de::toString(specParams.maxPatchVertices)));
564
565         return params;
566 }
567
568 static void specializeShaderSources (ProgramSources&                                    dst,
569                                                                          const ProgramSources&                          src,
570                                                                          const ProgramSpecializationParams&     specParams,
571                                                                          glu::ShaderType                                        shaderType,
572                                                                          map<string, string>                            (*specializationGenerator) (const ProgramSpecializationParams& specParams))
573 {
574         if (!src.sources[shaderType].empty())
575         {
576                 const map<string, string>       tmplParams      = specializationGenerator(specParams);
577
578                 for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx)
579                 {
580                         const StringTemplate    tmpl                    (src.sources[shaderType][ndx]);
581                         const std::string               baseGLSLCode    = tmpl.specialize(tmplParams);
582                         const std::string               sourceWithExts  = injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType);
583
584                         dst << glu::ShaderSource(shaderType, sourceWithExts);
585                 }
586         }
587 }
588
589 static void specializeProgramSources (glu::ProgramSources&                                      dst,
590                                                                           const glu::ProgramSources&                    src,
591                                                                           const ProgramSpecializationParams&    specParams)
592 {
593         specializeShaderSources(dst, src, specParams, SHADERTYPE_VERTEX,                                        generateVertexSpecialization);
594         specializeShaderSources(dst, src, specParams, SHADERTYPE_FRAGMENT,                                      generateFragmentSpecialization);
595         specializeShaderSources(dst, src, specParams, SHADERTYPE_GEOMETRY,                                      generateGeometrySpecialization);
596         specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_CONTROL,          generateTessControlSpecialization);
597         specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_EVALUATION,       generateTessEvalSpecialization);
598
599         dst << ProgramSeparable(src.separable);
600 }
601
602 enum
603 {
604         VIEWPORT_WIDTH          = 128,
605         VIEWPORT_HEIGHT         = 128
606 };
607
608 class BeforeDrawValidator : public glu::DrawUtilCallback
609 {
610 public:
611         enum TargetType
612         {
613                 TARGETTYPE_PROGRAM = 0,
614                 TARGETTYPE_PIPELINE,
615
616                 TARGETTYPE_LAST
617         };
618
619                                                         BeforeDrawValidator     (const glw::Functions& gl, glw::GLuint target, TargetType targetType);
620
621         void                                    beforeDrawCall          (void);
622
623         const std::string&              getInfoLog                      (void) const;
624         glw::GLint                              getValidateStatus       (void) const;
625
626 private:
627         const glw::Functions&   m_gl;
628         const glw::GLuint               m_target;
629         const TargetType                m_targetType;
630
631         glw::GLint                              m_validateStatus;
632         std::string                             m_logMessage;
633 };
634
635 BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType)
636         : m_gl                          (gl)
637         , m_target                      (target)
638         , m_targetType          (targetType)
639         , m_validateStatus      (-1)
640 {
641         DE_ASSERT(targetType < TARGETTYPE_LAST);
642 }
643
644 void BeforeDrawValidator::beforeDrawCall (void)
645 {
646         glw::GLint                                      bytesWritten    = 0;
647         glw::GLint                                      infoLogLength;
648         std::vector<glw::GLchar>        logBuffer;
649         int                                                     stringLength;
650
651         // validate
652         if (m_targetType == TARGETTYPE_PROGRAM)
653                 m_gl.validateProgram(m_target);
654         else if (m_targetType == TARGETTYPE_PIPELINE)
655                 m_gl.validateProgramPipeline(m_target);
656         else
657                 DE_ASSERT(false);
658
659         GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate");
660
661         // check status
662         m_validateStatus = -1;
663
664         if (m_targetType == TARGETTYPE_PROGRAM)
665                 m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
666         else if (m_targetType == TARGETTYPE_PIPELINE)
667                 m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
668         else
669                 DE_ASSERT(false);
670
671         GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status");
672         TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE);
673
674         // read log
675
676         infoLogLength = 0;
677
678         if (m_targetType == TARGETTYPE_PROGRAM)
679                 m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
680         else if (m_targetType == TARGETTYPE_PIPELINE)
681                 m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
682         else
683                 DE_ASSERT(false);
684
685         GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length");
686
687         if (infoLogLength <= 0)
688         {
689                 m_logMessage.clear();
690                 return;
691         }
692
693         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
694
695         if (m_targetType == TARGETTYPE_PROGRAM)
696                 m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
697         else if (m_targetType == TARGETTYPE_PIPELINE)
698                 m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
699         else
700                 DE_ASSERT(false);
701
702         // just ignore bytesWritten to be safe, find the null terminator
703         stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin());
704         m_logMessage.assign(&logBuffer[0], stringLength);
705 }
706
707 const std::string& BeforeDrawValidator::getInfoLog (void) const
708 {
709         return m_logMessage;
710 }
711
712 glw::GLint BeforeDrawValidator::getValidateStatus (void) const
713 {
714         return m_validateStatus;
715 }
716
717 // ShaderCase.
718
719 ShaderLibraryCase::ShaderLibraryCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification)
720         : tcu::TestCase (testCtx, name, description)
721         , m_renderCtx   (renderCtx)
722         , m_contextInfo (contextInfo)
723         , m_spec                (specification)
724 {
725 }
726
727 ShaderLibraryCase::~ShaderLibraryCase (void)
728 {
729 }
730
731 void ShaderLibraryCase::init (void)
732 {
733         DE_ASSERT(isValid(m_spec));
734
735         if (!isGLSLVersionSupported(m_renderCtx.getType(), m_spec.targetVersion))
736                 TCU_THROW(NotSupportedError, (string(getGLSLVersionName(m_spec.targetVersion)) + " is not supported").c_str());
737
738         checkImplementationLimits(m_spec.requiredCaps, m_contextInfo);
739
740         // log the expected result
741         switch (m_spec.expectResult)
742         {
743                 case EXPECT_PASS:
744                         // Don't write anything
745                         break;
746
747                 case EXPECT_COMPILE_FAIL:
748                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
749                         break;
750
751                 case EXPECT_LINK_FAIL:
752                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
753                         break;
754
755                 case EXPECT_COMPILE_LINK_FAIL:
756                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
757                         break;
758
759                 case EXPECT_VALIDATION_FAIL:
760                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
761                         break;
762
763                 case EXPECT_BUILD_SUCCESSFUL:
764                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
765                         break;
766
767                 default:
768                         DE_ASSERT(false);
769                         break;
770         }
771 }
772
773 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const Value& val, int arrayNdx, tcu::TestLog& log)
774 {
775         bool foundAnyMatch = false;
776
777         for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
778         {
779                 const DataType  dataType        = val.type.getBasicType();
780                 const int               scalarSize      = getDataTypeScalarSize(dataType);
781                 const int               loc                     = gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
782                 const int               elemNdx         = arrayNdx * scalarSize;
783
784                 DE_ASSERT(elemNdx+scalarSize <= (int)val.elements.size());
785
786                 if (loc == -1)
787                         continue;
788
789                 foundAnyMatch = true;
790
791                 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLfloat));
792                 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLint));
793
794                 gl.useProgram(pipelinePrograms[programNdx]);
795
796                 switch (dataType)
797                 {
798                         case TYPE_FLOAT:                gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
799                         case TYPE_FLOAT_VEC2:   gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
800                         case TYPE_FLOAT_VEC3:   gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
801                         case TYPE_FLOAT_VEC4:   gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
802                         case TYPE_FLOAT_MAT2:   gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
803                         case TYPE_FLOAT_MAT3:   gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
804                         case TYPE_FLOAT_MAT4:   gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
805                         case TYPE_INT:                  gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
806                         case TYPE_INT_VEC2:             gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
807                         case TYPE_INT_VEC3:             gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
808                         case TYPE_INT_VEC4:             gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
809                         case TYPE_BOOL:                 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
810                         case TYPE_BOOL_VEC2:    gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
811                         case TYPE_BOOL_VEC3:    gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
812                         case TYPE_BOOL_VEC4:    gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
813                         case TYPE_UINT:                 gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
814                         case TYPE_UINT_VEC2:    gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
815                         case TYPE_UINT_VEC3:    gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
816                         case TYPE_UINT_VEC4:    gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
817                         case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
818                         case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
819                         case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
820                         case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
821                         case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
822                         case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
823
824                         case TYPE_SAMPLER_2D:
825                         case TYPE_SAMPLER_CUBE:
826                                 DE_FATAL("implement!");
827                                 break;
828
829                         default:
830                                 DE_ASSERT(false);
831                 }
832         }
833
834         if (!foundAnyMatch)
835                 log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
836 }
837
838 static bool isTessellationPresent (const ShaderCaseSpecification& spec)
839 {
840         if (spec.programs[0].sources.separable)
841         {
842                 const deUint32 tessellationBits =       (1 << glu::SHADERTYPE_TESSELLATION_CONTROL)             |
843                                                                                         (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
844
845                 for (int programNdx = 0; programNdx < (int)spec.programs.size(); ++programNdx)
846                         if (spec.programs[programNdx].activeStages & tessellationBits)
847                                 return true;
848                 return false;
849         }
850         else
851                 return !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
852                            !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
853 }
854
855 static bool isTessellationSupported (const glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo)
856 {
857         if (renderCtx.getType().getProfile() == PROFILE_ES)
858         {
859                 const int       majorVer        = renderCtx.getType().getMajorVersion();
860                 const int       minorVer        = renderCtx.getType().getMinorVersion();
861
862                 return (majorVer > 3) || (majorVer == 3 && minorVer >= 2) ||
863                            ctxInfo.isExtensionSupported("GL_EXT_tessellation_shader");
864         }
865         else
866                 return false;
867 }
868
869 static bool checkPixels (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& surface)
870 {
871         bool    allWhite                = true;
872         bool    allBlack                = true;
873         bool    anyUnexpected   = false;
874
875         for (int y = 0; y < surface.getHeight(); y++)
876         {
877                 for (int x = 0; x < surface.getWidth(); x++)
878                 {
879                         const tcu::IVec4        pixel            = surface.getPixelInt(x, y);
880                         // Note: we really do not want to involve alpha in the check comparison
881                         // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
882                         const bool                      isWhite          = (pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255);
883                         const bool                      isBlack          = (pixel[0] ==   0) && (pixel[1] ==   0) && (pixel[2] ==   0);
884
885                         allWhite                = allWhite && isWhite;
886                         allBlack                = allBlack && isBlack;
887                         anyUnexpected   = anyUnexpected || (!isWhite && !isBlack);
888                 }
889         }
890
891         if (!allWhite)
892         {
893                 if (anyUnexpected)
894                         log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
895                 else if (!allBlack)
896                         log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
897
898                 return false;
899         }
900
901         return true;
902 }
903
904 bool ShaderLibraryCase::execute (void)
905 {
906         const float                                                     quadSize                                = 1.0f;
907         static const float                                      s_positions[4*4]                =
908         {
909                 -quadSize, -quadSize, 0.0f, 1.0f,
910                 -quadSize, +quadSize, 0.0f, 1.0f,
911                 +quadSize, -quadSize, 0.0f, 1.0f,
912                 +quadSize, +quadSize, 0.0f, 1.0f
913         };
914
915         static const deUint16                           s_indices[2*3]                  =
916         {
917                 0, 1, 2,
918                 1, 3, 2
919         };
920
921         TestLog&                                                        log                                             = m_testCtx.getLog();
922         const glw::Functions&                           gl                                              = m_renderCtx.getFunctions();
923
924         // Compute viewport.
925         const tcu::RenderTarget&                        renderTarget                    = m_renderCtx.getRenderTarget();
926         de::Random                                                      rnd                                             (deStringHash(getName()));
927         const int                                                       width                                   = deMin32(renderTarget.getWidth(),      VIEWPORT_WIDTH);
928         const int                                                       height                                  = deMin32(renderTarget.getHeight(),     VIEWPORT_HEIGHT);
929         const int                                                       viewportX                               = rnd.getInt(0, renderTarget.getWidth()  - width);
930         const int                                                       viewportY                               = rnd.getInt(0, renderTarget.getHeight() - height);
931         const int                                                       numVerticesPerDraw              = 4;
932         const bool                                                      tessellationPresent             = isTessellationPresent(m_spec);
933         const bool                                                      separablePrograms               = m_spec.programs[0].sources.separable;
934
935         bool                                                            allCompilesOk                   = true;
936         bool                                                            allLinksOk                              = true;
937         const char*                                                     failReason                              = DE_NULL;
938
939         vector<ProgramSources>                          specializedSources              (m_spec.programs.size());
940
941         deUint32                                                        vertexProgramID                 = -1;
942         vector<deUint32>                                        pipelineProgramIDs;
943         vector<SharedPtr<ShaderProgram> >       programs;
944         SharedPtr<ProgramPipeline>                      programPipeline;
945
946         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
947
948         if(isCapabilityRequired(CAPABILITY_ONLY_GLSL_ES_100_SUPPORT, m_spec))
949         {
950                 // GL_MAJOR_VERSION query does not exist on GLES2
951                 // so succeeding query implies GLES3+ hardware.
952                 glw::GLint majorVersion = 0;
953                 gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
954                 if (gl.getError() == GL_NO_ERROR)
955                         return true;
956         }
957
958         if(isCapabilityRequired(CAPABILITY_EXACTLY_ONE_DRAW_BUFFER, m_spec))
959         {
960                 // on unextended ES2 there is only one draw buffer
961                 // and there is no GL_MAX_DRAW_BUFFERS query
962                 glw::GLint maxDrawBuffers = 0;
963                 gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
964                 if ((gl.getError() == GL_NO_ERROR) && (maxDrawBuffers > 1))
965                         throw tcu::NotSupportedError("Test requires exactly one draw buffer");
966         }
967
968         // Specialize shaders
969         if (m_spec.caseType == CASETYPE_VERTEX_ONLY)
970         {
971                 const vector<RequiredExtension> reqExt  = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
972
973                 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX].size() == 1);
974                 specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX][0], reqExt))
975                                                           << glu::FragmentSource(genFragmentShader(m_spec));
976         }
977         else if (m_spec.caseType == CASETYPE_FRAGMENT_ONLY)
978         {
979                 const vector<RequiredExtension> reqExt  = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
980
981                 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].size() == 1);
982                 specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
983                                                           << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT][0], reqExt));
984         }
985         else
986         {
987                 DE_ASSERT(m_spec.caseType == CASETYPE_COMPLETE);
988
989                 const int       maxPatchVertices        = isTessellationPresent(m_spec) && isTessellationSupported(m_renderCtx, m_contextInfo)
990                                                                                 ? m_contextInfo.getInt(GL_MAX_PATCH_VERTICES) : 0;
991
992                 for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
993                 {
994                         const ProgramSpecializationParams       progSpecParams  (m_spec, checkAndSpecializeExtensions(m_spec.programs[progNdx].requiredExtensions, m_contextInfo), maxPatchVertices);
995
996                         specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
997                 }
998         }
999
1000         if (!separablePrograms)
1001         {
1002                 de::SharedPtr<glu::ShaderProgram>       program         (new glu::ShaderProgram(m_renderCtx, specializedSources[0]));
1003
1004                 vertexProgramID = program->getProgram();
1005                 pipelineProgramIDs.push_back(program->getProgram());
1006                 programs.push_back(program);
1007
1008                 // Check that compile/link results are what we expect.
1009
1010                 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
1011                 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1012                         if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
1013                                 allCompilesOk = false;
1014
1015                 if (!program->getProgramInfo().linkOk)
1016                         allLinksOk = false;
1017
1018                 log << *program;
1019         }
1020         else
1021         {
1022                 // Separate programs
1023                 for (size_t programNdx = 0; programNdx < m_spec.programs.size(); ++programNdx)
1024                 {
1025                         de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, specializedSources[programNdx]));
1026
1027                         if (m_spec.programs[programNdx].activeStages & (1u << glu::SHADERTYPE_VERTEX))
1028                                 vertexProgramID = program->getProgram();
1029
1030                         pipelineProgramIDs.push_back(program->getProgram());
1031                         programs.push_back(program);
1032
1033                         // Check that compile/link results are what we expect.
1034
1035                         DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
1036                         for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1037                                 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
1038                                         allCompilesOk = false;
1039
1040                         if (!program->getProgramInfo().linkOk)
1041                                 allLinksOk = false;
1042
1043                         // Log program and active stages
1044                         {
1045                                 const tcu::ScopedLogSection     section         (log, "Program", "Program " + de::toString(programNdx+1));
1046                                 tcu::MessageBuilder                     builder         (&log);
1047                                 bool                                            firstStage      = true;
1048
1049                                 builder << "Pipeline uses stages: ";
1050                                 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1051                                 {
1052                                         if (m_spec.programs[programNdx].activeStages & (1u << stage))
1053                                         {
1054                                                 if (!firstStage)
1055                                                         builder << ", ";
1056                                                 builder << glu::getShaderTypeName((glu::ShaderType)stage);
1057                                                 firstStage = true;
1058                                         }
1059                                 }
1060                                 builder << tcu::TestLog::EndMessage;
1061
1062                                 log << *program;
1063                         }
1064                 }
1065         }
1066
1067         switch (m_spec.expectResult)
1068         {
1069                 case EXPECT_PASS:
1070                 case EXPECT_VALIDATION_FAIL:
1071                 case EXPECT_BUILD_SUCCESSFUL:
1072                         if (!allCompilesOk)
1073                                 failReason = "expected shaders to compile and link properly, but failed to compile.";
1074                         else if (!allLinksOk)
1075                                 failReason = "expected shaders to compile and link properly, but failed to link.";
1076                         break;
1077
1078                 case EXPECT_COMPILE_FAIL:
1079                         if (allCompilesOk && !allLinksOk)
1080                                 failReason = "expected compilation to fail, but shaders compiled and link failed.";
1081                         else if (allCompilesOk)
1082                                 failReason = "expected compilation to fail, but shaders compiled correctly.";
1083                         break;
1084
1085                 case EXPECT_LINK_FAIL:
1086                         if (!allCompilesOk)
1087                                 failReason = "expected linking to fail, but unable to compile.";
1088                         else if (allLinksOk)
1089                                 failReason = "expected linking to fail, but passed.";
1090                         break;
1091
1092                 case EXPECT_COMPILE_LINK_FAIL:
1093                         if (allCompilesOk && allLinksOk)
1094                                 failReason = "expected compile or link to fail, but passed.";
1095                         break;
1096
1097                 default:
1098                         DE_ASSERT(false);
1099                         return false;
1100         }
1101
1102         if (failReason != DE_NULL)
1103         {
1104                 // \todo [2010-06-07 petri] These should be handled in the test case?
1105                 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
1106
1107                 if (isCapabilityRequired(CAPABILITY_FULL_GLSL_ES_100_SUPPORT, m_spec))
1108                 {
1109                         log     << TestLog::Message
1110                                 << "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
1111                                 << TestLog::EndMessage;
1112
1113                         if (allCompilesOk && !allLinksOk)
1114                         {
1115                                 // Used features are detectable at compile time. If implementation parses shader
1116                                 // at link time, report it as quality warning.
1117                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
1118                         }
1119                         else
1120                                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
1121                 }
1122                 else if (m_spec.expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
1123                 {
1124                         // If implementation parses shader at link time, report it as quality warning.
1125                         m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
1126                 }
1127                 else
1128                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
1129                 return false;
1130         }
1131
1132         // Return if shader is not intended to be run
1133         if (m_spec.expectResult == EXPECT_COMPILE_FAIL          ||
1134                 m_spec.expectResult == EXPECT_COMPILE_LINK_FAIL ||
1135                 m_spec.expectResult == EXPECT_LINK_FAIL                 ||
1136                 m_spec.expectResult == EXPECT_BUILD_SUCCESSFUL)
1137                 return true;
1138
1139         // Setup viewport.
1140         gl.viewport(viewportX, viewportY, width, height);
1141
1142         if (separablePrograms)
1143         {
1144                 programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
1145
1146                 // Setup pipeline
1147                 gl.bindProgramPipeline(programPipeline->getPipeline());
1148                 for (int programNdx = 0; programNdx < (int)m_spec.programs.size(); ++programNdx)
1149                 {
1150                         deUint32 shaderFlags = 0;
1151                         for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1152                                 if (m_spec.programs[programNdx].activeStages & (1u << stage))
1153                                         shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
1154
1155                         programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
1156                 }
1157
1158                 programPipeline->activeShaderProgram(vertexProgramID);
1159                 GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
1160         }
1161         else
1162         {
1163                 // Start using program
1164                 gl.useProgram(vertexProgramID);
1165                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
1166         }
1167
1168         // Fetch location for positions positions.
1169         int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
1170         if (positionLoc == -1)
1171         {
1172                 string errStr = string("no location found for attribute 'dEQP_Position'");
1173                 TCU_FAIL(errStr.c_str());
1174         }
1175
1176         // Iterate all value blocks.
1177         {
1178                 const ValueBlock&       valueBlock              = m_spec.values;
1179
1180                 // always render at least one pass even if there is no input/output data
1181                 const int                       numRenderPasses = valueBlock.outputs.empty() ? 1 : (int)valueBlock.outputs[0].elements.size() / valueBlock.outputs[0].type.getScalarSize();
1182
1183                 // Iterate all array sub-cases.
1184                 for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
1185                 {
1186                         vector<VertexArrayBinding>      vertexArrays;
1187                         int                                                     attribValueNdx          = 0;
1188                         vector<vector<float> >          attribValues            (valueBlock.inputs.size());
1189                         glw::GLenum                                     postDrawError;
1190                         BeforeDrawValidator                     beforeDrawValidator     (gl,
1191                                                                                                                          (separablePrograms) ? (programPipeline->getPipeline())                 : (vertexProgramID),
1192                                                                                                                          (separablePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE)       : (BeforeDrawValidator::TARGETTYPE_PROGRAM));
1193
1194                         vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
1195
1196                         // Collect VA pointer for inputs
1197                         for (size_t valNdx = 0; valNdx < valueBlock.inputs.size(); valNdx++)
1198                         {
1199                                 const Value&            val                     = valueBlock.inputs[valNdx];
1200                                 const char* const       valueName       = val.name.c_str();
1201                                 const DataType          dataType        = val.type.getBasicType();
1202                                 const int                       scalarSize      = getDataTypeScalarSize(dataType);
1203
1204                                 // Replicate values four times.
1205                                 std::vector<float>& scalars = attribValues[attribValueNdx++];
1206                                 scalars.resize(numVerticesPerDraw * scalarSize);
1207                                 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
1208                                 {
1209                                         for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
1210                                                 for (int ndx = 0; ndx < scalarSize; ndx++)
1211                                                         scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
1212                                 }
1213                                 else
1214                                 {
1215                                         // convert to floats.
1216                                         for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
1217                                         {
1218                                                 for (int ndx = 0; ndx < scalarSize; ndx++)
1219                                                 {
1220                                                         float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
1221                                                         DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
1222                                                         scalars[repNdx*scalarSize + ndx] = v;
1223                                                 }
1224                                         }
1225                                 }
1226
1227                                 // Attribute name prefix.
1228                                 string attribPrefix = "";
1229                                 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
1230                                 if ((m_spec.caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
1231                                         attribPrefix = "a_";
1232
1233                                 // Input always given as attribute.
1234                                 string attribName = attribPrefix + valueName;
1235                                 int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
1236                                 if (attribLoc == -1)
1237                                 {
1238                                         log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
1239                                         continue;
1240                                 }
1241
1242                                 if (isDataTypeMatrix(dataType))
1243                                 {
1244                                         int numCols = getDataTypeMatrixNumColumns(dataType);
1245                                         int numRows = getDataTypeMatrixNumRows(dataType);
1246                                         DE_ASSERT(scalarSize == numCols*numRows);
1247
1248                                         for (int i = 0; i < numCols; i++)
1249                                                 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*(int)sizeof(float), &scalars[i * numRows]));
1250                                 }
1251                                 else
1252                                 {
1253                                         DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
1254                                         vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
1255                                 }
1256
1257                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
1258                         }
1259
1260                         GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
1261
1262                         // set reference values for outputs.
1263                         for (size_t valNdx = 0; valNdx < valueBlock.outputs.size(); valNdx++)
1264                         {
1265                                 const Value&            val                     = valueBlock.outputs[valNdx];
1266                                 const char* const       valueName       = val.name.c_str();
1267
1268                                 // Set reference value.
1269                                 string refName = string("ref_") + valueName;
1270                                 setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
1271                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
1272                         }
1273
1274                         // set uniform values
1275                         for (size_t valNdx = 0; valNdx < valueBlock.uniforms.size(); valNdx++)
1276                         {
1277                                 const Value&            val                     = valueBlock.uniforms[valNdx];
1278                                 const char* const       valueName       = val.name.c_str();
1279
1280                                 setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
1281                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
1282                         }
1283
1284                         // Clear.
1285                         gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
1286                         gl.clear(GL_COLOR_BUFFER_BIT);
1287                         GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1288
1289                         // Use program or pipeline
1290                         if (separablePrograms)
1291                                 gl.useProgram(0);
1292                         else
1293                                 gl.useProgram(vertexProgramID);
1294
1295                         // Draw.
1296                         if (tessellationPresent)
1297                         {
1298                                 gl.patchParameteri(GL_PATCH_VERTICES, 3);
1299                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
1300                         }
1301
1302                         draw(m_renderCtx,
1303                                  vertexProgramID,
1304                                  (int)vertexArrays.size(),
1305                                  &vertexArrays[0],
1306                                  (tessellationPresent) ?
1307                                         (pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
1308                                         (pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
1309                                  (m_spec.expectResult == EXPECT_VALIDATION_FAIL) ?
1310                                         (&beforeDrawValidator) :
1311                                         (DE_NULL));
1312
1313                         postDrawError = gl.getError();
1314
1315                         if (m_spec.expectResult == EXPECT_PASS)
1316                         {
1317                                 // Read back results.
1318                                 Surface                 surface                 (width, height);
1319                                 const float             w                               = s_positions[3];
1320                                 const int               minY                    = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
1321                                 const int               maxY                    = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
1322                                 const int               minX                    = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
1323                                 const int               maxX                    = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
1324
1325                                 GLU_EXPECT_NO_ERROR(postDrawError, "draw");
1326
1327                                 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
1328                                 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
1329
1330                                 if (!checkPixels(log, tcu::getSubregion(surface.getAccess(), minX, minY, maxX-minX+1, maxY-minY+1)))
1331                                 {
1332                                         log << TestLog::Message << "INCORRECT RESULT for sub-case " << arrayNdx+1 << " of " << numRenderPasses << "):"
1333                                                 << TestLog::EndMessage;
1334
1335                                         log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
1336                                         dumpValues(log, valueBlock, arrayNdx);
1337
1338                                         // Dump image on failure.
1339                                         log << TestLog::Image("Result", "Rendered result image", surface);
1340
1341                                         gl.useProgram(0);
1342                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1343                                         return false;
1344                                 }
1345                         }
1346                         else if (m_spec.expectResult == EXPECT_VALIDATION_FAIL)
1347                         {
1348                                 log     << TestLog::Message
1349                                         << "Draw call generated error: "
1350                                         << glu::getErrorStr(postDrawError) << " "
1351                                         << ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
1352                                         << "Validate status: "
1353                                         << glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
1354                                         << ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
1355                                         << "Info log: "
1356                                         << ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
1357                                         << TestLog::EndMessage;
1358
1359                                 // test result
1360
1361                                 if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
1362                                 {
1363                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
1364                                         return false;
1365                                 }
1366
1367                                 if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
1368                                 {
1369                                         if (postDrawError == GL_NO_ERROR)
1370                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
1371                                         else if (postDrawError == GL_INVALID_OPERATION)
1372                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
1373                                         else
1374                                                 DE_ASSERT(false);
1375                                         return false;
1376                                 }
1377                                 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
1378                                 {
1379                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
1380                                         return false;
1381                                 }
1382                                 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
1383                                 {
1384                                         // Validation does not depend on input values, no need to test all values
1385                                         return true;
1386                                 }
1387                                 else
1388                                         DE_ASSERT(false);
1389                         }
1390                         else
1391                                 DE_ASSERT(false);
1392                 }
1393         }
1394
1395         gl.useProgram(0);
1396         if (separablePrograms)
1397                 gl.bindProgramPipeline(0);
1398
1399         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
1400         return true;
1401 }
1402
1403 TestCase::IterateResult ShaderLibraryCase::iterate (void)
1404 {
1405         // Initialize state to pass.
1406         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1407
1408         bool executeOk = execute();
1409
1410         DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
1411         DE_UNREF(executeOk);
1412         return TestCase::STOP;
1413 }
1414
1415 } // gls
1416 } // deqp