vktTessellationUserDefinedIO.cpp revision abbf1c4efd3388dcfe59d125e5f33140c444a53a
1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2014 The Android Open Source Project 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 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 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 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. 19 * 20 *//*! 21 * \file 22 * \brief Tessellation User Defined IO Tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktTessellationUserDefinedIO.hpp" 26#include "vktTestCaseUtil.hpp" 27#include "vktTessellationUtil.hpp" 28 29#include "tcuTestLog.hpp" 30#include "tcuImageCompare.hpp" 31#include "tcuImageIO.hpp" 32 33#include "gluVarType.hpp" 34#include "gluVarTypeUtil.hpp" 35 36#include "vkDefs.hpp" 37#include "vkQueryUtil.hpp" 38#include "vkImageUtil.hpp" 39#include "vkBuilderUtil.hpp" 40#include "vkTypeUtil.hpp" 41 42#include "deUniquePtr.hpp" 43#include "deSharedPtr.hpp" 44 45namespace vkt 46{ 47namespace tessellation 48{ 49 50using namespace vk; 51 52namespace 53{ 54 55enum Constants 56{ 57 NUM_PER_PATCH_BLOCKS = 2, 58 NUM_PER_PATCH_ARRAY_ELEMS = 3, 59 NUM_OUTPUT_VERTICES = 5, 60 NUM_TESS_LEVELS = 6, 61 MAX_TESSELLATION_PATCH_SIZE = 32, 62 RENDER_SIZE = 256, 63}; 64 65enum IOType 66{ 67 IO_TYPE_PER_PATCH = 0, 68 IO_TYPE_PER_PATCH_ARRAY, 69 IO_TYPE_PER_PATCH_BLOCK, 70 IO_TYPE_PER_PATCH_BLOCK_ARRAY, 71 IO_TYPE_PER_VERTEX, 72 IO_TYPE_PER_VERTEX_BLOCK, 73 74 IO_TYPE_LAST 75}; 76 77enum VertexIOArraySize 78{ 79 VERTEX_IO_ARRAY_SIZE_IMPLICIT = 0, 80 VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN, //!< Use gl_MaxPatchVertices as size for per-vertex input array. 81 VERTEX_IO_ARRAY_SIZE_EXPLICIT_SPEC_MIN, //!< Minimum maxTessellationPatchSize required by the spec. 82 83 VERTEX_IO_ARRAY_SIZE_LAST 84}; 85 86struct CaseDefinition 87{ 88 TessPrimitiveType primitiveType; 89 IOType ioType; 90 VertexIOArraySize vertexIOArraySize; 91 std::string referenceImagePath; 92}; 93 94typedef std::string (*BasicTypeVisitFunc)(const std::string& name, glu::DataType type, int indentationDepth); //!< See glslTraverseBasicTypes below. 95 96class TopLevelObject 97{ 98public: 99 virtual ~TopLevelObject (void) {} 100 101 virtual std::string name (void) const = 0; 102 virtual std::string declare (void) const = 0; 103 virtual std::string declareArray (const std::string& arraySizeExpr) const = 0; 104 virtual std::string glslTraverseBasicTypeArray (const int numArrayElements, //!< If negative, traverse just array[gl_InvocationID], not all indices. 105 const int indentationDepth, 106 BasicTypeVisitFunc) const = 0; 107 virtual std::string glslTraverseBasicType (const int indentationDepth, 108 BasicTypeVisitFunc) const = 0; 109 virtual int numBasicSubobjectsInElementType (void) const = 0; 110 virtual std::string basicSubobjectAtIndex (const int index, const int arraySize) const = 0; 111}; 112 113std::string glslTraverseBasicTypes (const std::string& rootName, 114 const glu::VarType& rootType, 115 const int arrayNestingDepth, 116 const int indentationDepth, 117 const BasicTypeVisitFunc visit) 118{ 119 if (rootType.isBasicType()) 120 return visit(rootName, rootType.getBasicType(), indentationDepth); 121 else if (rootType.isArrayType()) 122 { 123 const std::string indentation = std::string(indentationDepth, '\t'); 124 const std::string loopIndexName = "i" + de::toString(arrayNestingDepth); 125 const std::string arrayLength = de::toString(rootType.getArraySize()); 126 return indentation + "for (int " + loopIndexName + " = 0; " + loopIndexName + " < " + de::toString(rootType.getArraySize()) + "; ++" + loopIndexName + ")\n" + 127 indentation + "{\n" + 128 glslTraverseBasicTypes(rootName + "[" + loopIndexName + "]", rootType.getElementType(), arrayNestingDepth+1, indentationDepth+1, visit) + 129 indentation + "}\n"; 130 } 131 else if (rootType.isStructType()) 132 { 133 const glu::StructType& structType = *rootType.getStructPtr(); 134 const int numMembers = structType.getNumMembers(); 135 std::string result; 136 137 for (int membNdx = 0; membNdx < numMembers; ++membNdx) 138 { 139 const glu::StructMember& member = structType.getMember(membNdx); 140 result += glslTraverseBasicTypes(rootName + "." + member.getName(), member.getType(), arrayNestingDepth, indentationDepth, visit); 141 } 142 143 return result; 144 } 145 else 146 { 147 DE_ASSERT(false); 148 return DE_NULL; 149 } 150} 151 152//! Used as the 'visit' argument for glslTraverseBasicTypes. 153std::string glslAssignBasicTypeObject (const std::string& name, const glu::DataType type, const int indentationDepth) 154{ 155 const int scalarSize = glu::getDataTypeScalarSize(type); 156 const std::string indentation = std::string(indentationDepth, '\t'); 157 std::ostringstream result; 158 159 result << indentation << name << " = "; 160 161 if (type != glu::TYPE_FLOAT) 162 result << std::string() << glu::getDataTypeName(type) << "("; 163 for (int i = 0; i < scalarSize; ++i) 164 result << (i > 0 ? ", v+" + de::floatToString(0.8f*i, 1) : "v"); 165 if (type != glu::TYPE_FLOAT) 166 result << ")"; 167 result << ";\n" 168 << indentation << "v += 0.4;\n"; 169 return result.str(); 170} 171 172//! Used as the 'visit' argument for glslTraverseBasicTypes. 173std::string glslCheckBasicTypeObject (const std::string& name, const glu::DataType type, const int indentationDepth) 174{ 175 const int scalarSize = glu::getDataTypeScalarSize(type); 176 const std::string indentation = std::string(indentationDepth, '\t'); 177 std::ostringstream result; 178 179 result << indentation << "allOk = allOk && compare_" << glu::getDataTypeName(type) << "(" << name << ", "; 180 181 if (type != glu::TYPE_FLOAT) 182 result << std::string() << glu::getDataTypeName(type) << "("; 183 for (int i = 0; i < scalarSize; ++i) 184 result << (i > 0 ? ", v+" + de::floatToString(0.8f*i, 1) : "v"); 185 if (type != glu::TYPE_FLOAT) 186 result << ")"; 187 result << ");\n" 188 << indentation << "v += 0.4;\n" 189 << indentation << "if (allOk) ++firstFailedInputIndex;\n"; 190 191 return result.str(); 192} 193 194int numBasicSubobjectsInElementType (const std::vector<de::SharedPtr<TopLevelObject> >& objects) 195{ 196 int result = 0; 197 for (int i = 0; i < static_cast<int>(objects.size()); ++i) 198 result += objects[i]->numBasicSubobjectsInElementType(); 199 return result; 200} 201 202std::string basicSubobjectAtIndex (const int subobjectIndex, const std::vector<de::SharedPtr<TopLevelObject> >& objects, const int topLevelArraySize) 203{ 204 int currentIndex = 0; 205 int objectIndex = 0; 206 207 for (; currentIndex < subobjectIndex; ++objectIndex) 208 currentIndex += objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize; 209 210 if (currentIndex > subobjectIndex) 211 { 212 --objectIndex; 213 currentIndex -= objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize; 214 } 215 216 return objects[objectIndex]->basicSubobjectAtIndex(subobjectIndex - currentIndex, topLevelArraySize); 217} 218 219int numBasicSubobjects (const glu::VarType& type) 220{ 221 if (type.isBasicType()) 222 return 1; 223 else if (type.isArrayType()) 224 return type.getArraySize()*numBasicSubobjects(type.getElementType()); 225 else if (type.isStructType()) 226 { 227 const glu::StructType& structType = *type.getStructPtr(); 228 int result = 0; 229 for (int i = 0; i < structType.getNumMembers(); ++i) 230 result += numBasicSubobjects(structType.getMember(i).getType()); 231 return result; 232 } 233 else 234 { 235 DE_ASSERT(false); 236 return -1; 237 } 238} 239 240class Variable : public TopLevelObject 241{ 242public: 243 Variable (const std::string& name_, const glu::VarType& type, const bool isArray) 244 : m_name (name_) 245 , m_type (type) 246 , m_isArray (isArray) 247 { 248 DE_ASSERT(!type.isArrayType()); 249 } 250 251 std::string name (void) const { return m_name; } 252 std::string declare (void) const; 253 std::string declareArray (const std::string& arraySizeExpr) const; 254 std::string glslTraverseBasicTypeArray (const int numArrayElements, const int indentationDepth, BasicTypeVisitFunc) const; 255 std::string glslTraverseBasicType (const int indentationDepth, BasicTypeVisitFunc) const; 256 int numBasicSubobjectsInElementType (void) const; 257 std::string basicSubobjectAtIndex (const int index, const int arraySize) const; 258 259private: 260 std::string m_name; 261 glu::VarType m_type; //!< If this Variable is an array element, m_type is the element type; otherwise just the variable type. 262 const bool m_isArray; 263}; 264 265std::string Variable::declare (void) const 266{ 267 DE_ASSERT(!m_isArray); 268 return de::toString(glu::declare(m_type, m_name)) + ";\n"; 269} 270 271std::string Variable::declareArray (const std::string& sizeExpr) const 272{ 273 DE_ASSERT(m_isArray); 274 return de::toString(glu::declare(m_type, m_name)) + "[" + sizeExpr + "];\n"; 275} 276 277std::string Variable::glslTraverseBasicTypeArray (const int numArrayElements, const int indentationDepth, BasicTypeVisitFunc visit) const 278{ 279 DE_ASSERT(m_isArray); 280 281 const bool traverseAsArray = numArrayElements >= 0; 282 const std::string traversedName = m_name + (!traverseAsArray ? "[gl_InvocationID]" : ""); 283 const glu::VarType type = traverseAsArray ? glu::VarType(m_type, numArrayElements) : m_type; 284 285 return glslTraverseBasicTypes(traversedName, type, 0, indentationDepth, visit); 286} 287 288std::string Variable::glslTraverseBasicType (const int indentationDepth, BasicTypeVisitFunc visit) const 289{ 290 DE_ASSERT(!m_isArray); 291 return glslTraverseBasicTypes(m_name, m_type, 0, indentationDepth, visit); 292} 293 294int Variable::numBasicSubobjectsInElementType (void) const 295{ 296 return numBasicSubobjects(m_type); 297} 298 299std::string Variable::basicSubobjectAtIndex (const int subobjectIndex, const int arraySize) const 300{ 301 const glu::VarType type = m_isArray ? glu::VarType(m_type, arraySize) : m_type; 302 int currentIndex = 0; 303 304 for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&type); basicIt != glu::BasicTypeIterator::end(&type); ++basicIt) 305 { 306 if (currentIndex == subobjectIndex) 307 return m_name + de::toString(glu::TypeAccessFormat(type, basicIt.getPath())); 308 ++currentIndex; 309 } 310 DE_ASSERT(false); 311 return DE_NULL; 312} 313 314class IOBlock : public TopLevelObject 315{ 316public: 317 struct Member 318 { 319 std::string name; 320 glu::VarType type; 321 322 Member (const std::string& n, const glu::VarType& t) : name(n), type(t) {} 323 }; 324 325 IOBlock (const std::string& blockName, const std::string& interfaceName, const std::vector<Member>& members) 326 : m_blockName (blockName) 327 , m_interfaceName (interfaceName) 328 , m_members (members) 329 { 330 } 331 332 std::string name (void) const { return m_interfaceName; } 333 std::string declare (void) const; 334 std::string declareArray (const std::string& arraySizeExpr) const; 335 std::string glslTraverseBasicTypeArray (const int numArrayElements, const int indentationDepth, BasicTypeVisitFunc) const; 336 std::string glslTraverseBasicType (const int indentationDepth, BasicTypeVisitFunc) const; 337 int numBasicSubobjectsInElementType (void) const; 338 std::string basicSubobjectAtIndex (const int index, const int arraySize) const; 339 340private: 341 std::string m_blockName; 342 std::string m_interfaceName; 343 std::vector<Member> m_members; 344}; 345 346std::string IOBlock::declare (void) const 347{ 348 std::ostringstream buf; 349 350 buf << m_blockName << "\n" 351 << "{\n"; 352 353 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 354 buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n"; 355 356 buf << "} " << m_interfaceName << ";\n"; 357 return buf.str(); 358} 359 360std::string IOBlock::declareArray (const std::string& sizeExpr) const 361{ 362 std::ostringstream buf; 363 364 buf << m_blockName << "\n" 365 << "{\n"; 366 367 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 368 buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n"; 369 370 buf << "} " << m_interfaceName << "[" << sizeExpr << "];\n"; 371 return buf.str(); 372} 373 374std::string IOBlock::glslTraverseBasicTypeArray (const int numArrayElements, const int indentationDepth, BasicTypeVisitFunc visit) const 375{ 376 if (numArrayElements >= 0) 377 { 378 const std::string indentation = std::string(indentationDepth, '\t'); 379 std::ostringstream result; 380 381 result << indentation << "for (int i0 = 0; i0 < " << numArrayElements << "; ++i0)\n" 382 << indentation << "{\n"; 383 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 384 result << glslTraverseBasicTypes(m_interfaceName + "[i0]." + m_members[i].name, m_members[i].type, 1, indentationDepth + 1, visit); 385 result << indentation + "}\n"; 386 return result.str(); 387 } 388 else 389 { 390 std::ostringstream result; 391 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 392 result << glslTraverseBasicTypes(m_interfaceName + "[gl_InvocationID]." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit); 393 return result.str(); 394 } 395} 396 397std::string IOBlock::glslTraverseBasicType (const int indentationDepth, BasicTypeVisitFunc visit) const 398{ 399 std::ostringstream result; 400 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 401 result << glslTraverseBasicTypes(m_interfaceName + "." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit); 402 return result.str(); 403} 404 405int IOBlock::numBasicSubobjectsInElementType (void) const 406{ 407 int result = 0; 408 for (int i = 0; i < static_cast<int>(m_members.size()); ++i) 409 result += numBasicSubobjects(m_members[i].type); 410 return result; 411} 412 413std::string IOBlock::basicSubobjectAtIndex (const int subobjectIndex, const int arraySize) const 414{ 415 int currentIndex = 0; 416 for (int arrayNdx = 0; arrayNdx < arraySize; ++arrayNdx) 417 for (int memberNdx = 0; memberNdx < static_cast<int>(m_members.size()); ++memberNdx) 418 { 419 const glu::VarType& membType = m_members[memberNdx].type; 420 for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&membType); basicIt != glu::BasicTypeIterator::end(&membType); ++basicIt) 421 { 422 if (currentIndex == subobjectIndex) 423 return m_interfaceName + "[" + de::toString(arrayNdx) + "]." + m_members[memberNdx].name + de::toString(glu::TypeAccessFormat(membType, basicIt.getPath())); 424 currentIndex++; 425 } 426 } 427 DE_ASSERT(false); 428 return DE_NULL; 429} 430 431class UserDefinedIOTest : public TestCase 432{ 433public: 434 UserDefinedIOTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const CaseDefinition caseDef); 435 void initPrograms (vk::SourceCollections& programCollection) const; 436 TestInstance* createInstance (Context& context) const; 437 438private: 439 const CaseDefinition m_caseDef; 440 std::vector<glu::StructType> m_structTypes; 441 std::vector<de::SharedPtr<TopLevelObject> > m_tcsOutputs; 442 std::vector<de::SharedPtr<TopLevelObject> > m_tesInputs; 443 std::string m_tcsDeclarations; 444 std::string m_tcsStatements; 445 std::string m_tesDeclarations; 446 std::string m_tesStatements; 447}; 448 449UserDefinedIOTest::UserDefinedIOTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const CaseDefinition caseDef) 450 : TestCase (testCtx, name, description) 451 , m_caseDef (caseDef) 452{ 453 const bool isPerPatchIO = m_caseDef.ioType == IO_TYPE_PER_PATCH || 454 m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY || 455 m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK || 456 m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY; 457 458 const bool isExplicitVertexArraySize = m_caseDef.vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN || 459 m_caseDef.vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SPEC_MIN; 460 461 const std::string vertexAttrArrayInputSize = m_caseDef.vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_IMPLICIT ? "" 462 : m_caseDef.vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN ? "gl_MaxPatchVertices" 463 : m_caseDef.vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SPEC_MIN ? de::toString(MAX_TESSELLATION_PATCH_SIZE) 464 : DE_NULL; 465 466 const char* const maybePatch = isPerPatchIO ? "patch " : ""; 467 const std::string outMaybePatch = std::string() + maybePatch + "out "; 468 const std::string inMaybePatch = std::string() + maybePatch + "in "; 469 const bool useBlock = m_caseDef.ioType == IO_TYPE_PER_VERTEX_BLOCK || 470 m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK || 471 m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY; 472 const int wrongNumElements = -2; 473 474 std::ostringstream tcsDeclarations; 475 std::ostringstream tcsStatements; 476 std::ostringstream tesDeclarations; 477 std::ostringstream tesStatements; 478 479 // Indices 0 and 1 are taken, see initPrograms() 480 int tcsNextOutputLocation = 2; 481 int tesNextInputLocation = 2; 482 483 m_structTypes.push_back(glu::StructType("S")); 484 485 const glu::VarType highpFloat (glu::TYPE_FLOAT, glu::PRECISION_HIGHP); 486 glu::StructType& structType = m_structTypes.back(); 487 const glu::VarType structVarType (&structType); 488 bool usedStruct = false; 489 490 structType.addMember("x", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)); 491 structType.addMember("y", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); 492 493 // It is illegal to have a structure containing an array as an output variable 494 if (useBlock) 495 structType.addMember("z", glu::VarType(highpFloat, 2)); 496 497 if (useBlock) 498 { 499 std::vector<IOBlock::Member> blockMembers; 500 501 // use leaner block to make sure it is not larger than allowed (per-patch storage is very limited) 502 const bool useLightweightBlock = (m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY); 503 504 if (!useLightweightBlock) 505 blockMembers.push_back(IOBlock::Member("blockS", structVarType)); 506 507 blockMembers.push_back(IOBlock::Member("blockFa", glu::VarType(highpFloat, 3))); 508 blockMembers.push_back(IOBlock::Member("blockSa", glu::VarType(structVarType, 2))); 509 blockMembers.push_back(IOBlock::Member("blockF", highpFloat)); 510 511 m_tcsOutputs.push_back (de::SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "tcBlock", blockMembers))); 512 m_tesInputs.push_back (de::SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "teBlock", blockMembers))); 513 514 usedStruct = true; 515 } 516 else 517 { 518 const Variable var0("in_te_s", structVarType, m_caseDef.ioType != IO_TYPE_PER_PATCH); 519 const Variable var1("in_te_f", highpFloat, m_caseDef.ioType != IO_TYPE_PER_PATCH); 520 521 if (m_caseDef.ioType != IO_TYPE_PER_PATCH_ARRAY) 522 { 523 // Arrays of structures are disallowed, add struct cases only if not arrayed variable 524 m_tcsOutputs.push_back (de::SharedPtr<TopLevelObject>(new Variable(var0))); 525 m_tesInputs.push_back (de::SharedPtr<TopLevelObject>(new Variable(var0))); 526 527 usedStruct = true; 528 } 529 530 m_tcsOutputs.push_back (de::SharedPtr<TopLevelObject>(new Variable(var1))); 531 m_tesInputs.push_back (de::SharedPtr<TopLevelObject>(new Variable(var1))); 532 } 533 534 if (usedStruct) 535 tcsDeclarations << de::toString(glu::declare(structType)) + ";\n"; 536 537 tcsStatements << "\t{\n" 538 << "\t\thighp float v = 1.3;\n"; 539 540 for (int tcsOutputNdx = 0; tcsOutputNdx < static_cast<int>(m_tcsOutputs.size()); ++tcsOutputNdx) 541 { 542 const TopLevelObject& output = *m_tcsOutputs[tcsOutputNdx]; 543 const int numElements = !isPerPatchIO ? -1 //!< \note -1 means indexing with gl_InstanceID 544 : m_caseDef.ioType == IO_TYPE_PER_PATCH ? 1 545 : m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY ? NUM_PER_PATCH_ARRAY_ELEMS 546 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK ? 1 547 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY ? NUM_PER_PATCH_BLOCKS 548 : wrongNumElements; 549 const bool isArray = (numElements != 1); 550 551 DE_ASSERT(numElements != wrongNumElements); 552 553 // \note: TCS output arrays are always implicitly-sized 554 tcsDeclarations << "layout(location = " << tcsNextOutputLocation << ") "; 555 if (isArray) 556 tcsDeclarations << outMaybePatch << output.declareArray(m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY ? de::toString(NUM_PER_PATCH_ARRAY_ELEMS) 557 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY ? de::toString(NUM_PER_PATCH_BLOCKS) 558 : ""); 559 else 560 tcsDeclarations << outMaybePatch << output.declare(); 561 562 tcsNextOutputLocation += output.numBasicSubobjectsInElementType(); 563 564 if (!isPerPatchIO) 565 tcsStatements << "\t\tv += float(gl_InvocationID)*" << de::floatToString(0.4f * output.numBasicSubobjectsInElementType(), 1) << ";\n"; 566 567 tcsStatements << "\n\t\t// Assign values to output " << output.name() << "\n"; 568 if (isArray) 569 tcsStatements << output.glslTraverseBasicTypeArray(numElements, 2, glslAssignBasicTypeObject); 570 else 571 tcsStatements << output.glslTraverseBasicType(2, glslAssignBasicTypeObject); 572 573 if (!isPerPatchIO) 574 tcsStatements << "\t\tv += float(" << de::toString(NUM_OUTPUT_VERTICES) << "-gl_InvocationID-1)*" << de::floatToString(0.4f * output.numBasicSubobjectsInElementType(), 1) << ";\n"; 575 } 576 tcsStatements << "\t}\n"; 577 578 tcsDeclarations << "\n" 579 << "layout(location = 0) in " + Variable("in_tc_attr", highpFloat, true).declareArray(vertexAttrArrayInputSize); 580 581 if (usedStruct) 582 tesDeclarations << de::toString(glu::declare(structType)) << ";\n"; 583 584 tesStatements << "\tbool allOk = true;\n" 585 << "\thighp uint firstFailedInputIndex = 0u;\n" 586 << "\t{\n" 587 << "\t\thighp float v = 1.3;\n"; 588 589 for (int tesInputNdx = 0; tesInputNdx < static_cast<int>(m_tesInputs.size()); ++tesInputNdx) 590 { 591 const TopLevelObject& input = *m_tesInputs[tesInputNdx]; 592 const int numElements = !isPerPatchIO ? NUM_OUTPUT_VERTICES 593 : m_caseDef.ioType == IO_TYPE_PER_PATCH ? 1 594 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK ? 1 595 : m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY ? NUM_PER_PATCH_ARRAY_ELEMS 596 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY ? NUM_PER_PATCH_BLOCKS 597 : wrongNumElements; 598 const bool isArray = (numElements != 1); 599 600 DE_ASSERT(numElements != wrongNumElements); 601 602 tesDeclarations << "layout(location = " << tesNextInputLocation << ") "; 603 if (isArray) 604 tesDeclarations << inMaybePatch << input.declareArray(m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY ? de::toString(NUM_PER_PATCH_ARRAY_ELEMS) 605 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY ? de::toString(NUM_PER_PATCH_BLOCKS) 606 : isExplicitVertexArraySize ? de::toString(vertexAttrArrayInputSize) 607 : ""); 608 else 609 tesDeclarations << inMaybePatch + input.declare(); 610 611 tesNextInputLocation += input.numBasicSubobjectsInElementType(); 612 613 tesStatements << "\n\t\t// Check values in input " << input.name() << "\n"; 614 if (isArray) 615 tesStatements << input.glslTraverseBasicTypeArray(numElements, 2, glslCheckBasicTypeObject); 616 else 617 tesStatements << input.glslTraverseBasicType(2, glslCheckBasicTypeObject); 618 } 619 tesStatements << "\t}\n"; 620 621 m_tcsDeclarations = tcsDeclarations.str(); 622 m_tcsStatements = tcsStatements.str(); 623 m_tesDeclarations = tesDeclarations.str(); 624 m_tesStatements = tesStatements.str(); 625} 626 627void UserDefinedIOTest::initPrograms (vk::SourceCollections& programCollection) const 628{ 629 // Vertex shader 630 { 631 std::ostringstream src; 632 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 633 << "\n" 634 << "layout(location = 0) in highp float in_v_attr;\n" 635 << "layout(location = 0) out highp float in_tc_attr;\n" 636 << "\n" 637 << "void main (void)\n" 638 << "{\n" 639 << " in_tc_attr = in_v_attr;\n" 640 << "}\n"; 641 642 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 643 } 644 645 // Tessellation control shader 646 { 647 std::ostringstream src; 648 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 649 << "#extension GL_EXT_tessellation_shader : require\n" 650 << "\n" 651 << "layout(vertices = " << NUM_OUTPUT_VERTICES << ") out;\n" 652 << "\n" 653 << "layout(location = 0) patch out highp vec2 in_te_positionScale;\n" 654 << "layout(location = 1) patch out highp vec2 in_te_positionOffset;\n" 655 << "\n" 656 << m_tcsDeclarations 657 << "\n" 658 << "void main (void)\n" 659 << "{\n" 660 << m_tcsStatements 661 << "\n" 662 << " gl_TessLevelInner[0] = in_tc_attr[0];\n" 663 << " gl_TessLevelInner[1] = in_tc_attr[1];\n" 664 << "\n" 665 << " gl_TessLevelOuter[0] = in_tc_attr[2];\n" 666 << " gl_TessLevelOuter[1] = in_tc_attr[3];\n" 667 << " gl_TessLevelOuter[2] = in_tc_attr[4];\n" 668 << " gl_TessLevelOuter[3] = in_tc_attr[5];\n" 669 << "\n" 670 << " in_te_positionScale = vec2(in_tc_attr[6], in_tc_attr[7]);\n" 671 << " in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n" 672 << "}\n"; 673 674 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 675 } 676 677 // Tessellation evaluation shader 678 { 679 std::ostringstream src; 680 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 681 << "#extension GL_EXT_tessellation_shader : require\n" 682 << "\n" 683 << "layout(" << getTessPrimitiveTypeShaderName(m_caseDef.primitiveType) << ") in;\n" 684 << "\n" 685 << "layout(location = 0) patch in highp vec2 in_te_positionScale;\n" 686 << "layout(location = 1) patch in highp vec2 in_te_positionOffset;\n" 687 << "\n" 688 << m_tesDeclarations 689 << "\n" 690 << "layout(location = 0) out highp vec4 in_f_color;\n" 691 << "\n" 692 << "// Will contain the index of the first incorrect input,\n" 693 << "// or the number of inputs if all are correct\n" 694 << "layout (set = 0, binding = 0, std430) coherent restrict buffer Output {\n" 695 << " int numInvocations;\n" 696 << " uint firstFailedInputIndex[];\n" 697 << "} sb_out;\n" 698 << "\n" 699 << "bool compare_int (int a, int b) { return a == b; }\n" 700 << "bool compare_float (float a, float b) { return abs(a - b) < 0.01f; }\n" 701 << "bool compare_vec4 (vec4 a, vec4 b) { return all(lessThan(abs(a - b), vec4(0.01f))); }\n" 702 << "\n" 703 << "void main (void)\n" 704 << "{\n" 705 << m_tesStatements 706 << "\n" 707 << " gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n" 708 << " in_f_color = allOk ? vec4(0.0, 1.0, 0.0, 1.0)\n" 709 << " : vec4(1.0, 0.0, 0.0, 1.0);\n" 710 << "\n" 711 << " int index = atomicAdd(sb_out.numInvocations, 1);\n" 712 << " sb_out.firstFailedInputIndex[index] = firstFailedInputIndex;\n" 713 << "}\n"; 714 715 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 716 } 717 718 // Fragment shader 719 { 720 std::ostringstream src; 721 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 722 << "\n" 723 << "layout(location = 0) in highp vec4 in_f_color;\n" 724 << "layout(location = 0) out mediump vec4 o_color;\n" 725 << "\n" 726 << "void main (void)\n" 727 << "{\n" 728 << " o_color = in_f_color;\n" 729 << "}\n"; 730 731 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 732 } 733} 734 735class UserDefinedIOTestInstance : public TestInstance 736{ 737public: 738 UserDefinedIOTestInstance (Context& context, 739 const CaseDefinition caseDef, 740 const std::vector<de::SharedPtr<TopLevelObject> >& tesInputs); 741 tcu::TestStatus iterate (void); 742 743private: 744 const CaseDefinition m_caseDef; 745 const std::vector<de::SharedPtr<TopLevelObject> > m_tesInputs; 746}; 747 748UserDefinedIOTestInstance::UserDefinedIOTestInstance (Context& context, const CaseDefinition caseDef, const std::vector<de::SharedPtr<TopLevelObject> >& tesInputs) 749 : TestInstance (context) 750 , m_caseDef (caseDef) 751 , m_tesInputs (tesInputs) 752{ 753} 754 755tcu::TestStatus UserDefinedIOTestInstance::iterate (void) 756{ 757 requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS); 758 759 const DeviceInterface& vk = m_context.getDeviceInterface(); 760 const VkDevice device = m_context.getDevice(); 761 const VkQueue queue = m_context.getUniversalQueue(); 762 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 763 Allocator& allocator = m_context.getDefaultAllocator(); 764 765 const int numAttributes = NUM_TESS_LEVELS + 2 + 2; 766 static const float attributes[numAttributes] = { /* inner */ 3.0f, 4.0f, /* outer */ 5.0f, 6.0f, 7.0f, 8.0f, /* pos. scale */ 1.2f, 1.3f, /* pos. offset */ -0.3f, -0.4f }; 767 const int refNumVertices = referenceVertexCount(m_caseDef.primitiveType, SPACINGMODE_EQUAL, false, &attributes[0], &attributes[2]); 768 const int refNumUniqueVertices = referenceVertexCount(m_caseDef.primitiveType, SPACINGMODE_EQUAL, true, &attributes[0], &attributes[2]); 769 770 // Vertex input attributes buffer: to pass tessellation levels 771 772 const VkFormat vertexFormat = VK_FORMAT_R32_SFLOAT; 773 const deUint32 vertexStride = tcu::getPixelSize(mapVkFormat(vertexFormat)); 774 const VkDeviceSize vertexDataSizeBytes = numAttributes * vertexStride; 775 const Buffer vertexBuffer (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible); 776 777 { 778 const Allocation& alloc = vertexBuffer.getAllocation(); 779 deMemcpy(alloc.getHostPtr(), &attributes[0], static_cast<std::size_t>(vertexDataSizeBytes)); 780 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes); 781 } 782 783 // Output buffer: number of invocations and verification indices 784 785 const int resultBufferMaxVertices = refNumVertices; 786 const VkDeviceSize resultBufferSizeBytes = sizeof(deInt32) + resultBufferMaxVertices * sizeof(deUint32); 787 const Buffer resultBuffer (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 788 789 { 790 const Allocation& alloc = resultBuffer.getAllocation(); 791 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes)); 792 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes); 793 } 794 795 // Color attachment 796 797 const tcu::IVec2 renderSize = tcu::IVec2(RENDER_SIZE, RENDER_SIZE); 798 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 799 const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 800 const Image colorAttachmentImage (vk, device, allocator, 801 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u), 802 MemoryRequirement::Any); 803 804 // Color output buffer: image will be copied here for verification 805 806 const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)); 807 const Buffer colorBuffer (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible); 808 809 // Descriptors 810 811 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 812 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) 813 .build(vk, device)); 814 815 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 816 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 817 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 818 819 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 820 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes); 821 822 DescriptorSetUpdateBuilder() 823 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo) 824 .update(vk, device); 825 826 // Pipeline 827 828 const Unique<VkImageView> colorAttachmentView(makeImageView (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange)); 829 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, colorFormat)); 830 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u)); 831 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); 832 const Unique<VkCommandPool> cmdPool (makeCommandPool (vk, device, queueFamilyIndex)); 833 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 834 835 const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder() 836 .setRenderSize (renderSize) 837 .setPatchControlPoints (numAttributes) 838 .setVertexInputSingleAttribute(vertexFormat, vertexStride) 839 .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), DE_NULL) 840 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), DE_NULL) 841 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL) 842 .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), DE_NULL) 843 .build (vk, device, *pipelineLayout, *renderPass)); 844 845 // Begin draw 846 847 beginCommandBuffer(vk, *cmdBuffer); 848 849 // Change color attachment image layout 850 { 851 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier( 852 (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 853 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 854 *colorAttachmentImage, colorImageSubresourceRange); 855 856 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 857 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier); 858 } 859 860 { 861 const VkRect2D renderArea = { 862 makeOffset2D(0, 0), 863 makeExtent2D(renderSize.x(), renderSize.y()), 864 }; 865 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f); 866 867 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); 868 } 869 870 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 871 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 872 { 873 const VkDeviceSize vertexBufferOffset = 0ull; 874 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); 875 } 876 877 vk.cmdDraw(*cmdBuffer, numAttributes, 1u, 0u, 0u); 878 endRenderPass(vk, *cmdBuffer); 879 880 // Copy render result to a host-visible buffer 881 { 882 const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier( 883 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 884 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 885 *colorAttachmentImage, colorImageSubresourceRange); 886 887 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 888 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier); 889 } 890 { 891 const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 0), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)); 892 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ©Region); 893 } 894 { 895 const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier( 896 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes); 897 898 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 899 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL); 900 } 901 902 endCommandBuffer(vk, *cmdBuffer); 903 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 904 905 // Verification 906 907 bool isImageCompareOK = false; 908 { 909 const Allocation& colorBufferAlloc = colorBuffer.getAllocation(); 910 invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes); 911 912 // Load reference image 913 tcu::TextureLevel referenceImage; 914 tcu::ImageIO::loadPNG(referenceImage, m_context.getTestContext().getArchive(), m_caseDef.referenceImagePath.c_str()); 915 916 // Verify case result 917 const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr()); 918 isImageCompareOK = tcu::fuzzyCompare(m_context.getTestContext().getLog(), "ImageComparison", "Image Comparison", 919 referenceImage.getAccess(), resultImageAccess, 0.02f, tcu::COMPARE_LOG_RESULT); 920 } 921 { 922 const Allocation& resultAlloc = resultBuffer.getAllocation(); 923 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes); 924 925 const deInt32 numVertices = *static_cast<deInt32*>(resultAlloc.getHostPtr()); 926 const deUint32* const vertices = reinterpret_cast<deUint32*>(static_cast<deUint8*>(resultAlloc.getHostPtr()) + sizeof(deInt32)); 927 928 // If this fails then we didn't read all vertices from shader and test must be changed to allow more. 929 DE_ASSERT(numVertices <= refNumVertices); 930 931 if (numVertices < refNumUniqueVertices) 932 { 933 m_context.getTestContext().getLog() 934 << tcu::TestLog::Message << "Failure: got " << numVertices << " vertices, but expected at least " << refNumUniqueVertices << tcu::TestLog::EndMessage; 935 936 return tcu::TestStatus::fail("Wrong number of vertices"); 937 } 938 else 939 { 940 tcu::TestLog& log = m_context.getTestContext().getLog(); 941 const int topLevelArraySize = (m_caseDef.ioType == IO_TYPE_PER_PATCH ? 1 942 : m_caseDef.ioType == IO_TYPE_PER_PATCH_ARRAY ? NUM_PER_PATCH_ARRAY_ELEMS 943 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK ? 1 944 : m_caseDef.ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY ? NUM_PER_PATCH_BLOCKS 945 : NUM_OUTPUT_VERTICES); 946 const deUint32 numTEInputs = numBasicSubobjectsInElementType(m_tesInputs) * topLevelArraySize; 947 948 for (int vertexNdx = 0; vertexNdx < numVertices; ++vertexNdx) 949 if (vertices[vertexNdx] > numTEInputs) 950 { 951 log << tcu::TestLog::Message 952 << "Failure: out_te_firstFailedInputIndex has value " << vertices[vertexNdx] 953 << ", but should be in range [0, " << numTEInputs << "]" << tcu::TestLog::EndMessage; 954 955 return tcu::TestStatus::fail("Invalid values returned from shader"); 956 } 957 else if (vertices[vertexNdx] != numTEInputs) 958 { 959 log << tcu::TestLog::Message << "Failure: in tessellation evaluation shader, check for input " 960 << basicSubobjectAtIndex(vertices[vertexNdx], m_tesInputs, topLevelArraySize) << " failed" << tcu::TestLog::EndMessage; 961 962 return tcu::TestStatus::fail("Invalid input value in tessellation evaluation shader"); 963 } 964 } 965 } 966 return (isImageCompareOK ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed")); 967} 968 969TestInstance* UserDefinedIOTest::createInstance (Context& context) const 970{ 971 return new UserDefinedIOTestInstance(context, m_caseDef, m_tesInputs); 972} 973 974} // anonymous 975 976//! These tests correspond roughly to dEQP-GLES31.functional.tessellation.user_defined_io.* 977//! Original GLES test queried maxTessellationPatchSize, but this can't be done at the stage the shader source is prepared. 978//! Instead, we use minimum supported value. 979//! Negative tests weren't ported because vktShaderLibrary doesn't support tests that are expected to fail shader compilation. 980tcu::TestCaseGroup* createUserDefinedIOTests (tcu::TestContext& testCtx) 981{ 982 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "user_defined_io", "Test non-built-in per-patch and per-vertex inputs and outputs")); 983 984 static const struct 985 { 986 const char* name; 987 const char* description; 988 IOType ioType; 989 } ioCases[] = 990 { 991 { "per_patch", "Per-patch TCS outputs", IO_TYPE_PER_PATCH }, 992 { "per_patch_array", "Per-patch array TCS outputs", IO_TYPE_PER_PATCH_ARRAY }, 993 { "per_patch_block", "Per-patch TCS outputs in IO block", IO_TYPE_PER_PATCH_BLOCK }, 994 { "per_patch_block_array", "Per-patch TCS outputs in IO block array", IO_TYPE_PER_PATCH_BLOCK_ARRAY }, 995 { "per_vertex", "Per-vertex TCS outputs", IO_TYPE_PER_VERTEX }, 996 { "per_vertex_block", "Per-vertex TCS outputs in IO block", IO_TYPE_PER_VERTEX_BLOCK }, 997 }; 998 999 static const struct 1000 { 1001 const char* name; 1002 VertexIOArraySize vertexIOArraySize; 1003 } vertexArraySizeCases[] = 1004 { 1005 { "vertex_io_array_size_implicit", VERTEX_IO_ARRAY_SIZE_IMPLICIT }, 1006 { "vertex_io_array_size_shader_builtin", VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN }, 1007 { "vertex_io_array_size_spec_min", VERTEX_IO_ARRAY_SIZE_EXPLICIT_SPEC_MIN }, 1008 }; 1009 1010 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(ioCases); ++caseNdx) 1011 { 1012 de::MovePtr<tcu::TestCaseGroup> ioTypeGroup (new tcu::TestCaseGroup(testCtx, ioCases[caseNdx].name, ioCases[caseNdx].description)); 1013 for (int arrayCaseNdx = 0; arrayCaseNdx < DE_LENGTH_OF_ARRAY(vertexArraySizeCases); ++arrayCaseNdx) 1014 { 1015 de::MovePtr<tcu::TestCaseGroup> vertexArraySizeGroup (new tcu::TestCaseGroup(testCtx, vertexArraySizeCases[arrayCaseNdx].name, "")); 1016 for (int primitiveTypeNdx = 0; primitiveTypeNdx < TESSPRIMITIVETYPE_LAST; ++primitiveTypeNdx) 1017 { 1018 const TessPrimitiveType primitiveType = static_cast<TessPrimitiveType>(primitiveTypeNdx); 1019 const std::string primitiveName = getTessPrimitiveTypeShaderName(primitiveType); 1020 const CaseDefinition caseDef = { primitiveType, ioCases[caseNdx].ioType, vertexArraySizeCases[arrayCaseNdx].vertexIOArraySize, 1021 std::string() + "vulkan/data/tessellation/user_defined_io_" + primitiveName + "_ref.png" }; 1022 1023 vertexArraySizeGroup->addChild(new UserDefinedIOTest(testCtx, primitiveName, "", caseDef)); 1024 } 1025 ioTypeGroup->addChild(vertexArraySizeGroup.release()); 1026 } 1027 group->addChild(ioTypeGroup.release()); 1028 } 1029 1030 return group.release(); 1031} 1032 1033} // tessellation 1034} // vkt 1035