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