resolve merge conflicts of 76a147bf to deqp-dev
[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         if (!isGLSLVersionSupported(m_renderCtx.getType(), m_spec.targetVersion))
732                 TCU_THROW(NotSupportedError, (string(getGLSLVersionName(m_spec.targetVersion)) + " is not supported").c_str());
733
734         checkImplementationLimits(m_spec.requiredCaps, m_contextInfo);
735
736         // log the expected result
737         switch (m_spec.expectResult)
738         {
739                 case EXPECT_PASS:
740                         // Don't write anything
741                         break;
742
743                 case EXPECT_COMPILE_FAIL:
744                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
745                         break;
746
747                 case EXPECT_LINK_FAIL:
748                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
749                         break;
750
751                 case EXPECT_COMPILE_LINK_FAIL:
752                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
753                         break;
754
755                 case EXPECT_VALIDATION_FAIL:
756                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
757                         break;
758
759                 case EXPECT_BUILD_SUCCESSFUL:
760                         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
761                         break;
762
763                 default:
764                         DE_ASSERT(false);
765                         break;
766         }
767 }
768
769 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const Value& val, int arrayNdx, tcu::TestLog& log)
770 {
771         bool foundAnyMatch = false;
772
773         for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
774         {
775                 const DataType  dataType        = val.type.getBasicType();
776                 const int               scalarSize      = getDataTypeScalarSize(dataType);
777                 const int               loc                     = gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
778                 const int               elemNdx         = arrayNdx * scalarSize;
779
780                 DE_ASSERT(elemNdx+scalarSize <= (int)val.elements.size());
781
782                 if (loc == -1)
783                         continue;
784
785                 foundAnyMatch = true;
786
787                 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLfloat));
788                 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLint));
789
790                 gl.useProgram(pipelinePrograms[programNdx]);
791
792                 switch (dataType)
793                 {
794                         case TYPE_FLOAT:                gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
795                         case TYPE_FLOAT_VEC2:   gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
796                         case TYPE_FLOAT_VEC3:   gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
797                         case TYPE_FLOAT_VEC4:   gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);                                          break;
798                         case TYPE_FLOAT_MAT2:   gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
799                         case TYPE_FLOAT_MAT3:   gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
800                         case TYPE_FLOAT_MAT4:   gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);          break;
801                         case TYPE_INT:                  gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
802                         case TYPE_INT_VEC2:             gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
803                         case TYPE_INT_VEC3:             gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
804                         case TYPE_INT_VEC4:             gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
805                         case TYPE_BOOL:                 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
806                         case TYPE_BOOL_VEC2:    gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
807                         case TYPE_BOOL_VEC3:    gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
808                         case TYPE_BOOL_VEC4:    gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);                                            break;
809                         case TYPE_UINT:                 gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
810                         case TYPE_UINT_VEC2:    gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
811                         case TYPE_UINT_VEC3:    gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
812                         case TYPE_UINT_VEC4:    gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);          break;
813                         case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
814                         case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
815                         case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
816                         case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
817                         case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
818                         case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);        break;
819
820                         case TYPE_SAMPLER_2D:
821                         case TYPE_SAMPLER_CUBE:
822                                 DE_FATAL("implement!");
823                                 break;
824
825                         default:
826                                 DE_ASSERT(false);
827                 }
828         }
829
830         if (!foundAnyMatch)
831                 log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
832 }
833
834 static bool isTessellationPresent (const ShaderCaseSpecification& spec)
835 {
836         if (spec.programs[0].sources.separable)
837         {
838                 const deUint32 tessellationBits =       (1 << glu::SHADERTYPE_TESSELLATION_CONTROL)             |
839                                                                                         (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
840
841                 for (int programNdx = 0; programNdx < (int)spec.programs.size(); ++programNdx)
842                         if (spec.programs[programNdx].activeStages & tessellationBits)
843                                 return true;
844                 return false;
845         }
846         else
847                 return !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
848                            !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
849 }
850
851 static bool isTessellationSupported (const glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo)
852 {
853         if (renderCtx.getType().getProfile() == PROFILE_ES)
854         {
855                 const int       majorVer        = renderCtx.getType().getMajorVersion();
856                 const int       minorVer        = renderCtx.getType().getMinorVersion();
857
858                 return (majorVer > 3) || (majorVer == 3 && minorVer >= 2) ||
859                            ctxInfo.isExtensionSupported("GL_EXT_tessellation_shader");
860         }
861         else
862                 return false;
863 }
864
865 static bool checkPixels (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& surface)
866 {
867         bool    allWhite                = true;
868         bool    allBlack                = true;
869         bool    anyUnexpected   = false;
870
871         for (int y = 0; y < surface.getHeight(); y++)
872         {
873                 for (int x = 0; x < surface.getWidth(); x++)
874                 {
875                         const tcu::IVec4        pixel            = surface.getPixelInt(x, y);
876                         // Note: we really do not want to involve alpha in the check comparison
877                         // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
878                         const bool                      isWhite          = (pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255);
879                         const bool                      isBlack          = (pixel[0] ==   0) && (pixel[1] ==   0) && (pixel[2] ==   0);
880
881                         allWhite                = allWhite && isWhite;
882                         allBlack                = allBlack && isBlack;
883                         anyUnexpected   = anyUnexpected || (!isWhite && !isBlack);
884                 }
885         }
886
887         if (!allWhite)
888         {
889                 if (anyUnexpected)
890                         log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
891                 else if (!allBlack)
892                         log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
893
894                 return false;
895         }
896
897         return true;
898 }
899
900 bool ShaderLibraryCase::execute (void)
901 {
902         const float                                                     quadSize                                = 1.0f;
903         static const float                                      s_positions[4*4]                =
904         {
905                 -quadSize, -quadSize, 0.0f, 1.0f,
906                 -quadSize, +quadSize, 0.0f, 1.0f,
907                 +quadSize, -quadSize, 0.0f, 1.0f,
908                 +quadSize, +quadSize, 0.0f, 1.0f
909         };
910
911         static const deUint16                           s_indices[2*3]                  =
912         {
913                 0, 1, 2,
914                 1, 3, 2
915         };
916
917         TestLog&                                                        log                                             = m_testCtx.getLog();
918         const glw::Functions&                           gl                                              = m_renderCtx.getFunctions();
919
920         // Compute viewport.
921         const tcu::RenderTarget&                        renderTarget                    = m_renderCtx.getRenderTarget();
922         de::Random                                                      rnd                                             (deStringHash(getName()));
923         const int                                                       width                                   = deMin32(renderTarget.getWidth(),      VIEWPORT_WIDTH);
924         const int                                                       height                                  = deMin32(renderTarget.getHeight(),     VIEWPORT_HEIGHT);
925         const int                                                       viewportX                               = rnd.getInt(0, renderTarget.getWidth()  - width);
926         const int                                                       viewportY                               = rnd.getInt(0, renderTarget.getHeight() - height);
927         const int                                                       numVerticesPerDraw              = 4;
928         const bool                                                      tessellationPresent             = isTessellationPresent(m_spec);
929         const bool                                                      separablePrograms               = m_spec.programs[0].sources.separable;
930
931         bool                                                            allCompilesOk                   = true;
932         bool                                                            allLinksOk                              = true;
933         const char*                                                     failReason                              = DE_NULL;
934
935         vector<ProgramSources>                          specializedSources              (m_spec.programs.size());
936
937         deUint32                                                        vertexProgramID                 = -1;
938         vector<deUint32>                                        pipelineProgramIDs;
939         vector<SharedPtr<ShaderProgram> >       programs;
940         SharedPtr<ProgramPipeline>                      programPipeline;
941
942         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
943
944         // Specialize shaders
945         if (m_spec.caseType == CASETYPE_VERTEX_ONLY)
946         {
947                 const vector<RequiredExtension> reqExt  = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
948
949                 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX].size() == 1);
950                 specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX][0], reqExt))
951                                                           << glu::FragmentSource(genFragmentShader(m_spec));
952         }
953         else if (m_spec.caseType == CASETYPE_FRAGMENT_ONLY)
954         {
955                 const vector<RequiredExtension> reqExt  = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
956
957                 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].size() == 1);
958                 specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
959                                                           << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT][0], reqExt));
960         }
961         else
962         {
963                 DE_ASSERT(m_spec.caseType == CASETYPE_COMPLETE);
964
965                 const int       maxPatchVertices        = isTessellationPresent(m_spec) && isTessellationSupported(m_renderCtx, m_contextInfo)
966                                                                                 ? m_contextInfo.getInt(GL_MAX_PATCH_VERTICES) : 0;
967
968                 for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
969                 {
970                         const ProgramSpecializationParams       progSpecParams  (m_spec, checkAndSpecializeExtensions(m_spec.programs[progNdx].requiredExtensions, m_contextInfo), maxPatchVertices);
971
972                         specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
973                 }
974         }
975
976         if (!separablePrograms)
977         {
978                 de::SharedPtr<glu::ShaderProgram>       program         (new glu::ShaderProgram(m_renderCtx, specializedSources[0]));
979
980                 vertexProgramID = program->getProgram();
981                 pipelineProgramIDs.push_back(program->getProgram());
982                 programs.push_back(program);
983
984                 // Check that compile/link results are what we expect.
985
986                 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
987                 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
988                         if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
989                                 allCompilesOk = false;
990
991                 if (!program->getProgramInfo().linkOk)
992                         allLinksOk = false;
993
994                 log << *program;
995         }
996         else
997         {
998                 // Separate programs
999                 for (size_t programNdx = 0; programNdx < m_spec.programs.size(); ++programNdx)
1000                 {
1001                         de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, specializedSources[programNdx]));
1002
1003                         if (m_spec.programs[programNdx].activeStages & (1u << glu::SHADERTYPE_VERTEX))
1004                                 vertexProgramID = program->getProgram();
1005
1006                         pipelineProgramIDs.push_back(program->getProgram());
1007                         programs.push_back(program);
1008
1009                         // Check that compile/link results are what we expect.
1010
1011                         DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
1012                         for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1013                                 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
1014                                         allCompilesOk = false;
1015
1016                         if (!program->getProgramInfo().linkOk)
1017                                 allLinksOk = false;
1018
1019                         // Log program and active stages
1020                         {
1021                                 const tcu::ScopedLogSection     section         (log, "Program", "Program " + de::toString(programNdx+1));
1022                                 tcu::MessageBuilder                     builder         (&log);
1023                                 bool                                            firstStage      = true;
1024
1025                                 builder << "Pipeline uses stages: ";
1026                                 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1027                                 {
1028                                         if (m_spec.programs[programNdx].activeStages & (1u << stage))
1029                                         {
1030                                                 if (!firstStage)
1031                                                         builder << ", ";
1032                                                 builder << glu::getShaderTypeName((glu::ShaderType)stage);
1033                                                 firstStage = true;
1034                                         }
1035                                 }
1036                                 builder << tcu::TestLog::EndMessage;
1037
1038                                 log << *program;
1039                         }
1040                 }
1041         }
1042
1043         switch (m_spec.expectResult)
1044         {
1045                 case EXPECT_PASS:
1046                 case EXPECT_VALIDATION_FAIL:
1047                 case EXPECT_BUILD_SUCCESSFUL:
1048                         if (!allCompilesOk)
1049                                 failReason = "expected shaders to compile and link properly, but failed to compile.";
1050                         else if (!allLinksOk)
1051                                 failReason = "expected shaders to compile and link properly, but failed to link.";
1052                         break;
1053
1054                 case EXPECT_COMPILE_FAIL:
1055                         if (allCompilesOk && !allLinksOk)
1056                                 failReason = "expected compilation to fail, but shaders compiled and link failed.";
1057                         else if (allCompilesOk)
1058                                 failReason = "expected compilation to fail, but shaders compiled correctly.";
1059                         break;
1060
1061                 case EXPECT_LINK_FAIL:
1062                         if (!allCompilesOk)
1063                                 failReason = "expected linking to fail, but unable to compile.";
1064                         else if (allLinksOk)
1065                                 failReason = "expected linking to fail, but passed.";
1066                         break;
1067
1068                 case EXPECT_COMPILE_LINK_FAIL:
1069                         if (allCompilesOk && allLinksOk)
1070                                 failReason = "expected compile or link to fail, but passed.";
1071                         break;
1072
1073                 default:
1074                         DE_ASSERT(false);
1075                         return false;
1076         }
1077
1078         if (failReason != DE_NULL)
1079         {
1080                 // \todo [2010-06-07 petri] These should be handled in the test case?
1081                 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
1082
1083                 if (m_spec.fullGLSLES100Required)
1084                 {
1085                         log     << TestLog::Message
1086                                 << "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
1087                                 << TestLog::EndMessage;
1088
1089                         if (allCompilesOk && !allLinksOk)
1090                         {
1091                                 // Used features are detectable at compile time. If implementation parses shader
1092                                 // at link time, report it as quality warning.
1093                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
1094                         }
1095                         else
1096                                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
1097                 }
1098                 else if (m_spec.expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
1099                 {
1100                         // If implementation parses shader at link time, report it as quality warning.
1101                         m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
1102                 }
1103                 else
1104                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
1105                 return false;
1106         }
1107
1108         // Return if shader is not intended to be run
1109         if (m_spec.expectResult == EXPECT_COMPILE_FAIL          ||
1110                 m_spec.expectResult == EXPECT_COMPILE_LINK_FAIL ||
1111                 m_spec.expectResult == EXPECT_LINK_FAIL                 ||
1112                 m_spec.expectResult == EXPECT_BUILD_SUCCESSFUL)
1113                 return true;
1114
1115         // Setup viewport.
1116         gl.viewport(viewportX, viewportY, width, height);
1117
1118         if (separablePrograms)
1119         {
1120                 programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
1121
1122                 // Setup pipeline
1123                 gl.bindProgramPipeline(programPipeline->getPipeline());
1124                 for (int programNdx = 0; programNdx < (int)m_spec.programs.size(); ++programNdx)
1125                 {
1126                         deUint32 shaderFlags = 0;
1127                         for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1128                                 if (m_spec.programs[programNdx].activeStages & (1u << stage))
1129                                         shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
1130
1131                         programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
1132                 }
1133
1134                 programPipeline->activeShaderProgram(vertexProgramID);
1135                 GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
1136         }
1137         else
1138         {
1139                 // Start using program
1140                 gl.useProgram(vertexProgramID);
1141                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
1142         }
1143
1144         // Fetch location for positions positions.
1145         int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
1146         if (positionLoc == -1)
1147         {
1148                 string errStr = string("no location found for attribute 'dEQP_Position'");
1149                 TCU_FAIL(errStr.c_str());
1150         }
1151
1152         // Iterate all value blocks.
1153         {
1154                 const ValueBlock&       valueBlock              = m_spec.values;
1155
1156                 // always render at least one pass even if there is no input/output data
1157                 const int                       numRenderPasses = valueBlock.outputs.empty() ? 1 : (int)valueBlock.outputs[0].elements.size() / valueBlock.outputs[0].type.getScalarSize();
1158
1159                 // Iterate all array sub-cases.
1160                 for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
1161                 {
1162                         vector<VertexArrayBinding>      vertexArrays;
1163                         int                                                     attribValueNdx          = 0;
1164                         vector<vector<float> >          attribValues            (valueBlock.inputs.size());
1165                         glw::GLenum                                     postDrawError;
1166                         BeforeDrawValidator                     beforeDrawValidator     (gl,
1167                                                                                                                          (separablePrograms) ? (programPipeline->getPipeline())                 : (vertexProgramID),
1168                                                                                                                          (separablePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE)       : (BeforeDrawValidator::TARGETTYPE_PROGRAM));
1169
1170                         vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
1171
1172                         // Collect VA pointer for inputs
1173                         for (size_t valNdx = 0; valNdx < valueBlock.inputs.size(); valNdx++)
1174                         {
1175                                 const Value&            val                     = valueBlock.inputs[valNdx];
1176                                 const char* const       valueName       = val.name.c_str();
1177                                 const DataType          dataType        = val.type.getBasicType();
1178                                 const int                       scalarSize      = getDataTypeScalarSize(dataType);
1179
1180                                 // Replicate values four times.
1181                                 std::vector<float>& scalars = attribValues[attribValueNdx++];
1182                                 scalars.resize(numVerticesPerDraw * scalarSize);
1183                                 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
1184                                 {
1185                                         for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
1186                                                 for (int ndx = 0; ndx < scalarSize; ndx++)
1187                                                         scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
1188                                 }
1189                                 else
1190                                 {
1191                                         // convert to floats.
1192                                         for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
1193                                         {
1194                                                 for (int ndx = 0; ndx < scalarSize; ndx++)
1195                                                 {
1196                                                         float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
1197                                                         DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
1198                                                         scalars[repNdx*scalarSize + ndx] = v;
1199                                                 }
1200                                         }
1201                                 }
1202
1203                                 // Attribute name prefix.
1204                                 string attribPrefix = "";
1205                                 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
1206                                 if ((m_spec.caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
1207                                         attribPrefix = "a_";
1208
1209                                 // Input always given as attribute.
1210                                 string attribName = attribPrefix + valueName;
1211                                 int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
1212                                 if (attribLoc == -1)
1213                                 {
1214                                         log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
1215                                         continue;
1216                                 }
1217
1218                                 if (isDataTypeMatrix(dataType))
1219                                 {
1220                                         int numCols = getDataTypeMatrixNumColumns(dataType);
1221                                         int numRows = getDataTypeMatrixNumRows(dataType);
1222                                         DE_ASSERT(scalarSize == numCols*numRows);
1223
1224                                         for (int i = 0; i < numCols; i++)
1225                                                 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*(int)sizeof(float), &scalars[i * numRows]));
1226                                 }
1227                                 else
1228                                 {
1229                                         DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
1230                                         vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
1231                                 }
1232
1233                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
1234                         }
1235
1236                         GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
1237
1238                         // set reference values for outputs.
1239                         for (size_t valNdx = 0; valNdx < valueBlock.outputs.size(); valNdx++)
1240                         {
1241                                 const Value&            val                     = valueBlock.outputs[valNdx];
1242                                 const char* const       valueName       = val.name.c_str();
1243
1244                                 // Set reference value.
1245                                 string refName = string("ref_") + valueName;
1246                                 setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
1247                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
1248                         }
1249
1250                         // set uniform values
1251                         for (size_t valNdx = 0; valNdx < valueBlock.uniforms.size(); valNdx++)
1252                         {
1253                                 const Value&            val                     = valueBlock.uniforms[valNdx];
1254                                 const char* const       valueName       = val.name.c_str();
1255
1256                                 setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
1257                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
1258                         }
1259
1260                         // Clear.
1261                         gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
1262                         gl.clear(GL_COLOR_BUFFER_BIT);
1263                         GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1264
1265                         // Use program or pipeline
1266                         if (separablePrograms)
1267                                 gl.useProgram(0);
1268                         else
1269                                 gl.useProgram(vertexProgramID);
1270
1271                         // Draw.
1272                         if (tessellationPresent)
1273                         {
1274                                 gl.patchParameteri(GL_PATCH_VERTICES, 3);
1275                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
1276                         }
1277
1278                         draw(m_renderCtx,
1279                                  vertexProgramID,
1280                                  (int)vertexArrays.size(),
1281                                  &vertexArrays[0],
1282                                  (tessellationPresent) ?
1283                                         (pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
1284                                         (pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
1285                                  (m_spec.expectResult == EXPECT_VALIDATION_FAIL) ?
1286                                         (&beforeDrawValidator) :
1287                                         (DE_NULL));
1288
1289                         postDrawError = gl.getError();
1290
1291                         if (m_spec.expectResult == EXPECT_PASS)
1292                         {
1293                                 // Read back results.
1294                                 Surface                 surface                 (width, height);
1295                                 const float             w                               = s_positions[3];
1296                                 const int               minY                    = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
1297                                 const int               maxY                    = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
1298                                 const int               minX                    = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
1299                                 const int               maxX                    = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
1300
1301                                 GLU_EXPECT_NO_ERROR(postDrawError, "draw");
1302
1303                                 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
1304                                 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
1305
1306                                 if (!checkPixels(log, tcu::getSubregion(surface.getAccess(), minX, minY, maxX-minX+1, maxY-minY+1)))
1307                                 {
1308                                         log << TestLog::Message << "INCORRECT RESULT for sub-case " << arrayNdx+1 << " of " << numRenderPasses << "):"
1309                                                 << TestLog::EndMessage;
1310
1311                                         log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
1312                                         dumpValues(log, valueBlock, arrayNdx);
1313
1314                                         // Dump image on failure.
1315                                         log << TestLog::Image("Result", "Rendered result image", surface);
1316
1317                                         gl.useProgram(0);
1318                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1319                                         return false;
1320                                 }
1321                         }
1322                         else if (m_spec.expectResult == EXPECT_VALIDATION_FAIL)
1323                         {
1324                                 log     << TestLog::Message
1325                                         << "Draw call generated error: "
1326                                         << glu::getErrorStr(postDrawError) << " "
1327                                         << ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
1328                                         << "Validate status: "
1329                                         << glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
1330                                         << ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
1331                                         << "Info log: "
1332                                         << ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
1333                                         << TestLog::EndMessage;
1334
1335                                 // test result
1336
1337                                 if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
1338                                 {
1339                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
1340                                         return false;
1341                                 }
1342
1343                                 if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
1344                                 {
1345                                         if (postDrawError == GL_NO_ERROR)
1346                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
1347                                         else if (postDrawError == GL_INVALID_OPERATION)
1348                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
1349                                         else
1350                                                 DE_ASSERT(false);
1351                                         return false;
1352                                 }
1353                                 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
1354                                 {
1355                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
1356                                         return false;
1357                                 }
1358                                 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
1359                                 {
1360                                         // Validation does not depend on input values, no need to test all values
1361                                         return true;
1362                                 }
1363                                 else
1364                                         DE_ASSERT(false);
1365                         }
1366                         else
1367                                 DE_ASSERT(false);
1368                 }
1369         }
1370
1371         gl.useProgram(0);
1372         if (separablePrograms)
1373                 gl.bindProgramPipeline(0);
1374
1375         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
1376         return true;
1377 }
1378
1379 TestCase::IterateResult ShaderLibraryCase::iterate (void)
1380 {
1381         // Initialize state to pass.
1382         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1383
1384         bool executeOk = execute();
1385
1386         DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
1387         DE_UNREF(executeOk);
1388         return TestCase::STOP;
1389 }
1390
1391 } // gls
1392 } // deqp