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