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