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 Fractional Spacing Tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktTessellationFractionalSpacingTests.hpp" 26#include "vktTestCaseUtil.hpp" 27#include "vktTessellationUtil.hpp" 28 29#include "tcuTestLog.hpp" 30 31#include "vkDefs.hpp" 32#include "vkQueryUtil.hpp" 33#include "vkBuilderUtil.hpp" 34#include "vkTypeUtil.hpp" 35 36#include "deUniquePtr.hpp" 37#include "deStringUtil.hpp" 38 39#include <string> 40#include <vector> 41 42namespace vkt 43{ 44namespace tessellation 45{ 46 47using namespace vk; 48 49namespace 50{ 51 52template <typename T, typename MembT> 53std::vector<MembT> members (const std::vector<T>& objs, MembT T::* membP) 54{ 55 std::vector<MembT> result(objs.size()); 56 for (int i = 0; i < static_cast<int>(objs.size()); ++i) 57 result[i] = objs[i].*membP; 58 return result; 59} 60 61//! Predicate functor for comparing structs by their members. 62template <typename Pred, typename T, typename MembT> 63class MemberPred 64{ 65public: 66 MemberPred (MembT T::* membP) : m_membP(membP), m_pred(Pred()) {} 67 bool operator() (const T& a, const T& b) const { return m_pred(a.*m_membP, b.*m_membP); } 68 69private: 70 MembT T::* m_membP; 71 Pred m_pred; 72}; 73 74//! Convenience wrapper for MemberPred, because class template arguments aren't deduced based on constructor arguments. 75template <template <typename> class Pred, typename T, typename MembT> 76inline MemberPred<Pred<MembT>, T, MembT> memberPred (MembT T::* membP) { return MemberPred<Pred<MembT>, T, MembT>(membP); } 77 78struct Segment 79{ 80 int index; //!< Index of left coordinate in sortedXCoords. 81 float length; 82 83 Segment (void) : index(-1), length(-1.0f) {} 84 Segment (int index_, float length_) : index(index_), length(length_) {} 85}; 86 87inline std::vector<float> lengths (const std::vector<Segment>& segments) { return members(segments, &Segment::length); } 88 89struct LineData 90{ 91 float tessLevel; 92 float additionalSegmentLength; 93 int additionalSegmentLocation; 94 95 LineData (float lev, float len, int loc) : tessLevel(lev), additionalSegmentLength(len), additionalSegmentLocation(loc) {} 96}; 97 98/*--------------------------------------------------------------------*//*! 99 * \brief Verify fractional spacing conditions for a single line 100 * 101 * Verify that the splitting of an edge (resulting from e.g. an isoline 102 * with outer levels { 1.0, tessLevel }) with a given fractional spacing 103 * mode fulfills certain conditions given in the spec. 104 * 105 * Note that some conditions can't be checked from just one line 106 * (specifically, that the additional segment decreases monotonically 107 * length and the requirement that the additional segments be placed 108 * identically for identical values of clamped level). 109 * 110 * Therefore, the function stores some values to additionalSegmentLengthDst 111 * and additionalSegmentLocationDst that can later be given to 112 * verifyFractionalSpacingMultiple(). A negative value in length means that 113 * no additional segments are present, i.e. there's just one segment. 114 * A negative value in location means that the value wasn't determinable, 115 * i.e. all segments had same length. 116 * The values are not stored if false is returned. 117 *//*--------------------------------------------------------------------*/ 118bool verifyFractionalSpacingSingle (tcu::TestLog& log, 119 const SpacingMode spacingMode, 120 const float tessLevel, 121 const std::vector<float>& coords, 122 float* const pOutAdditionalSegmentLength, 123 int* const pOutAdditionalSegmentLocation) 124{ 125 DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN); 126 127 const float clampedLevel = getClampedTessLevel(spacingMode, tessLevel); 128 const int finalLevel = getRoundedTessLevel(spacingMode, clampedLevel); 129 const std::vector<float> sortedCoords = sorted(coords); 130 std::string failNote = "Note: tessellation level is " + de::toString(tessLevel) + "\nNote: sorted coordinates are:\n " + containerStr(sortedCoords); 131 132 if (static_cast<int>(coords.size()) != finalLevel + 1) 133 { 134 log << tcu::TestLog::Message << "Failure: number of vertices is " << coords.size() << "; expected " << finalLevel + 1 135 << " (clamped tessellation level is " << clampedLevel << ")" 136 << "; final level (clamped level rounded up to " << (spacingMode == SPACINGMODE_FRACTIONAL_EVEN ? "even" : "odd") << ") is " << finalLevel 137 << " and should equal the number of segments, i.e. number of vertices minus 1" << tcu::TestLog::EndMessage 138 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 139 return false; 140 } 141 142 if (sortedCoords[0] != 0.0f || sortedCoords.back() != 1.0f) 143 { 144 log << tcu::TestLog::Message << "Failure: smallest coordinate should be 0.0 and biggest should be 1.0" << tcu::TestLog::EndMessage 145 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 146 return false; 147 } 148 149 { 150 std::vector<Segment> segments(finalLevel); 151 for (int i = 0; i < finalLevel; ++i) 152 segments[i] = Segment(i, sortedCoords[i+1] - sortedCoords[i]); 153 154 failNote += "\nNote: segment lengths are, from left to right:\n " + containerStr(lengths(segments)); 155 156 { 157 // Divide segments to two different groups based on length. 158 159 std::vector<Segment> segmentsA; 160 std::vector<Segment> segmentsB; 161 segmentsA.push_back(segments[0]); 162 163 for (int segNdx = 1; segNdx < static_cast<int>(segments.size()); ++segNdx) 164 { 165 const float epsilon = 0.001f; 166 const Segment& seg = segments[segNdx]; 167 168 if (de::abs(seg.length - segmentsA[0].length) < epsilon) 169 segmentsA.push_back(seg); 170 else if (segmentsB.empty() || de::abs(seg.length - segmentsB[0].length) < epsilon) 171 segmentsB.push_back(seg); 172 else 173 { 174 log << tcu::TestLog::Message << "Failure: couldn't divide segments to 2 groups by length; " 175 << "e.g. segment of length " << seg.length << " isn't approximately equal to either " 176 << segmentsA[0].length << " or " << segmentsB[0].length << tcu::TestLog::EndMessage 177 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 178 return false; 179 } 180 } 181 182 if (clampedLevel == static_cast<float>(finalLevel)) 183 { 184 // All segments should be of equal length. 185 if (!segmentsA.empty() && !segmentsB.empty()) 186 { 187 log << tcu::TestLog::Message << "Failure: clamped and final tessellation level are equal, but not all segments are of equal length." << tcu::TestLog::EndMessage 188 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 189 return false; 190 } 191 } 192 193 if (segmentsA.empty() || segmentsB.empty()) // All segments have same length. This is ok. 194 { 195 *pOutAdditionalSegmentLength = (segments.size() == 1 ? -1.0f : segments[0].length); 196 *pOutAdditionalSegmentLocation = -1; 197 return true; 198 } 199 200 if (segmentsA.size() != 2 && segmentsB.size() != 2) 201 { 202 log << tcu::TestLog::Message << "Failure: when dividing the segments to 2 groups by length, neither of the two groups has exactly 2 or 0 segments in it" << tcu::TestLog::EndMessage 203 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 204 return false; 205 } 206 207 // For convenience, arrange so that the 2-segment group is segmentsB. 208 if (segmentsB.size() != 2) 209 std::swap(segmentsA, segmentsB); 210 211 // \note For 4-segment lines both segmentsA and segmentsB have 2 segments each. 212 // Thus, we can't be sure which ones were meant as the additional segments. 213 // We give the benefit of the doubt by assuming that they're the shorter 214 // ones (as they should). 215 216 if (segmentsA.size() != 2) 217 { 218 if (segmentsB[0].length > segmentsA[0].length + 0.001f) 219 { 220 log << tcu::TestLog::Message << "Failure: the two additional segments are longer than the other segments" << tcu::TestLog::EndMessage 221 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 222 return false; 223 } 224 } 225 else 226 { 227 // We have 2 segmentsA and 2 segmentsB, ensure segmentsB has the shorter lengths 228 if (segmentsB[0].length > segmentsA[0].length) 229 std::swap(segmentsA, segmentsB); 230 } 231 232 // Check that the additional segments are placed symmetrically. 233 if (segmentsB[0].index + segmentsB[1].index + 1 != static_cast<int>(segments.size())) 234 { 235 log << tcu::TestLog::Message << "Failure: the two additional segments aren't placed symmetrically; " 236 << "one is at index " << segmentsB[0].index << " and other is at index " << segmentsB[1].index 237 << " (note: the two indexes should sum to " << static_cast<int>(segments.size())-1 << ", i.e. numberOfSegments-1)" << tcu::TestLog::EndMessage 238 << tcu::TestLog::Message << failNote << tcu::TestLog::EndMessage; 239 return false; 240 } 241 242 *pOutAdditionalSegmentLength = segmentsB[0].length; 243 if (segmentsA.size() != 2) 244 *pOutAdditionalSegmentLocation = de::min(segmentsB[0].index, segmentsB[1].index); 245 else 246 *pOutAdditionalSegmentLocation = segmentsB[0].length < segmentsA[0].length - 0.001f ? de::min(segmentsB[0].index, segmentsB[1].index) 247 : -1; // \note -1 when can't reliably decide which ones are the additional segments, a or b. 248 249 return true; 250 } 251 } 252} 253 254/*--------------------------------------------------------------------*//*! 255 * \brief Verify fractional spacing conditions between multiple lines 256 * 257 * Verify the fractional spacing conditions that are not checked in 258 * verifyFractionalSpacingSingle(). Uses values given by said function 259 * as parameters, in addition to the spacing mode and tessellation level. 260 *//*--------------------------------------------------------------------*/ 261static bool verifyFractionalSpacingMultiple (tcu::TestLog& log, 262 const SpacingMode spacingMode, 263 const std::vector<float>& tessLevels, 264 const std::vector<float>& additionalSegmentLengths, 265 const std::vector<int>& additionalSegmentLocations) 266{ 267 DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN); 268 DE_ASSERT(tessLevels.size() == additionalSegmentLengths.size() && tessLevels.size() == additionalSegmentLocations.size()); 269 270 std::vector<LineData> lineDatas; 271 272 for (int i = 0; i < static_cast<int>(tessLevels.size()); ++i) 273 lineDatas.push_back(LineData(tessLevels[i], additionalSegmentLengths[i], additionalSegmentLocations[i])); 274 275 { 276 const std::vector<LineData> lineDatasSortedByLevel = sorted(lineDatas, memberPred<std::less>(&LineData::tessLevel)); 277 278 // Check that lines with identical clamped tessellation levels have identical additionalSegmentLocation. 279 280 for (int lineNdx = 1; lineNdx < static_cast<int>(lineDatasSortedByLevel.size()); ++lineNdx) 281 { 282 const LineData& curData = lineDatasSortedByLevel[lineNdx]; 283 const LineData& prevData = lineDatasSortedByLevel[lineNdx-1]; 284 285 if (curData.additionalSegmentLocation < 0 || prevData.additionalSegmentLocation < 0) 286 continue; // Unknown locations, skip. 287 288 if (getClampedTessLevel(spacingMode, curData.tessLevel) == getClampedTessLevel(spacingMode, prevData.tessLevel) && 289 curData.additionalSegmentLocation != prevData.additionalSegmentLocation) 290 { 291 log << tcu::TestLog::Message << "Failure: additional segments not located identically for two edges with identical clamped tessellation levels" << tcu::TestLog::EndMessage 292 << tcu::TestLog::Message << "Note: tessellation levels are " << curData.tessLevel << " and " << prevData.tessLevel 293 << " (clamped level " << getClampedTessLevel(spacingMode, curData.tessLevel) << ")" 294 << "; but first additional segments located at indices " 295 << curData.additionalSegmentLocation << " and " << prevData.additionalSegmentLocation << ", respectively" << tcu::TestLog::EndMessage; 296 return false; 297 } 298 } 299 300 // Check that, among lines with same clamped rounded tessellation level, additionalSegmentLength is monotonically decreasing with "clampedRoundedTessLevel - clampedTessLevel" (the "fraction"). 301 302 for (int lineNdx = 1; lineNdx < static_cast<int>(lineDatasSortedByLevel.size()); ++lineNdx) 303 { 304 const LineData& curData = lineDatasSortedByLevel[lineNdx]; 305 const LineData& prevData = lineDatasSortedByLevel[lineNdx-1]; 306 307 if (curData.additionalSegmentLength < 0.0f || prevData.additionalSegmentLength < 0.0f) 308 continue; // Unknown segment lengths, skip. 309 310 const float curClampedLevel = getClampedTessLevel(spacingMode, curData.tessLevel); 311 const float prevClampedLevel = getClampedTessLevel(spacingMode, prevData.tessLevel); 312 const int curFinalLevel = getRoundedTessLevel(spacingMode, curClampedLevel); 313 const int prevFinalLevel = getRoundedTessLevel(spacingMode, prevClampedLevel); 314 315 if (curFinalLevel != prevFinalLevel) 316 continue; 317 318 const float curFraction = static_cast<float>(curFinalLevel) - curClampedLevel; 319 const float prevFraction = static_cast<float>(prevFinalLevel) - prevClampedLevel; 320 321 if (curData.additionalSegmentLength < prevData.additionalSegmentLength || 322 (curClampedLevel == prevClampedLevel && curData.additionalSegmentLength != prevData.additionalSegmentLength)) 323 { 324 log << tcu::TestLog::Message << "Failure: additional segment length isn't monotonically decreasing with the fraction <n> - <f>, among edges with same final tessellation level" << tcu::TestLog::EndMessage 325 << tcu::TestLog::Message << "Note: <f> stands for the clamped tessellation level and <n> for the final (rounded and clamped) tessellation level" << tcu::TestLog::EndMessage 326 << tcu::TestLog::Message << "Note: two edges have tessellation levels " << prevData.tessLevel << " and " << curData.tessLevel << " respectively" 327 << ", clamped " << prevClampedLevel << " and " << curClampedLevel << ", final " << prevFinalLevel << " and " << curFinalLevel 328 << "; fractions are " << prevFraction << " and " << curFraction 329 << ", but resulted in segment lengths " << prevData.additionalSegmentLength << " and " << curData.additionalSegmentLength << tcu::TestLog::EndMessage; 330 return false; 331 } 332 } 333 } 334 335 return true; 336} 337 338std::vector<float> genTessLevelCases (void) 339{ 340 std::vector<float> result; 341 342 // Ranges [7.0 .. 8.0), [8.0 .. 9.0) and [9.0 .. 10.0) 343 { 344 static const float rangeStarts[] = { 7.0f, 8.0f, 9.0f }; 345 const int numSamplesPerRange = 10; 346 347 for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(rangeStarts); ++rangeNdx) 348 for (int i = 0; i < numSamplesPerRange; ++i) 349 result.push_back(rangeStarts[rangeNdx] + static_cast<float>(i)/numSamplesPerRange); 350 } 351 352 // 0.3, 1.3, 2.3, ... , 62.3 353 for (int i = 0; i <= 62; ++i) 354 result.push_back(static_cast<float>(i) + 0.3f); 355 356 return result; 357} 358 359//! Create a vector of floats from an array of floats. Offset is in bytes. 360std::vector<float> readFloatArray(const int count, const void* memory, const int offset) 361{ 362 std::vector<float> results(count); 363 364 const float* pFloatData = reinterpret_cast<const float*>(static_cast<const deUint8*>(memory) + offset); 365 deMemcpy(&results[0], pFloatData, sizeof(float) * count); 366 367 return results; 368} 369 370void initPrograms (vk::SourceCollections& programCollection, const SpacingMode spacingMode) 371{ 372 // Vertex shader: no inputs 373 { 374 std::ostringstream src; 375 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 376 << "\n" 377 << "void main (void)\n" 378 << "{\n" 379 << "}\n"; 380 381 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 382 } 383 384 // Tessellation control shader 385 { 386 std::ostringstream src; 387 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 388 << "#extension GL_EXT_tessellation_shader : require\n" 389 << "\n" 390 << "layout(vertices = 1) out;\n" 391 << "\n" 392 << "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n" 393 << " float outer1;\n" 394 << "} sb_levels;\n" 395 << "\n" 396 << "void main (void)\n" 397 << "{\n" 398 << " gl_TessLevelOuter[0] = 1.0;\n" 399 << " gl_TessLevelOuter[1] = sb_levels.outer1;\n" 400 << "}\n"; 401 402 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 403 } 404 405 // Tessellation evaluation shader 406 { 407 std::ostringstream src; 408 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 409 << "#extension GL_EXT_tessellation_shader : require\n" 410 << "\n" 411 << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_ISOLINES) << ", " 412 << getSpacingModeShaderName(spacingMode) << ", point_mode) in;\n" 413 << "\n" 414 << "layout(set = 0, binding = 1, std430) coherent restrict buffer Output {\n" 415 << " int numInvocations;\n" 416 << " float tessCoord[];\n" 417 << "} sb_out;\n" 418 << "\n" 419 << "void main (void)\n" 420 << "{\n" 421 << " int index = atomicAdd(sb_out.numInvocations, 1);\n" 422 << " sb_out.tessCoord[index] = gl_TessCoord.x;\n" 423 << "}\n"; 424 425 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 426 } 427} 428 429tcu::TestStatus test (Context& context, const SpacingMode spacingMode) 430{ 431 DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN); 432 433 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS); 434 435 const DeviceInterface& vk = context.getDeviceInterface(); 436 const VkDevice device = context.getDevice(); 437 const VkQueue queue = context.getUniversalQueue(); 438 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 439 Allocator& allocator = context.getDefaultAllocator(); 440 441 const std::vector<float> tessLevelCases = genTessLevelCases(); 442 const int maxNumVertices = 1 + getClampedRoundedTessLevel(spacingMode, *std::max_element(tessLevelCases.begin(), tessLevelCases.end())); 443 444 // Result buffer: generated tess coords go here. 445 446 const VkDeviceSize resultBufferSizeBytes = sizeof(int) + sizeof(float) * maxNumVertices; 447 const Buffer resultBuffer (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 448 449 // Outer1 tessellation level constant buffer. 450 451 const VkDeviceSize tessLevelsBufferSizeBytes = sizeof(float); // we pass only outer1 452 const Buffer tessLevelsBuffer (vk, device, allocator, makeBufferCreateInfo(tessLevelsBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 453 454 // Descriptors 455 456 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 457 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) 458 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) 459 .build(vk, device)); 460 461 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 462 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 463 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 464 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 465 466 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 467 const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, tessLevelsBufferSizeBytes); 468 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes); 469 470 DescriptorSetUpdateBuilder() 471 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo) 472 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo) 473 .update(vk, device); 474 475 // Pipeline 476 477 const Unique<VkRenderPass> renderPass (makeRenderPassWithoutAttachments (vk, device)); 478 const Unique<VkFramebuffer> framebuffer (makeFramebufferWithoutAttachments(vk, device, *renderPass)); 479 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout)); 480 const Unique<VkCommandPool> cmdPool (makeCommandPool (vk, device, queueFamilyIndex)); 481 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 482 483 const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder() 484 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL) 485 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"), DE_NULL) 486 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL) 487 .build(vk, device, *pipelineLayout, *renderPass)); 488 489 // Data that will be verified across all cases 490 std::vector<float> additionalSegmentLengths; 491 std::vector<int> additionalSegmentLocations; 492 493 bool success = false; 494 495 // Repeat the test for all tessellation coords cases 496 for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx) 497 { 498 // Upload tessellation levels data to the input buffer 499 { 500 const Allocation& alloc = tessLevelsBuffer.getAllocation(); 501 float* const tessLevelOuter1 = static_cast<float*>(alloc.getHostPtr()); 502 503 *tessLevelOuter1 = tessLevelCases[tessLevelCaseNdx]; 504 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), tessLevelsBufferSizeBytes); 505 } 506 507 // Clear the results buffer 508 { 509 const Allocation& alloc = resultBuffer.getAllocation(); 510 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes)); 511 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes); 512 } 513 514 beginCommandBuffer(vk, *cmdBuffer); 515 516 // Begin render pass 517 beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer); 518 519 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 520 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 521 522 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u); 523 endRenderPass(vk, *cmdBuffer); 524 525 { 526 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier( 527 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes); 528 529 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 530 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL); 531 } 532 533 endCommandBuffer(vk, *cmdBuffer); 534 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 535 536 // Verify the result. 537 { 538 tcu::TestLog& log = context.getTestContext().getLog(); 539 540 const Allocation& resultAlloc = resultBuffer.getAllocation(); 541 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes); 542 543 const deInt32 numResults = *static_cast<deInt32*>(resultAlloc.getHostPtr()); 544 const std::vector<float> resultTessCoords = readFloatArray(numResults, resultAlloc.getHostPtr(), sizeof(deInt32)); 545 546 // Outputs 547 float additionalSegmentLength; 548 int additionalSegmentLocation; 549 550 success = verifyFractionalSpacingSingle(log, spacingMode, tessLevelCases[tessLevelCaseNdx], resultTessCoords, 551 &additionalSegmentLength, &additionalSegmentLocation); 552 553 if (!success) 554 break; 555 556 additionalSegmentLengths.push_back(additionalSegmentLength); 557 additionalSegmentLocations.push_back(additionalSegmentLocation); 558 } 559 } // for tessLevelCaseNdx 560 561 if (success) 562 success = verifyFractionalSpacingMultiple(context.getTestContext().getLog(), spacingMode, tessLevelCases, additionalSegmentLengths, additionalSegmentLocations); 563 564 return (success ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure")); 565} 566 567} // anonymous 568 569//! These tests correspond to dEQP-GLES31.functional.tessellation.fractional_spacing.* 570//! Check validity of fractional spacing modes. Draws a single isoline, reads tess coords with SSBO. 571tcu::TestCaseGroup* createFractionalSpacingTests (tcu::TestContext& testCtx) 572{ 573 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "fractional_spacing", "Test fractional spacing modes")); 574 575 addFunctionCaseWithPrograms(group.get(), "odd", "", initPrograms, test, SPACINGMODE_FRACTIONAL_ODD); 576 addFunctionCaseWithPrograms(group.get(), "even", "", initPrograms, test, SPACINGMODE_FRACTIONAL_EVEN); 577 578 return group.release(); 579} 580 581} // tessellation 582} // vkt 583