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