blob: 70ea5e2ac21ed7d2754e66449c84d8a53ca97d43 [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001/*-------------------------------------------------------------------------
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"
Pyry Haulosfb193242015-09-01 13:56:41 -070028#include "tcuTextureUtil.hpp"
29#include "tcuSurface.hpp"
Jarkko Poyry3c827362014-09-02 11:48:52 +030030
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
Jarkko Poyry3c827362014-09-02 11:48:52 +030053namespace deqp
54{
55namespace gls
56{
Pyry Haulos877323d2015-09-01 13:56:41 -070057
Pyry Haulosfb193242015-09-01 13:56:41 -070058using namespace tcu;
59using namespace glu;
60using namespace glu::sl;
Pyry Haulos877323d2015-09-01 13:56:41 -070061
Pyry Haulosfb193242015-09-01 13:56:41 -070062using std::vector;
63using std::string;
64using std::ostringstream;
65using std::map;
66using std::pair;
67
68using de::SharedPtr;
69
70// OpenGL-specific specialization utils
71
72static vector<RequiredExtension> checkAndSpecializeExtensions (const vector<RequiredExtension>& src,
73 const ContextInfo& ctxInfo)
Pyry Haulos877323d2015-09-01 13:56:41 -070074{
Pyry Haulosfb193242015-09-01 13:56:41 -070075 vector<RequiredExtension> specialized;
76
77 for (size_t extNdx = 0; extNdx < src.size(); ++extNdx)
Pyry Haulos877323d2015-09-01 13:56:41 -070078 {
Pyry Haulosfb193242015-09-01 13:56:41 -070079 const RequiredExtension& extension = src[extNdx];
80 int supportedAltNdx = -1;
Pyry Haulos877323d2015-09-01 13:56:41 -070081
Pyry Haulosfb193242015-09-01 13:56:41 -070082 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 }
Pyry Haulos877323d2015-09-01 13:56:41 -0700112 }
Pyry Haulosfb193242015-09-01 13:56:41 -0700113
114 return specialized;
115}
116
117static void checkImplementationLimits (const vector<RequiredCapability>& requiredCaps,
118 const ContextInfo& ctxInfo)
119{
120 for (size_t capNdx = 0; capNdx < requiredCaps.size(); ++capNdx)
121 {
122 const deUint32 pname = requiredCaps[capNdx].enumName;
123 const int requiredValue = requiredCaps[capNdx].referenceValue;
124 const int supportedValue = ctxInfo.getInt((int)pname);
125
126 if (supportedValue <= requiredValue)
127 throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " (" + de::toString(supportedValue) + ") >= " + de::toString(requiredValue));
128 }
129}
130
131// Shader source specialization
132
133// This functions builds a matching vertex shader for a 'both' case, when
134// the fragment shader is being tested.
135// We need to build attributes and varyings for each 'input'.
136static string genVertexShader (const ShaderCaseSpecification& spec)
137{
138 ostringstream res;
139 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion);
140 const char* const vtxIn = usesInout ? "in" : "attribute";
141 const char* const vtxOut = usesInout ? "out" : "varying";
142
143 res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
144
145 // Declarations (position + attribute/varying for each input).
146 res << "precision highp float;\n";
147 res << "precision highp int;\n";
148 res << "\n";
149 res << vtxIn << " highp vec4 dEQP_Position;\n";
150
151 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
152 {
153 const Value& val = spec.values.inputs[ndx];
154 const DataType basicType = val.type.getBasicType();
155 const DataType floatType = getDataTypeFloatScalars(basicType);
156 const char* const typeStr = getDataTypeName(floatType);
157
158 res << vtxIn << " " << typeStr << " a_" << val.name << ";\n";
159
160 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
161 res << vtxOut << " " << typeStr << " " << val.name << ";\n";
162 else
163 res << vtxOut << " " << typeStr << " v_" << val.name << ";\n";
164 }
165 res << "\n";
166
167 // Main function.
168 // - gl_Position = dEQP_Position;
169 // - for each input: write attribute directly to varying
170 res << "void main()\n";
171 res << "{\n";
172 res << " gl_Position = dEQP_Position;\n";
173 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
174 {
175 const Value& val = spec.values.inputs[ndx];
176 const string& name = val.name;
177
178 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
179 res << " " << name << " = a_" << name << ";\n";
180 else
181 res << " v_" << name << " = a_" << name << ";\n";
182 }
183
184 res << "}\n";
185 return res.str();
186}
187
188static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName)
189{
190 bool isFirstOutput = true;
191
192 for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++)
193 {
194 const Value& val = valueBlock.outputs[ndx];
195
196 // Check if we're only interested in one variable (then skip if not the right one).
197 if (checkVarName && val.name != checkVarName)
198 continue;
199
200 // Prefix.
201 if (isFirstOutput)
202 {
203 output << "bool RES = ";
204 isFirstOutput = false;
205 }
206 else
207 output << "RES = RES && ";
208
209 // Generate actual comparison.
210 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
211 output << "isOk(" << val.name << ", ref_" << val.name << ", 0.05);\n";
212 else
213 output << "isOk(" << nonFloatNamePrefix << val.name << ", ref_" << val.name << ");\n";
214 }
215
216 if (isFirstOutput)
217 output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case?
218 else
219 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
Jarkko Poyry3c827362014-09-02 11:48:52 +0300220}
221
222static inline bool supportsFragmentHighp (glu::GLSLVersion version)
223{
224 return version != glu::GLSL_VERSION_100_ES;
225}
226
Pyry Haulosfb193242015-09-01 13:56:41 -0700227static string genFragmentShader (const ShaderCaseSpecification& spec)
Jarkko Pöyryc611ca52015-06-09 19:08:33 -0700228{
Pyry Haulosfb193242015-09-01 13:56:41 -0700229 ostringstream shader;
230 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion);
231 const bool customColorOut = usesInout;
232 const char* const fragIn = usesInout ? "in" : "varying";
233 const char* const prec = supportsFragmentHighp(spec.targetVersion) ? "highp" : "mediump";
Jarkko Pöyryc611ca52015-06-09 19:08:33 -0700234
Pyry Haulosfb193242015-09-01 13:56:41 -0700235 shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
Jarkko Pöyryc611ca52015-06-09 19:08:33 -0700236
Pyry Haulosfb193242015-09-01 13:56:41 -0700237 shader << "precision " << prec << " float;\n";
238 shader << "precision " << prec << " int;\n";
239 shader << "\n";
Pyry Haulos877323d2015-09-01 13:56:41 -0700240
Pyry Haulosfb193242015-09-01 13:56:41 -0700241 if (customColorOut)
Pyry Haulos877323d2015-09-01 13:56:41 -0700242 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700243 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
244 shader << "\n";
245 }
246
247 genCompareFunctions(shader, spec.values, true);
248 shader << "\n";
249
250 // Declarations (varying, reference for each output).
251 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
252 {
253 const Value& val = spec.values.outputs[ndx];
254 const DataType basicType = val.type.getBasicType();
255 const DataType floatType = getDataTypeFloatScalars(basicType);
256 const char* const floatTypeStr = getDataTypeName(floatType);
257 const char* const refTypeStr = getDataTypeName(basicType);
258
259 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
260 shader << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
261 else
262 shader << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
263
264 shader << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
265 }
266
267 shader << "\n";
268 shader << "void main()\n";
269 shader << "{\n";
270
271 shader << " ";
272 genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", spec.values, "v_", DE_NULL);
273
274 shader << "}\n";
275 return shader.str();
276}
277
278// Specialize a shader for the vertex shader test case.
Pyry Haulos677e4642015-09-30 10:00:12 -0700279static string specializeVertexShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
Pyry Haulosfb193242015-09-01 13:56:41 -0700280{
281 ostringstream decl;
282 ostringstream setup;
283 ostringstream output;
284 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion);
285 const char* const vtxIn = usesInout ? "in" : "attribute";
286 const char* const vtxOut = usesInout ? "out" : "varying";
287
288 // generated from "both" case
289 DE_ASSERT(spec.caseType == CASETYPE_VERTEX_ONLY);
290
291 // Output (write out position).
292 output << "gl_Position = dEQP_Position;\n";
293
294 // Declarations (position + attribute for each input, varying for each output).
295 decl << vtxIn << " highp vec4 dEQP_Position;\n";
296
297 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
298 {
299 const Value& val = spec.values.inputs[ndx];
300 const DataType basicType = val.type.getBasicType();
301 const DataType floatType = getDataTypeFloatScalars(basicType);
302 const char* const floatTypeStr = getDataTypeName(floatType);
303 const char* const refTypeStr = getDataTypeName(basicType);
304
305 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300306 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700307 decl << vtxIn << " " << floatTypeStr << " " << val.name << ";\n";
Jarkko Poyry3c827362014-09-02 11:48:52 +0300308 }
Pyry Haulosfb193242015-09-01 13:56:41 -0700309 else
Jarkko Poyry3c827362014-09-02 11:48:52 +0300310 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700311 decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
312 setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(a_" << val.name << ");\n";
Jarkko Poyry3c827362014-09-02 11:48:52 +0300313 }
Pyry Haulosfb193242015-09-01 13:56:41 -0700314 }
Jarkko Poyry3c827362014-09-02 11:48:52 +0300315
Pyry Haulosfb193242015-09-01 13:56:41 -0700316 // \todo [2015-07-24 pyry] Why are uniforms missing?
317
318 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
319 {
320 const Value& val = spec.values.outputs[ndx];
321 const DataType basicType = val.type.getBasicType();
322 const DataType floatType = getDataTypeFloatScalars(basicType);
323 const char* const floatTypeStr = getDataTypeName(floatType);
324 const char* const refTypeStr = getDataTypeName(basicType);
325
326 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
327 decl << vtxOut << " " << floatTypeStr << " " << val.name << ";\n";
328 else
Jarkko Pöyry789ca932015-03-12 14:23:10 -0700329 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700330 decl << vtxOut << " " << floatTypeStr << " v_" << val.name << ";\n";
331 decl << refTypeStr << " " << val.name << ";\n";
Pyry Haulos877323d2015-09-01 13:56:41 -0700332
Pyry Haulosfb193242015-09-01 13:56:41 -0700333 output << "v_" << val.name << " = " << floatTypeStr << "(" << val.name << ");\n";
334 }
335 }
336
337 // Shader specialization.
338 map<string, string> params;
339 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
340 params.insert(pair<string, string>("SETUP", setup.str()));
341 params.insert(pair<string, string>("OUTPUT", output.str()));
342 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
343
344 StringTemplate tmpl (src);
345 const string baseSrc = tmpl.specialize(params);
Pyry Haulos677e4642015-09-30 10:00:12 -0700346 const string withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_VERTEX);
Pyry Haulosfb193242015-09-01 13:56:41 -0700347
348 return withExt;
349}
350
351// Specialize a shader for the fragment shader test case.
Pyry Haulos677e4642015-09-30 10:00:12 -0700352static string specializeFragmentShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
Pyry Haulosfb193242015-09-01 13:56:41 -0700353{
354 ostringstream decl;
355 ostringstream setup;
356 ostringstream output;
357
358 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion);
359 const bool customColorOut = usesInout;
360 const char* const fragIn = usesInout ? "in" : "varying";
361 const char* const fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
362
363 // generated from "both" case
364 DE_ASSERT(spec.caseType == CASETYPE_FRAGMENT_ONLY);
365
366 genCompareFunctions(decl, spec.values, false);
367 genCompareOp(output, fragColor, spec.values, "", DE_NULL);
368
369 if (customColorOut)
370 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
371
372 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
373 {
374 const Value& val = spec.values.inputs[ndx];
375 const DataType basicType = val.type.getBasicType();
376 const DataType floatType = getDataTypeFloatScalars(basicType);
377 const char* const floatTypeStr = getDataTypeName(floatType);
378 const char* const refTypeStr = getDataTypeName(basicType);
379
380 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
381 decl << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
382 else
383 {
384 decl << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
385 std::string offset = isDataTypeIntOrIVec(basicType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
386 setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(v_" << val.name << offset << ");\n";
387 }
388 }
389
390 // \todo [2015-07-24 pyry] Why are uniforms missing?
391
392 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
393 {
394 const Value& val = spec.values.outputs[ndx];
395 const DataType basicType = val.type.getBasicType();
396 const char* const refTypeStr = getDataTypeName(basicType);
397
398 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
399 decl << refTypeStr << " " << val.name << ";\n";
400 }
401
402 /* \todo [2010-04-01 petri] Check all outputs. */
403
404 // Shader specialization.
405 map<string, string> params;
406 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
407 params.insert(pair<string, string>("SETUP", setup.str()));
408 params.insert(pair<string, string>("OUTPUT", output.str()));
409 params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
410
411 StringTemplate tmpl (src);
412 const string baseSrc = tmpl.specialize(params);
Pyry Haulos677e4642015-09-30 10:00:12 -0700413 const string withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_FRAGMENT);
Pyry Haulosfb193242015-09-01 13:56:41 -0700414
415 return withExt;
416}
417
418static void generateUniformDeclarations (std::ostream& dst, const ValueBlock& valueBlock)
419{
420 for (size_t ndx = 0; ndx < valueBlock.uniforms.size(); ndx++)
421 {
422 const Value& val = valueBlock.uniforms[ndx];
423 const char* const typeStr = getDataTypeName(val.type.getBasicType());
424
425 if (val.name.find('.') == string::npos)
426 dst << "uniform " << typeStr << " " << val.name << ";\n";
Jarkko Poyry3c827362014-09-02 11:48:52 +0300427 }
428}
429
Pyry Haulosfb193242015-09-01 13:56:41 -0700430static map<string, string> generateVertexSpecialization (const ProgramSpecializationParams& specParams)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300431{
Pyry Haulosfb193242015-09-01 13:56:41 -0700432 const bool usesInout = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
433 const char* vtxIn = usesInout ? "in" : "attribute";
434 ostringstream decl;
435 ostringstream setup;
436 map<string, string> params;
437
438 decl << vtxIn << " highp vec4 dEQP_Position;\n";
439
440 for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++)
441 {
442 const Value& val = specParams.caseSpec.values.inputs[ndx];
443 const DataType basicType = val.type.getBasicType();
444 const char* const typeStr = getDataTypeName(val.type.getBasicType());
445
446 if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
447 {
448 decl << vtxIn << " " << typeStr << " " << val.name << ";\n";
449 }
450 else
451 {
452 const DataType floatType = getDataTypeFloatScalars(basicType);
453 const char* const floatTypeStr = getDataTypeName(floatType);
454
455 decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
456 setup << typeStr << " " << val.name << " = " << typeStr << "(a_" << val.name << ");\n";
457 }
458 }
459
460 generateUniformDeclarations(decl, specParams.caseSpec.values);
461
462 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str()));
463 params.insert(pair<string, string>("VERTEX_SETUP", setup.str()));
464 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n")));
465
466 return params;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300467}
468
Pyry Haulosfb193242015-09-01 13:56:41 -0700469static map<string, string> generateFragmentSpecialization (const ProgramSpecializationParams& specParams)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300470{
Pyry Haulosfb193242015-09-01 13:56:41 -0700471 const bool usesInout = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
472 const bool customColorOut = usesInout;
473 const char* const fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
474 ostringstream decl;
475 ostringstream output;
476 map<string, string> params;
477
478 genCompareFunctions(decl, specParams.caseSpec.values, false);
479 genCompareOp(output, fragColor, specParams.caseSpec.values, "", DE_NULL);
480
481 if (customColorOut)
482 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
483
484 for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++)
485 {
486 const Value& val = specParams.caseSpec.values.outputs[ndx];
487 const char* const refTypeStr = getDataTypeName(val.type.getBasicType());
488
489 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
490 decl << refTypeStr << " " << val.name << ";\n";
491 }
492
493 generateUniformDeclarations(decl, specParams.caseSpec.values);
494
495 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str()));
496 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str()));
497 params.insert(pair<string, string>("FRAG_COLOR", fragColor));
498
499 return params;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300500}
501
Pyry Haulosfb193242015-09-01 13:56:41 -0700502static map<string, string> generateGeometrySpecialization (const ProgramSpecializationParams& specParams)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300503{
Pyry Haulosfb193242015-09-01 13:56:41 -0700504 ostringstream decl;
505 map<string, string> params;
506
507 decl << "layout (triangles) in;\n";
508 decl << "layout (triangle_strip, max_vertices=3) out;\n";
509 decl << "\n";
510
511 generateUniformDeclarations(decl, specParams.caseSpec.values);
512
513 params.insert(pair<string, string>("GEOMETRY_DECLARATIONS", decl.str()));
514
515 return params;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300516}
517
Pyry Haulosfb193242015-09-01 13:56:41 -0700518static map<string, string> generateTessControlSpecialization (const ProgramSpecializationParams& specParams)
519{
520 ostringstream decl;
521 ostringstream output;
522 map<string, string> params;
523
524 decl << "layout (vertices=3) out;\n";
525 decl << "\n";
526
527 generateUniformDeclarations(decl, specParams.caseSpec.values);
528
529 output << "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
530 "gl_TessLevelInner[0] = 2.0;\n"
531 "gl_TessLevelInner[1] = 2.0;\n"
532 "gl_TessLevelOuter[0] = 2.0;\n"
533 "gl_TessLevelOuter[1] = 2.0;\n"
534 "gl_TessLevelOuter[2] = 2.0;\n"
535 "gl_TessLevelOuter[3] = 2.0;";
536
537 params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS", decl.str()));
538 params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT", output.str()));
539 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices)));
540
541 return params;
542}
543
544static map<string, string> generateTessEvalSpecialization (const ProgramSpecializationParams& specParams)
545{
546 ostringstream decl;
547 ostringstream output;
548 map<string, string> params;
549
550 decl << "layout (triangles) in;\n";
551 decl << "\n";
552
553 generateUniformDeclarations(decl, specParams.caseSpec.values);
554
555 output << "gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n";
556
557 params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS", decl.str()));
558 params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT", output.str()));
559 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices)));
560
561 return params;
562}
563
564static void specializeShaderSources (ProgramSources& dst,
565 const ProgramSources& src,
566 const ProgramSpecializationParams& specParams,
567 glu::ShaderType shaderType,
568 map<string, string> (*specializationGenerator) (const ProgramSpecializationParams& specParams))
569{
570 if (!src.sources[shaderType].empty())
571 {
572 const map<string, string> tmplParams = specializationGenerator(specParams);
573
574 for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx)
575 {
576 const StringTemplate tmpl (src.sources[shaderType][ndx]);
577 const std::string baseGLSLCode = tmpl.specialize(tmplParams);
578 const std::string sourceWithExts = injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType);
579
580 dst << glu::ShaderSource(shaderType, sourceWithExts);
581 }
582 }
583}
584
585static void specializeProgramSources (glu::ProgramSources& dst,
586 const glu::ProgramSources& src,
587 const ProgramSpecializationParams& specParams)
588{
589 specializeShaderSources(dst, src, specParams, SHADERTYPE_VERTEX, generateVertexSpecialization);
590 specializeShaderSources(dst, src, specParams, SHADERTYPE_FRAGMENT, generateFragmentSpecialization);
591 specializeShaderSources(dst, src, specParams, SHADERTYPE_GEOMETRY, generateGeometrySpecialization);
592 specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_CONTROL, generateTessControlSpecialization);
593 specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_EVALUATION, generateTessEvalSpecialization);
594
595 dst << ProgramSeparable(src.separable);
596}
597
598enum
599{
600 VIEWPORT_WIDTH = 128,
601 VIEWPORT_HEIGHT = 128
602};
603
Jarkko Poyry3c827362014-09-02 11:48:52 +0300604class BeforeDrawValidator : public glu::DrawUtilCallback
605{
606public:
607 enum TargetType
608 {
609 TARGETTYPE_PROGRAM = 0,
610 TARGETTYPE_PIPELINE,
611
612 TARGETTYPE_LAST
613 };
614
615 BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType);
616
617 void beforeDrawCall (void);
618
619 const std::string& getInfoLog (void) const;
620 glw::GLint getValidateStatus (void) const;
621
622private:
623 const glw::Functions& m_gl;
624 const glw::GLuint m_target;
625 const TargetType m_targetType;
626
627 glw::GLint m_validateStatus;
628 std::string m_logMessage;
629};
630
631BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType)
632 : m_gl (gl)
633 , m_target (target)
634 , m_targetType (targetType)
635 , m_validateStatus (-1)
636{
637 DE_ASSERT(targetType < TARGETTYPE_LAST);
638}
639
640void BeforeDrawValidator::beforeDrawCall (void)
641{
642 glw::GLint bytesWritten = 0;
643 glw::GLint infoLogLength;
644 std::vector<glw::GLchar> logBuffer;
645 int stringLength;
646
647 // validate
648 if (m_targetType == TARGETTYPE_PROGRAM)
649 m_gl.validateProgram(m_target);
650 else if (m_targetType == TARGETTYPE_PIPELINE)
651 m_gl.validateProgramPipeline(m_target);
652 else
653 DE_ASSERT(false);
654
655 GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate");
656
657 // check status
658 m_validateStatus = -1;
659
660 if (m_targetType == TARGETTYPE_PROGRAM)
661 m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
662 else if (m_targetType == TARGETTYPE_PIPELINE)
663 m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
664 else
665 DE_ASSERT(false);
666
667 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status");
668 TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE);
669
670 // read log
671
672 infoLogLength = 0;
673
674 if (m_targetType == TARGETTYPE_PROGRAM)
675 m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
676 else if (m_targetType == TARGETTYPE_PIPELINE)
677 m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
678 else
679 DE_ASSERT(false);
680
681 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length");
682
683 if (infoLogLength <= 0)
684 {
685 m_logMessage.clear();
686 return;
687 }
688
689 logBuffer.resize(infoLogLength + 2, '0'); // +1 for zero terminator (infoLogLength should include it, but better play it safe), +1 to make sure buffer is always larger
690
691 if (m_targetType == TARGETTYPE_PROGRAM)
692 m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
693 else if (m_targetType == TARGETTYPE_PIPELINE)
694 m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
695 else
696 DE_ASSERT(false);
697
698 // just ignore bytesWritten to be safe, find the null terminator
699 stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin());
700 m_logMessage.assign(&logBuffer[0], stringLength);
701}
702
703const std::string& BeforeDrawValidator::getInfoLog (void) const
704{
705 return m_logMessage;
706}
707
708glw::GLint BeforeDrawValidator::getValidateStatus (void) const
709{
710 return m_validateStatus;
711}
712
713// ShaderCase.
714
Pyry Haulosfb193242015-09-01 13:56:41 -0700715ShaderLibraryCase::ShaderLibraryCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification)
716 : tcu::TestCase (testCtx, name, description)
717 , m_renderCtx (renderCtx)
718 , m_contextInfo (contextInfo)
719 , m_spec (specification)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300720{
721}
722
Pyry Haulosfb193242015-09-01 13:56:41 -0700723ShaderLibraryCase::~ShaderLibraryCase (void)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300724{
Pyry Haulosfb193242015-09-01 13:56:41 -0700725}
Jarkko Poyry3c827362014-09-02 11:48:52 +0300726
Pyry Haulosfb193242015-09-01 13:56:41 -0700727void ShaderLibraryCase::init (void)
728{
729 DE_ASSERT(isValid(m_spec));
Jarkko Poyry3c827362014-09-02 11:48:52 +0300730
Pyry Haulosfb193242015-09-01 13:56:41 -0700731 checkImplementationLimits(m_spec.requiredCaps, m_contextInfo);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300732
733 // log the expected result
Pyry Haulosfb193242015-09-01 13:56:41 -0700734 switch (m_spec.expectResult)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300735 {
736 case EXPECT_PASS:
737 // Don't write anything
738 break;
739
740 case EXPECT_COMPILE_FAIL:
741 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
742 break;
743
744 case EXPECT_LINK_FAIL:
745 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
746 break;
747
748 case EXPECT_COMPILE_LINK_FAIL:
749 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
750 break;
751
752 case EXPECT_VALIDATION_FAIL:
753 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
754 break;
755
Jarkko Pöyry9e574352014-12-16 11:33:56 -0800756 case EXPECT_BUILD_SUCCESSFUL:
757 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
758 break;
759
Jarkko Poyry3c827362014-09-02 11:48:52 +0300760 default:
761 DE_ASSERT(false);
762 break;
763 }
764}
765
Pyry Haulosfb193242015-09-01 13:56:41 -0700766static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const Value& val, int arrayNdx, tcu::TestLog& log)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300767{
768 bool foundAnyMatch = false;
769
770 for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
771 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700772 const DataType dataType = val.type.getBasicType();
773 const int scalarSize = getDataTypeScalarSize(dataType);
774 const int loc = gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
775 const int elemNdx = arrayNdx * scalarSize;
776
777 DE_ASSERT(elemNdx+scalarSize <= (int)val.elements.size());
Jarkko Poyry3c827362014-09-02 11:48:52 +0300778
779 if (loc == -1)
780 continue;
781
782 foundAnyMatch = true;
783
Pyry Haulosfb193242015-09-01 13:56:41 -0700784 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLfloat));
785 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLint));
Jarkko Poyry3c827362014-09-02 11:48:52 +0300786
787 gl.useProgram(pipelinePrograms[programNdx]);
788
Pyry Haulosfb193242015-09-01 13:56:41 -0700789 switch (dataType)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300790 {
791 case TYPE_FLOAT: gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32); break;
792 case TYPE_FLOAT_VEC2: gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32); break;
793 case TYPE_FLOAT_VEC3: gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32); break;
794 case TYPE_FLOAT_VEC4: gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32); break;
795 case TYPE_FLOAT_MAT2: gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
796 case TYPE_FLOAT_MAT3: gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
797 case TYPE_FLOAT_MAT4: gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
798 case TYPE_INT: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break;
799 case TYPE_INT_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break;
800 case TYPE_INT_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break;
801 case TYPE_INT_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break;
802 case TYPE_BOOL: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break;
803 case TYPE_BOOL_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break;
804 case TYPE_BOOL_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break;
805 case TYPE_BOOL_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break;
806 case TYPE_UINT: gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break;
807 case TYPE_UINT_VEC2: gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break;
808 case TYPE_UINT_VEC3: gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break;
809 case TYPE_UINT_VEC4: gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break;
810 case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
811 case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
812 case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
813 case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
814 case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
815 case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break;
816
817 case TYPE_SAMPLER_2D:
818 case TYPE_SAMPLER_CUBE:
Jarkko Pöyry1cc61b72015-05-29 16:36:30 -0700819 DE_FATAL("implement!");
Jarkko Poyry3c827362014-09-02 11:48:52 +0300820 break;
821
822 default:
823 DE_ASSERT(false);
824 }
825 }
826
827 if (!foundAnyMatch)
828 log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
829}
830
Pyry Haulosfb193242015-09-01 13:56:41 -0700831static bool isTessellationPresent (const ShaderCaseSpecification& spec)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300832{
Pyry Haulosfb193242015-09-01 13:56:41 -0700833 if (spec.programs[0].sources.separable)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300834 {
835 const deUint32 tessellationBits = (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) |
836 (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
837
Pyry Haulosfb193242015-09-01 13:56:41 -0700838 for (int programNdx = 0; programNdx < (int)spec.programs.size(); ++programNdx)
839 if (spec.programs[programNdx].activeStages & tessellationBits)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300840 return true;
841 return false;
842 }
843 else
Pyry Haulosfb193242015-09-01 13:56:41 -0700844 return !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
845 !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
Jarkko Poyry3c827362014-09-02 11:48:52 +0300846}
847
Pyry Haulosed67acb2015-10-13 13:06:24 -0700848static bool isTessellationSupported (const glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo)
849{
850 if (renderCtx.getType().getProfile() == PROFILE_ES)
851 {
852 const int majorVer = renderCtx.getType().getMajorVersion();
853 const int minorVer = renderCtx.getType().getMinorVersion();
854
855 return (majorVer > 3) || (majorVer == 3 && minorVer >= 2) ||
856 ctxInfo.isExtensionSupported("GL_EXT_tessellation_shader");
857 }
858 else
859 return false;
860}
861
Pyry Haulosfb193242015-09-01 13:56:41 -0700862static bool checkPixels (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& surface)
Jarkko Pöyry789ca932015-03-12 14:23:10 -0700863{
Pyry Haulosfb193242015-09-01 13:56:41 -0700864 bool allWhite = true;
865 bool allBlack = true;
866 bool anyUnexpected = false;
867
868 for (int y = 0; y < surface.getHeight(); y++)
Jarkko Pöyry789ca932015-03-12 14:23:10 -0700869 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700870 for (int x = 0; x < surface.getWidth(); x++)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300871 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700872 const tcu::IVec4 pixel = surface.getPixelInt(x, y);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300873 // Note: we really do not want to involve alpha in the check comparison
874 // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
Pyry Haulosfb193242015-09-01 13:56:41 -0700875 const bool isWhite = (pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255);
876 const bool isBlack = (pixel[0] == 0) && (pixel[1] == 0) && (pixel[2] == 0);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300877
878 allWhite = allWhite && isWhite;
879 allBlack = allBlack && isBlack;
880 anyUnexpected = anyUnexpected || (!isWhite && !isBlack);
881 }
882 }
883
884 if (!allWhite)
885 {
886 if (anyUnexpected)
887 log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
888 else if (!allBlack)
889 log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
890
891 return false;
892 }
Pyry Haulosfb193242015-09-01 13:56:41 -0700893
Jarkko Poyry3c827362014-09-02 11:48:52 +0300894 return true;
895}
896
Pyry Haulosfb193242015-09-01 13:56:41 -0700897bool ShaderLibraryCase::execute (void)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300898{
Pyry Haulosfb193242015-09-01 13:56:41 -0700899 const float quadSize = 1.0f;
900 static const float s_positions[4*4] =
Jarkko Poyry3c827362014-09-02 11:48:52 +0300901 {
902 -quadSize, -quadSize, 0.0f, 1.0f,
903 -quadSize, +quadSize, 0.0f, 1.0f,
904 +quadSize, -quadSize, 0.0f, 1.0f,
905 +quadSize, +quadSize, 0.0f, 1.0f
906 };
907
Pyry Haulosfb193242015-09-01 13:56:41 -0700908 static const deUint16 s_indices[2*3] =
Jarkko Poyry3c827362014-09-02 11:48:52 +0300909 {
910 0, 1, 2,
911 1, 3, 2
912 };
913
Pyry Haulosfb193242015-09-01 13:56:41 -0700914 TestLog& log = m_testCtx.getLog();
915 const glw::Functions& gl = m_renderCtx.getFunctions();
Jarkko Poyry3c827362014-09-02 11:48:52 +0300916
917 // Compute viewport.
Pyry Haulosfb193242015-09-01 13:56:41 -0700918 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget();
919 de::Random rnd (deStringHash(getName()));
920 const int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH);
921 const int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT);
922 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - width);
923 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - height);
924 const int numVerticesPerDraw = 4;
925 const bool tessellationPresent = isTessellationPresent(m_spec);
926 const bool separablePrograms = m_spec.programs[0].sources.separable;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300927
Pyry Haulosfb193242015-09-01 13:56:41 -0700928 bool allCompilesOk = true;
929 bool allLinksOk = true;
930 const char* failReason = DE_NULL;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300931
Pyry Haulosfb193242015-09-01 13:56:41 -0700932 vector<ProgramSources> specializedSources (m_spec.programs.size());
933
934 deUint32 vertexProgramID = -1;
935 vector<deUint32> pipelineProgramIDs;
936 vector<SharedPtr<ShaderProgram> > programs;
937 SharedPtr<ProgramPipeline> programPipeline;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300938
939 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
940
Pyry Haulosfb193242015-09-01 13:56:41 -0700941 // Specialize shaders
942 if (m_spec.caseType == CASETYPE_VERTEX_ONLY)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300943 {
Pyry Haulos677e4642015-09-30 10:00:12 -0700944 const vector<RequiredExtension> reqExt = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
945
Pyry Haulosfb193242015-09-01 13:56:41 -0700946 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX].size() == 1);
Pyry Haulos677e4642015-09-30 10:00:12 -0700947 specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX][0], reqExt))
Pyry Haulosfb193242015-09-01 13:56:41 -0700948 << glu::FragmentSource(genFragmentShader(m_spec));
949 }
950 else if (m_spec.caseType == CASETYPE_FRAGMENT_ONLY)
951 {
Pyry Haulos677e4642015-09-30 10:00:12 -0700952 const vector<RequiredExtension> reqExt = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
953
Pyry Haulosfb193242015-09-01 13:56:41 -0700954 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].size() == 1);
955 specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
Pyry Haulos677e4642015-09-30 10:00:12 -0700956 << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT][0], reqExt));
Pyry Haulosfb193242015-09-01 13:56:41 -0700957 }
958 else
959 {
960 DE_ASSERT(m_spec.caseType == CASETYPE_COMPLETE);
961
Pyry Haulosed67acb2015-10-13 13:06:24 -0700962 const int maxPatchVertices = isTessellationPresent(m_spec) && isTessellationSupported(m_renderCtx, m_contextInfo)
963 ? m_contextInfo.getInt(GL_MAX_PATCH_VERTICES) : 0;
Pyry Haulosfb193242015-09-01 13:56:41 -0700964
965 for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
966 {
967 const ProgramSpecializationParams progSpecParams (m_spec, checkAndSpecializeExtensions(m_spec.programs[progNdx].requiredExtensions, m_contextInfo), maxPatchVertices);
968
969 specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
970 }
971 }
972
973 if (!separablePrograms)
974 {
975 de::SharedPtr<glu::ShaderProgram> program (new glu::ShaderProgram(m_renderCtx, specializedSources[0]));
Jarkko Poyry3c827362014-09-02 11:48:52 +0300976
977 vertexProgramID = program->getProgram();
978 pipelineProgramIDs.push_back(program->getProgram());
979 programs.push_back(program);
980
981 // Check that compile/link results are what we expect.
982
983 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
984 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
985 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
986 allCompilesOk = false;
987
988 if (!program->getProgramInfo().linkOk)
989 allLinksOk = false;
990
991 log << *program;
992 }
993 else
994 {
995 // Separate programs
Pyry Haulosfb193242015-09-01 13:56:41 -0700996 for (size_t programNdx = 0; programNdx < m_spec.programs.size(); ++programNdx)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300997 {
Pyry Haulosfb193242015-09-01 13:56:41 -0700998 de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, specializedSources[programNdx]));
Jarkko Poyry3c827362014-09-02 11:48:52 +0300999
Pyry Haulosfb193242015-09-01 13:56:41 -07001000 if (m_spec.programs[programNdx].activeStages & (1u << glu::SHADERTYPE_VERTEX))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001001 vertexProgramID = program->getProgram();
1002
1003 pipelineProgramIDs.push_back(program->getProgram());
1004 programs.push_back(program);
1005
1006 // Check that compile/link results are what we expect.
1007
1008 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
1009 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1010 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
1011 allCompilesOk = false;
1012
1013 if (!program->getProgramInfo().linkOk)
1014 allLinksOk = false;
1015
1016 // Log program and active stages
1017 {
1018 const tcu::ScopedLogSection section (log, "Program", "Program " + de::toString(programNdx+1));
1019 tcu::MessageBuilder builder (&log);
1020 bool firstStage = true;
1021
1022 builder << "Pipeline uses stages: ";
1023 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
1024 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001025 if (m_spec.programs[programNdx].activeStages & (1u << stage))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001026 {
1027 if (!firstStage)
1028 builder << ", ";
1029 builder << glu::getShaderTypeName((glu::ShaderType)stage);
1030 firstStage = true;
1031 }
1032 }
1033 builder << tcu::TestLog::EndMessage;
1034
1035 log << *program;
1036 }
1037 }
1038 }
1039
Pyry Haulosfb193242015-09-01 13:56:41 -07001040 switch (m_spec.expectResult)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001041 {
1042 case EXPECT_PASS:
1043 case EXPECT_VALIDATION_FAIL:
Jarkko Pöyry9e574352014-12-16 11:33:56 -08001044 case EXPECT_BUILD_SUCCESSFUL:
Jarkko Poyry3c827362014-09-02 11:48:52 +03001045 if (!allCompilesOk)
1046 failReason = "expected shaders to compile and link properly, but failed to compile.";
1047 else if (!allLinksOk)
1048 failReason = "expected shaders to compile and link properly, but failed to link.";
1049 break;
1050
1051 case EXPECT_COMPILE_FAIL:
1052 if (allCompilesOk && !allLinksOk)
1053 failReason = "expected compilation to fail, but shaders compiled and link failed.";
1054 else if (allCompilesOk)
1055 failReason = "expected compilation to fail, but shaders compiled correctly.";
1056 break;
1057
1058 case EXPECT_LINK_FAIL:
1059 if (!allCompilesOk)
1060 failReason = "expected linking to fail, but unable to compile.";
1061 else if (allLinksOk)
1062 failReason = "expected linking to fail, but passed.";
1063 break;
1064
1065 case EXPECT_COMPILE_LINK_FAIL:
1066 if (allCompilesOk && allLinksOk)
1067 failReason = "expected compile or link to fail, but passed.";
1068 break;
1069
1070 default:
1071 DE_ASSERT(false);
1072 return false;
1073 }
1074
1075 if (failReason != DE_NULL)
1076 {
1077 // \todo [2010-06-07 petri] These should be handled in the test case?
1078 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
1079
Pyry Haulosfb193242015-09-01 13:56:41 -07001080 if (m_spec.fullGLSLES100Required)
Jarkko Pöyry789ca932015-03-12 14:23:10 -07001081 {
1082 log << TestLog::Message
1083 << "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
1084 << TestLog::EndMessage;
1085
1086 if (allCompilesOk && !allLinksOk)
1087 {
1088 // Used features are detectable at compile time. If implementation parses shader
1089 // at link time, report it as quality warning.
1090 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
1091 }
1092 else
1093 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
1094 }
Pyry Haulosfb193242015-09-01 13:56:41 -07001095 else if (m_spec.expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
Jarkko Pöyry789ca932015-03-12 14:23:10 -07001096 {
1097 // If implementation parses shader at link time, report it as quality warning.
Jarkko Poyry3c827362014-09-02 11:48:52 +03001098 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
Jarkko Pöyry789ca932015-03-12 14:23:10 -07001099 }
Jarkko Poyry3c827362014-09-02 11:48:52 +03001100 else
1101 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
1102 return false;
1103 }
1104
Jarkko Pöyry9e574352014-12-16 11:33:56 -08001105 // Return if shader is not intended to be run
Pyry Haulosfb193242015-09-01 13:56:41 -07001106 if (m_spec.expectResult == EXPECT_COMPILE_FAIL ||
1107 m_spec.expectResult == EXPECT_COMPILE_LINK_FAIL ||
1108 m_spec.expectResult == EXPECT_LINK_FAIL ||
1109 m_spec.expectResult == EXPECT_BUILD_SUCCESSFUL)
Jarkko Pöyry789ca932015-03-12 14:23:10 -07001110 return true;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001111
1112 // Setup viewport.
1113 gl.viewport(viewportX, viewportY, width, height);
1114
Pyry Haulosfb193242015-09-01 13:56:41 -07001115 if (separablePrograms)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001116 {
1117 programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
1118
1119 // Setup pipeline
1120 gl.bindProgramPipeline(programPipeline->getPipeline());
Pyry Haulosfb193242015-09-01 13:56:41 -07001121 for (int programNdx = 0; programNdx < (int)m_spec.programs.size(); ++programNdx)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001122 {
1123 deUint32 shaderFlags = 0;
1124 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
Pyry Haulosfb193242015-09-01 13:56:41 -07001125 if (m_spec.programs[programNdx].activeStages & (1u << stage))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001126 shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
1127
1128 programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
1129 }
1130
1131 programPipeline->activeShaderProgram(vertexProgramID);
1132 GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
1133 }
1134 else
1135 {
1136 // Start using program
1137 gl.useProgram(vertexProgramID);
1138 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
1139 }
1140
1141 // Fetch location for positions positions.
1142 int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
1143 if (positionLoc == -1)
1144 {
1145 string errStr = string("no location found for attribute 'dEQP_Position'");
1146 TCU_FAIL(errStr.c_str());
1147 }
1148
1149 // Iterate all value blocks.
Jarkko Poyry3c827362014-09-02 11:48:52 +03001150 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001151 const ValueBlock& valueBlock = m_spec.values;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001152
1153 // always render at least one pass even if there is no input/output data
Pyry Haulosfb193242015-09-01 13:56:41 -07001154 const int numRenderPasses = valueBlock.outputs.empty() ? 1 : (int)valueBlock.outputs[0].elements.size() / valueBlock.outputs[0].type.getScalarSize();
Jarkko Poyry3c827362014-09-02 11:48:52 +03001155
1156 // Iterate all array sub-cases.
1157 for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
1158 {
Jarkko Poyry3c827362014-09-02 11:48:52 +03001159 vector<VertexArrayBinding> vertexArrays;
1160 int attribValueNdx = 0;
Pyry Haulosfb193242015-09-01 13:56:41 -07001161 vector<vector<float> > attribValues (valueBlock.inputs.size());
Jarkko Poyry3c827362014-09-02 11:48:52 +03001162 glw::GLenum postDrawError;
1163 BeforeDrawValidator beforeDrawValidator (gl,
Pyry Haulosfb193242015-09-01 13:56:41 -07001164 (separablePrograms) ? (programPipeline->getPipeline()) : (vertexProgramID),
1165 (separablePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE) : (BeforeDrawValidator::TARGETTYPE_PROGRAM));
Jarkko Poyry3c827362014-09-02 11:48:52 +03001166
1167 vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
1168
1169 // Collect VA pointer for inputs
Pyry Haulosfb193242015-09-01 13:56:41 -07001170 for (size_t valNdx = 0; valNdx < valueBlock.inputs.size(); valNdx++)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001171 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001172 const Value& val = valueBlock.inputs[valNdx];
1173 const char* const valueName = val.name.c_str();
1174 const DataType dataType = val.type.getBasicType();
1175 const int scalarSize = getDataTypeScalarSize(dataType);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001176
Pyry Haulosfb193242015-09-01 13:56:41 -07001177 // Replicate values four times.
1178 std::vector<float>& scalars = attribValues[attribValueNdx++];
1179 scalars.resize(numVerticesPerDraw * scalarSize);
1180 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001181 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001182 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
1183 for (int ndx = 0; ndx < scalarSize; ndx++)
1184 scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
1185 }
1186 else
1187 {
1188 // convert to floats.
1189 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001190 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001191 for (int ndx = 0; ndx < scalarSize; ndx++)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001192 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001193 float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
1194 DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
1195 scalars[repNdx*scalarSize + ndx] = v;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001196 }
1197 }
Jarkko Poyry3c827362014-09-02 11:48:52 +03001198 }
Pyry Haulosfb193242015-09-01 13:56:41 -07001199
1200 // Attribute name prefix.
1201 string attribPrefix = "";
1202 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
1203 if ((m_spec.caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
1204 attribPrefix = "a_";
1205
1206 // Input always given as attribute.
1207 string attribName = attribPrefix + valueName;
1208 int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
1209 if (attribLoc == -1)
1210 {
1211 log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
1212 continue;
1213 }
1214
1215 if (isDataTypeMatrix(dataType))
1216 {
1217 int numCols = getDataTypeMatrixNumColumns(dataType);
1218 int numRows = getDataTypeMatrixNumRows(dataType);
1219 DE_ASSERT(scalarSize == numCols*numRows);
1220
1221 for (int i = 0; i < numCols; i++)
1222 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*(int)sizeof(float), &scalars[i * numRows]));
1223 }
1224 else
1225 {
1226 DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
1227 vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
1228 }
1229
1230 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
Jarkko Poyry3c827362014-09-02 11:48:52 +03001231 }
1232
1233 GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
1234
Pyry Haulosfb193242015-09-01 13:56:41 -07001235 // set reference values for outputs.
1236 for (size_t valNdx = 0; valNdx < valueBlock.outputs.size(); valNdx++)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001237 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001238 const Value& val = valueBlock.outputs[valNdx];
1239 const char* const valueName = val.name.c_str();
Jarkko Poyry3c827362014-09-02 11:48:52 +03001240
Pyry Haulosfb193242015-09-01 13:56:41 -07001241 // Set reference value.
1242 string refName = string("ref_") + valueName;
1243 setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
1244 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
1245 }
1246
1247 // set uniform values
1248 for (size_t valNdx = 0; valNdx < valueBlock.uniforms.size(); valNdx++)
1249 {
1250 const Value& val = valueBlock.uniforms[valNdx];
1251 const char* const valueName = val.name.c_str();
1252
1253 setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
1254 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
Jarkko Poyry3c827362014-09-02 11:48:52 +03001255 }
1256
1257 // Clear.
1258 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
1259 gl.clear(GL_COLOR_BUFFER_BIT);
1260 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1261
1262 // Use program or pipeline
Pyry Haulosfb193242015-09-01 13:56:41 -07001263 if (separablePrograms)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001264 gl.useProgram(0);
1265 else
1266 gl.useProgram(vertexProgramID);
1267
1268 // Draw.
1269 if (tessellationPresent)
1270 {
1271 gl.patchParameteri(GL_PATCH_VERTICES, 3);
1272 GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
1273 }
1274
1275 draw(m_renderCtx,
1276 vertexProgramID,
1277 (int)vertexArrays.size(),
1278 &vertexArrays[0],
1279 (tessellationPresent) ?
1280 (pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
1281 (pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
Pyry Haulosfb193242015-09-01 13:56:41 -07001282 (m_spec.expectResult == EXPECT_VALIDATION_FAIL) ?
Jarkko Poyry3c827362014-09-02 11:48:52 +03001283 (&beforeDrawValidator) :
1284 (DE_NULL));
1285
1286 postDrawError = gl.getError();
1287
Pyry Haulosfb193242015-09-01 13:56:41 -07001288 if (m_spec.expectResult == EXPECT_PASS)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001289 {
1290 // Read back results.
1291 Surface surface (width, height);
1292 const float w = s_positions[3];
Jarkko Pöyryc8e526b2015-05-19 19:31:53 -07001293 const int minY = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
1294 const int maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
1295 const int minX = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
1296 const int maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001297
1298 GLU_EXPECT_NO_ERROR(postDrawError, "draw");
1299
1300 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
1301 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
1302
Pyry Haulosfb193242015-09-01 13:56:41 -07001303 if (!checkPixels(log, tcu::getSubregion(surface.getAccess(), minX, minY, maxX-minX+1, maxY-minY+1)))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001304 {
Pyry Haulosfb193242015-09-01 13:56:41 -07001305 log << TestLog::Message << "INCORRECT RESULT for sub-case " << arrayNdx+1 << " of " << numRenderPasses << "):"
Jarkko Poyry3c827362014-09-02 11:48:52 +03001306 << TestLog::EndMessage;
1307
1308 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
Pyry Haulosfb193242015-09-01 13:56:41 -07001309 dumpValues(log, valueBlock, arrayNdx);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001310
1311 // Dump image on failure.
1312 log << TestLog::Image("Result", "Rendered result image", surface);
1313
1314 gl.useProgram(0);
1315 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1316 return false;
1317 }
1318 }
Pyry Haulosfb193242015-09-01 13:56:41 -07001319 else if (m_spec.expectResult == EXPECT_VALIDATION_FAIL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001320 {
1321 log << TestLog::Message
1322 << "Draw call generated error: "
1323 << glu::getErrorStr(postDrawError) << " "
1324 << ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
1325 << "Validate status: "
1326 << glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
1327 << ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
1328 << "Info log: "
1329 << ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
1330 << TestLog::EndMessage;
1331
1332 // test result
1333
1334 if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
1335 {
1336 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
1337 return false;
1338 }
1339
1340 if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
1341 {
1342 if (postDrawError == GL_NO_ERROR)
1343 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
1344 else if (postDrawError == GL_INVALID_OPERATION)
1345 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
1346 else
1347 DE_ASSERT(false);
1348 return false;
1349 }
1350 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
1351 {
1352 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
1353 return false;
1354 }
1355 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
1356 {
1357 // Validation does not depend on input values, no need to test all values
1358 return true;
1359 }
1360 else
1361 DE_ASSERT(false);
1362 }
1363 else
1364 DE_ASSERT(false);
1365 }
1366 }
1367
1368 gl.useProgram(0);
Pyry Haulosfb193242015-09-01 13:56:41 -07001369 if (separablePrograms)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001370 gl.bindProgramPipeline(0);
1371
1372 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
1373 return true;
1374}
1375
Pyry Haulosfb193242015-09-01 13:56:41 -07001376TestCase::IterateResult ShaderLibraryCase::iterate (void)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001377{
1378 // Initialize state to pass.
1379 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1380
1381 bool executeOk = execute();
1382
1383 DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
1384 DE_UNREF(executeOk);
1385 return TestCase::STOP;
1386}
1387
Jarkko Poyry3c827362014-09-02 11:48:52 +03001388} // gls
1389} // deqp