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 45 namespace vkt 46 { 47 namespace tessellation 48 { 49 50 using namespace vk; 51 52 namespace 53 { 54 55 enum 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 65 enum 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 77 enum 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 86 struct CaseDefinition 87 { 88 TessPrimitiveType primitiveType; 89 IOType ioType; 90 VertexIOArraySize vertexIOArraySize; 91 std::string referenceImagePath; 92 }; 93 94 typedef std::string (*BasicTypeVisitFunc)(const std::string& name, glu::DataType type, int indentationDepth); //!< See glslTraverseBasicTypes below. 95 96 class TopLevelObject 97 { 98 public: 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 113 std::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. 153 std::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*(float)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. 173 std::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*(float)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 194 int 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 202 std::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 219 int 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 240 class Variable : public TopLevelObject 241 { 242 public: 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 259 private: 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 265 std::string Variable::declare (void) const 266 { 267 DE_ASSERT(!m_isArray); 268 return de::toString(glu::declare(m_type, m_name)) + ";\n"; 269 } 270 271 std::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 277 std::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 288 std::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 294 int Variable::numBasicSubobjectsInElementType (void) const 295 { 296 return numBasicSubobjects(m_type); 297 } 298 299 std::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 314 class IOBlock : public TopLevelObject 315 { 316 public: 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 340 private: 341 std::string m_blockName; 342 std::string m_interfaceName; 343 std::vector<Member> m_members; 344 }; 345 346 std::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 360 std::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 374 std::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 397 std::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 405 int 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 413 std::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 431 class UserDefinedIOTest : public TestCase 432 { 433 public: 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 438 private: 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 449 UserDefinedIOTest::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 * (float)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 * (float)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 627 void 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 735 class UserDefinedIOTestInstance : public TestInstance 736 { 737 public: 738 UserDefinedIOTestInstance (Context& context, 739 const CaseDefinition caseDef, 740 const std::vector<de::SharedPtr<TopLevelObject> >& tesInputs); 741 tcu::TestStatus iterate (void); 742 743 private: 744 const CaseDefinition m_caseDef; 745 const std::vector<de::SharedPtr<TopLevelObject> > m_tesInputs; 746 }; 747 748 UserDefinedIOTestInstance::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 755 tcu::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 (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 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(), 1), 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 969 TestInstance* 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. 980 tcu::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