1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Compiler test case.
23 */ /*-------------------------------------------------------------------*/
25 #include "glcShaderLibraryCase.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuTestLog.hpp"
30 #include "gluDrawUtil.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluShaderProgram.hpp"
33 #include "tcuStringTemplate.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
40 #include "deRandom.hpp"
63 static inline bool usesShaderInoutQualifiers(glu::GLSLVersion version)
67 case glu::GLSL_VERSION_100_ES:
68 case glu::GLSL_VERSION_130:
69 case glu::GLSL_VERSION_140:
70 case glu::GLSL_VERSION_150:
80 ShaderCase::ShaderCase(tcu::TestContext& testCtx, RenderContext& renderCtx, const char* name, const char* description,
81 ExpectResult expectResult, const std::vector<ValueBlock>& valueBlocks, GLSLVersion targetVersion,
82 const char* vertexSource, const char* fragmentSource)
83 : tcu::TestCase(testCtx, name, description)
84 , m_renderCtx(renderCtx)
85 , m_expectResult(expectResult)
86 , m_valueBlocks(valueBlocks)
87 , m_targetVersion(targetVersion)
89 // If no value blocks given, use an empty one.
90 if (m_valueBlocks.size() == 0)
91 m_valueBlocks.push_back(ValueBlock());
93 // Use first value block to specialize shaders.
94 const ValueBlock& valueBlock = m_valueBlocks[0];
96 // \todo [2010-04-01 petri] Check that all value blocks have matching values.
98 // Generate specialized shader sources.
99 if (vertexSource && fragmentSource)
101 m_caseType = CASETYPE_COMPLETE;
102 specializeShaders(vertexSource, fragmentSource, m_vertexSource, m_fragmentSource, valueBlock);
104 else if (vertexSource)
106 m_caseType = CASETYPE_VERTEX_ONLY;
107 m_vertexSource = specializeVertexShader(vertexSource, valueBlock);
108 m_fragmentSource = genFragmentShader(valueBlock);
112 DE_ASSERT(fragmentSource);
113 m_caseType = CASETYPE_FRAGMENT_ONLY;
114 m_vertexSource = genVertexShader(valueBlock);
115 m_fragmentSource = specializeFragmentShader(fragmentSource, valueBlock);
119 ShaderCase::~ShaderCase(void)
123 static void setUniformValue(const glw::Functions& gl, deUint32 programID, const std::string& name,
124 const ShaderCase::Value& val, int arrayNdx)
126 int scalarSize = getDataTypeScalarSize(val.dataType);
127 int loc = gl.getUniformLocation(programID, name.c_str());
129 TCU_CHECK_MSG(loc != -1, "uniform location not found");
131 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat));
132 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint));
134 int elemNdx = (val.arrayLength == 1) ? 0 : (arrayNdx * scalarSize);
136 switch (val.dataType)
139 gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);
141 case TYPE_FLOAT_VEC2:
142 gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);
144 case TYPE_FLOAT_VEC3:
145 gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);
147 case TYPE_FLOAT_VEC4:
148 gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);
150 case TYPE_FLOAT_MAT2:
151 gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
153 case TYPE_FLOAT_MAT3:
154 gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
156 case TYPE_FLOAT_MAT4:
157 gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
160 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);
163 gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);
166 gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);
169 gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);
172 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);
175 gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);
178 gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);
181 gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);
184 gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
187 gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
190 gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
193 gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
195 case TYPE_FLOAT_MAT2X3:
196 gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
198 case TYPE_FLOAT_MAT2X4:
199 gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
201 case TYPE_FLOAT_MAT3X2:
202 gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
204 case TYPE_FLOAT_MAT3X4:
205 gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
207 case TYPE_FLOAT_MAT4X2:
208 gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
210 case TYPE_FLOAT_MAT4X3:
211 gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
214 case TYPE_SAMPLER_2D:
215 case TYPE_SAMPLER_CUBE:
216 DE_ASSERT(DE_FALSE && "implement!");
224 bool ShaderCase::checkPixels(Surface& surface, int minX, int maxX, int minY, int maxY)
226 TestLog& log = m_testCtx.getLog();
227 bool allWhite = true;
228 bool allBlack = true;
229 bool anyUnexpected = false;
231 DE_ASSERT((maxX > minX) && (maxY > minY));
233 for (int y = minY; y <= maxY; y++)
235 for (int x = minX; x <= maxX; x++)
237 RGBA pixel = surface.getPixel(x, y);
238 // Note: we really do not want to involve alpha in the check comparison
239 // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
240 bool isWhite = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255);
241 bool isBlack = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0);
243 allWhite = allWhite && isWhite;
244 allBlack = allBlack && isBlack;
245 anyUnexpected = anyUnexpected || (!isWhite && !isBlack);
252 log << TestLog::Message
253 << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!"
254 << TestLog::EndMessage;
256 log << TestLog::Message
257 << "WARNING: got inconsistent results over the image, when all pixels should be the same color!"
258 << TestLog::EndMessage;
265 bool ShaderCase::execute(void)
267 TestLog& log = m_testCtx.getLog();
268 const glw::Functions& gl = m_renderCtx.getFunctions();
271 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget();
272 de::Random rnd(deStringHash(getName()));
273 int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH);
274 int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT);
275 int viewportX = rnd.getInt(0, renderTarget.getWidth() - width);
276 int viewportY = rnd.getInt(0, renderTarget.getHeight() - height);
277 const int numVerticesPerDraw = 4;
279 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
282 gl.viewport(viewportX, viewportY, width, height);
284 const float quadSize = 1.0f;
285 static const float s_positions[4 * 4] = { -quadSize, -quadSize, 0.0f, 1.0f, -quadSize, +quadSize, 0.0f, 1.0f,
286 +quadSize, -quadSize, 0.0f, 1.0f, +quadSize, +quadSize, 0.0f, 1.0f };
288 static const deUint16 s_indices[2 * 3] = { 0, 1, 2, 1, 3, 2 };
291 glu::ShaderProgram program(m_renderCtx, glu::makeVtxFragSources(m_vertexSource.c_str(), m_fragmentSource.c_str()));
293 // Check that compile/link results are what we expect.
294 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
295 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
296 bool linkOk = program.getProgramInfo().linkOk;
297 const char* failReason = DE_NULL;
301 switch (m_expectResult)
304 if (!vertexOk || !fragmentOk)
305 failReason = "expected shaders to compile and link properly, but failed to compile.";
307 failReason = "expected shaders to compile and link properly, but failed to link.";
310 case EXPECT_COMPILE_FAIL:
311 if (vertexOk && fragmentOk && !linkOk)
312 failReason = "expected compilation to fail, but both shaders compiled and link failed.";
313 else if (vertexOk && fragmentOk)
314 failReason = "expected compilation to fail, but both shaders compiled correctly.";
317 case EXPECT_LINK_FAIL:
318 if (!vertexOk || !fragmentOk)
319 failReason = "expected linking to fail, but unable to compile.";
321 failReason = "expected linking to fail, but passed.";
329 if (failReason != DE_NULL)
331 // \todo [2010-06-07 petri] These should be handled in the test case?
332 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
334 // If implementation parses shader at link time, report it as quality warning.
335 if (m_expectResult == EXPECT_COMPILE_FAIL && vertexOk && fragmentOk && !linkOk)
336 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
338 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
342 // Return if compile/link expected to fail.
343 if (m_expectResult != EXPECT_PASS)
344 return (failReason == DE_NULL);
346 // Start using program.
347 deUint32 programID = program.getProgram();
348 gl.useProgram(programID);
349 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
351 // Fetch location for positions positions.
352 int positionLoc = gl.getAttribLocation(programID, "dEQP_Position");
353 if (positionLoc == -1)
355 string errStr = string("no location found for attribute 'dEQP_Position'");
356 TCU_FAIL(errStr.c_str());
359 // Iterate all value blocks.
360 for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++)
362 const ValueBlock& valueBlock = m_valueBlocks[blockNdx];
364 // Iterate all array sub-cases.
365 for (int arrayNdx = 0; arrayNdx < valueBlock.arrayLength; arrayNdx++)
367 int numValues = (int)valueBlock.values.size();
368 vector<VertexArrayBinding> vertexArrays;
370 int attribValueNdx = 0;
371 vector<vector<float> > attribValues(numValues);
373 vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
375 // Collect VA pointer for inputs and set uniform values for outputs (refs).
376 for (int valNdx = 0; valNdx < numValues; valNdx++)
378 const ShaderCase::Value& val = valueBlock.values[valNdx];
379 const char* valueName = val.valueName.c_str();
380 DataType dataType = val.dataType;
381 int scalarSize = getDataTypeScalarSize(val.dataType);
383 GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
385 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
387 // Replicate values four times.
388 std::vector<float>& scalars = attribValues[attribValueNdx++];
389 scalars.resize(numVerticesPerDraw * scalarSize);
390 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
392 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
393 for (int ndx = 0; ndx < scalarSize; ndx++)
394 scalars[repNdx * scalarSize + ndx] = val.elements[arrayNdx * scalarSize + ndx].float32;
398 // convert to floats.
399 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
401 for (int ndx = 0; ndx < scalarSize; ndx++)
403 float v = (float)val.elements[arrayNdx * scalarSize + ndx].int32;
404 DE_ASSERT(val.elements[arrayNdx * scalarSize + ndx].int32 == (int)v);
405 scalars[repNdx * scalarSize + ndx] = v;
410 // Attribute name prefix.
411 string attribPrefix = "";
412 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
413 if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
416 // Input always given as attribute.
417 string attribName = attribPrefix + valueName;
418 int attribLoc = gl.getAttribLocation(programID, attribName.c_str());
421 log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'"
422 << TestLog::EndMessage;
426 if (isDataTypeMatrix(dataType))
428 int numCols = getDataTypeMatrixNumColumns(dataType);
429 int numRows = getDataTypeMatrixNumRows(dataType);
430 DE_ASSERT(scalarSize == numCols * numRows);
432 for (int i = 0; i < numCols; i++)
433 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw,
434 static_cast<int>(scalarSize * sizeof(float)),
435 &scalars[i * numRows]));
439 DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) ||
440 isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
441 vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
444 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
446 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
448 // Set reference value.
449 string refName = string("ref_") + valueName;
450 setUniformValue(gl, programID, refName, val, arrayNdx);
451 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
455 DE_ASSERT(val.storageType == ShaderCase::Value::STORAGE_UNIFORM);
456 setUniformValue(gl, programID, valueName, val, arrayNdx);
457 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
462 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
463 gl.clear(GL_COLOR_BUFFER_BIT);
464 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
467 draw(m_renderCtx, program.getProgram(), (int)vertexArrays.size(), &vertexArrays[0],
468 pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
469 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
471 // Read back results.
472 Surface surface(width, height);
473 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
474 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
476 float w = s_positions[3];
477 int minY = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
478 int maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
479 int minX = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
480 int maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
482 if (!checkPixels(surface, minX, maxX, minY, maxY))
484 log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx + 1) << " of "
485 << (int)m_valueBlocks.size() << ", sub-case " << arrayNdx + 1 << " of " << valueBlock.arrayLength
486 << "):" << TestLog::EndMessage;
488 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
489 dumpValues(valueBlock, arrayNdx);
491 // Dump image on failure.
492 log << TestLog::Image("Result", "Rendered result image", surface);
495 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
502 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
506 TestCase::IterateResult ShaderCase::iterate(void)
508 // Initialize state to pass.
509 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
511 bool executeOk = execute();
513 DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS :
514 m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
516 return TestCase::STOP;
519 // This functions builds a matching vertex shader for a 'both' case, when
520 // the fragment shader is being tested.
521 // We need to build attributes and varyings for each 'input'.
522 string ShaderCase::genVertexShader(const ValueBlock& valueBlock)
525 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion);
526 const char* vtxIn = usesInout ? "in" : "attribute";
527 const char* vtxOut = usesInout ? "out" : "varying";
529 res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
531 // Declarations (position + attribute/varying for each input).
532 res << "precision highp float;\n";
533 res << "precision highp int;\n";
535 res << vtxIn << " highp vec4 dEQP_Position;\n";
536 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
538 const ShaderCase::Value& val = valueBlock.values[ndx];
539 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
541 DataType floatType = getDataTypeFloatScalars(val.dataType);
542 const char* typeStr = getDataTypeName(floatType);
543 res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n";
545 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
546 res << vtxOut << " " << typeStr << " " << val.valueName << ";\n";
548 res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n";
554 // - gl_Position = dEQP_Position;
555 // - for each input: write attribute directly to varying
556 res << "void main()\n";
558 res << " gl_Position = dEQP_Position;\n";
559 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
561 const ShaderCase::Value& val = valueBlock.values[ndx];
562 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
564 const string& name = val.valueName;
565 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
566 res << " " << name << " = a_" << name << ";\n";
568 res << " v_" << name << " = a_" << name << ";\n";
576 static void genCompareFunctions(ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes)
578 bool cmpTypeFound[TYPE_LAST];
579 for (int i = 0; i < TYPE_LAST; i++)
580 cmpTypeFound[i] = false;
582 for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
584 const ShaderCase::Value& val = valueBlock.values[valueNdx];
585 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
586 cmpTypeFound[(int)val.dataType] = true;
591 if (cmpTypeFound[TYPE_BOOL])
592 stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
593 if (cmpTypeFound[TYPE_BOOL_VEC2])
594 stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
595 if (cmpTypeFound[TYPE_BOOL_VEC3])
596 stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
597 if (cmpTypeFound[TYPE_BOOL_VEC4])
598 stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
599 if (cmpTypeFound[TYPE_INT])
600 stream << "bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= "
602 if (cmpTypeFound[TYPE_INT_VEC2])
603 stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
604 if (cmpTypeFound[TYPE_INT_VEC3])
605 stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
606 if (cmpTypeFound[TYPE_INT_VEC4])
607 stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
608 if (cmpTypeFound[TYPE_UINT])
609 stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= "
611 if (cmpTypeFound[TYPE_UINT_VEC2])
612 stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
613 if (cmpTypeFound[TYPE_UINT_VEC3])
614 stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
615 if (cmpTypeFound[TYPE_UINT_VEC4])
616 stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
620 if (cmpTypeFound[TYPE_BOOL])
621 stream << "bool isOk (bool a, bool b) { return (a == b); }\n";
622 if (cmpTypeFound[TYPE_BOOL_VEC2])
623 stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
624 if (cmpTypeFound[TYPE_BOOL_VEC3])
625 stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
626 if (cmpTypeFound[TYPE_BOOL_VEC4])
627 stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
628 if (cmpTypeFound[TYPE_INT])
629 stream << "bool isOk (int a, int b) { return (a == b); }\n";
630 if (cmpTypeFound[TYPE_INT_VEC2])
631 stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
632 if (cmpTypeFound[TYPE_INT_VEC3])
633 stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
634 if (cmpTypeFound[TYPE_INT_VEC4])
635 stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
636 if (cmpTypeFound[TYPE_UINT])
637 stream << "bool isOk (uint a, uint b) { return (a == b); }\n";
638 if (cmpTypeFound[TYPE_UINT_VEC2])
639 stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
640 if (cmpTypeFound[TYPE_UINT_VEC3])
641 stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
642 if (cmpTypeFound[TYPE_UINT_VEC4])
643 stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
646 if (cmpTypeFound[TYPE_FLOAT])
647 stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
648 if (cmpTypeFound[TYPE_FLOAT_VEC2])
650 << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
651 if (cmpTypeFound[TYPE_FLOAT_VEC3])
653 << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
654 if (cmpTypeFound[TYPE_FLOAT_VEC4])
656 << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
658 if (cmpTypeFound[TYPE_FLOAT_MAT2])
659 stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
660 "all(lessThanEqual(diff, vec2(eps))); }\n";
661 if (cmpTypeFound[TYPE_FLOAT_MAT2X3])
662 stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
663 "all(lessThanEqual(diff, vec3(eps))); }\n";
664 if (cmpTypeFound[TYPE_FLOAT_MAT2X4])
665 stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
666 "all(lessThanEqual(diff, vec4(eps))); }\n";
667 if (cmpTypeFound[TYPE_FLOAT_MAT3X2])
668 stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
669 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
670 if (cmpTypeFound[TYPE_FLOAT_MAT3])
671 stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
672 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
673 if (cmpTypeFound[TYPE_FLOAT_MAT3X4])
674 stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
675 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
676 if (cmpTypeFound[TYPE_FLOAT_MAT4X2])
677 stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
678 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
679 if (cmpTypeFound[TYPE_FLOAT_MAT4X3])
680 stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
681 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
682 if (cmpTypeFound[TYPE_FLOAT_MAT4])
683 stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
684 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";
687 static void genCompareOp(ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock,
688 const char* nonFloatNamePrefix, const char* checkVarName)
690 bool isFirstOutput = true;
692 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
694 const ShaderCase::Value& val = valueBlock.values[ndx];
695 const char* valueName = val.valueName.c_str();
697 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
699 // Check if we're only interested in one variable (then skip if not the right one).
700 if (checkVarName && !deStringEqual(valueName, checkVarName))
706 output << "bool RES = ";
707 isFirstOutput = false;
710 output << "RES = RES && ";
712 // Generate actual comparison.
713 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
714 output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n";
716 output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n";
718 // \note Uniforms are already declared in shader.
722 output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case?
724 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
727 string ShaderCase::genFragmentShader(const ValueBlock& valueBlock)
729 ostringstream shader;
730 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion);
731 const bool customColorOut = usesInout;
732 const char* fragIn = usesInout ? "in" : "varying";
734 shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
736 shader << "precision mediump float;\n";
737 shader << "precision mediump int;\n";
742 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
746 genCompareFunctions(shader, valueBlock, true);
749 // Declarations (varying, reference for each output).
750 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
752 const ShaderCase::Value& val = valueBlock.values[ndx];
753 DataType floatType = getDataTypeFloatScalars(val.dataType);
754 const char* floatTypeStr = getDataTypeName(floatType);
755 const char* refTypeStr = getDataTypeName(val.dataType);
757 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
759 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
760 shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n";
762 shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n";
764 shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n";
769 shader << "void main()\n";
773 genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL);
779 // Specialize a shader for the vertex shader test case.
780 string ShaderCase::specializeVertexShader(const char* src, const ValueBlock& valueBlock)
784 ostringstream output;
785 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion);
786 const char* vtxIn = usesInout ? "in" : "attribute";
787 const char* vtxOut = usesInout ? "out" : "varying";
789 // Output (write out position).
790 output << "gl_Position = dEQP_Position;\n";
792 // Declarations (position + attribute for each input, varying for each output).
793 decl << vtxIn << " highp vec4 dEQP_Position;\n";
794 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
796 const ShaderCase::Value& val = valueBlock.values[ndx];
797 const char* valueName = val.valueName.c_str();
798 DataType floatType = getDataTypeFloatScalars(val.dataType);
799 const char* floatTypeStr = getDataTypeName(floatType);
800 const char* refTypeStr = getDataTypeName(val.dataType);
802 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
804 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
806 decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n";
810 decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n";
811 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n";
814 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
816 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
817 decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n";
820 decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n";
821 decl << refTypeStr << " " << valueName << ";\n";
823 output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n";
828 // Shader specialization.
829 map<string, string> params;
830 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
831 params.insert(pair<string, string>("SETUP", setup.str()));
832 params.insert(pair<string, string>("OUTPUT", output.str()));
833 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
835 StringTemplate tmpl(src);
836 return tmpl.specialize(params);
839 // Specialize a shader for the fragment shader test case.
840 string ShaderCase::specializeFragmentShader(const char* src, const ValueBlock& valueBlock)
844 ostringstream output;
846 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion);
847 const bool customColorOut = usesInout;
848 const char* fragIn = usesInout ? "in" : "varying";
849 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
851 genCompareFunctions(decl, valueBlock, false);
852 genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
855 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
857 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
859 const ShaderCase::Value& val = valueBlock.values[ndx];
860 const char* valueName = val.valueName.c_str();
861 DataType floatType = getDataTypeFloatScalars(val.dataType);
862 const char* floatTypeStr = getDataTypeName(floatType);
863 const char* refTypeStr = getDataTypeName(val.dataType);
865 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
867 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
868 decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n";
871 decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n";
873 isDataTypeIntOrIVec(val.dataType) ?
875 ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
876 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset
880 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
882 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
883 decl << refTypeStr << " " << valueName << ";\n";
887 /* \todo [2010-04-01 petri] Check all outputs. */
889 // Shader specialization.
890 map<string, string> params;
891 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
892 params.insert(pair<string, string>("SETUP", setup.str()));
893 params.insert(pair<string, string>("OUTPUT", output.str()));
894 params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
896 StringTemplate tmpl(src);
897 return tmpl.specialize(params);
900 void ShaderCase::specializeShaders(const char* vertexSource, const char* fragmentSource, string& outVertexSource,
901 string& outFragmentSource, const ValueBlock& valueBlock)
903 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion);
904 const bool customColorOut = usesInout;
906 // Vertex shader specialization.
910 const char* vtxIn = usesInout ? "in" : "attribute";
912 decl << vtxIn << " highp vec4 dEQP_Position;\n";
914 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
916 const ShaderCase::Value& val = valueBlock.values[ndx];
917 const char* typeStr = getDataTypeName(val.dataType);
919 if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
921 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
923 decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n";
927 DataType floatType = getDataTypeFloatScalars(val.dataType);
928 const char* floatTypeStr = getDataTypeName(floatType);
930 decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n";
931 setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n";
934 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos)
936 decl << "uniform " << typeStr << " " << val.valueName << ";\n";
940 map<string, string> params;
941 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str()));
942 params.insert(pair<string, string>("VERTEX_SETUP", setup.str()));
943 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n")));
944 StringTemplate tmpl(vertexSource);
945 outVertexSource = tmpl.specialize(params);
948 // Fragment shader specialization.
951 ostringstream output;
952 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
954 genCompareFunctions(decl, valueBlock, false);
955 genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
958 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
960 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
962 const ShaderCase::Value& val = valueBlock.values[ndx];
963 const char* valueName = val.valueName.c_str();
964 const char* refTypeStr = getDataTypeName(val.dataType);
966 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
968 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
969 decl << refTypeStr << " " << valueName << ";\n";
971 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos)
973 decl << "uniform " << refTypeStr << " " << valueName << ";\n";
977 map<string, string> params;
978 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str()));
979 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str()));
980 params.insert(pair<string, string>("FRAG_COLOR", fragColor));
981 StringTemplate tmpl(fragmentSource);
982 outFragmentSource = tmpl.specialize(params);
986 void ShaderCase::dumpValues(const ValueBlock& valueBlock, int arrayNdx)
988 vector<vector<float> > attribValues;
990 int numValues = (int)valueBlock.values.size();
991 for (int valNdx = 0; valNdx < numValues; valNdx++)
993 const ShaderCase::Value& val = valueBlock.values[valNdx];
994 const char* valueName = val.valueName.c_str();
995 DataType dataType = val.dataType;
996 int scalarSize = getDataTypeScalarSize(val.dataType);
997 ostringstream result;
1000 if (val.storageType == Value::STORAGE_INPUT)
1002 else if (val.storageType == Value::STORAGE_UNIFORM)
1003 result << "uniform ";
1004 else if (val.storageType == Value::STORAGE_OUTPUT)
1005 result << "expected ";
1007 result << getDataTypeName(dataType) << " " << valueName << ":";
1009 if (isDataTypeScalar(dataType))
1011 if (isDataTypeVector(dataType))
1013 else if (isDataTypeMatrix(dataType))
1016 if (isDataTypeScalarOrVector(dataType))
1018 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1020 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
1021 const Value::Element& e = val.elements[elemNdx * scalarSize + scalarNdx];
1022 result << ((scalarNdx != 0) ? ", " : "");
1024 if (isDataTypeFloatOrVec(dataType))
1025 result << e.float32;
1026 else if (isDataTypeIntOrIVec(dataType))
1028 else if (isDataTypeBoolOrBVec(dataType))
1029 result << (e.bool32 ? "true" : "false");
1032 else if (isDataTypeMatrix(dataType))
1034 int numRows = getDataTypeMatrixNumRows(dataType);
1035 int numCols = getDataTypeMatrixNumColumns(dataType);
1036 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1039 for (int colNdx = 0; colNdx < numCols; colNdx++)
1041 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
1042 float v = val.elements[elemNdx * scalarSize + rowNdx * numCols + colNdx].float32;
1043 result << ((colNdx == 0) ? "" : ", ") << v;
1049 if (isDataTypeScalar(dataType))
1051 else if (isDataTypeVector(dataType))
1054 m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage;