1 /*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 The Khronos Group Inc. 6 * Copyright (c) 2017 Samsung Electronics Co., Ltd. 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 Protected memory interaction with VkSwapchain Tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktProtectedMemWsiSwapchainTests.hpp" 26 27 #include "vktTestCaseUtil.hpp" 28 #include "vktTestGroupUtil.hpp" 29 30 #include "vkDefs.hpp" 31 #include "vkPlatform.hpp" 32 #include "vkStrUtil.hpp" 33 #include "vkRef.hpp" 34 #include "vkRefUtil.hpp" 35 #include "vkQueryUtil.hpp" 36 #include "vkMemUtil.hpp" 37 #include "vkDeviceUtil.hpp" 38 #include "vkPrograms.hpp" 39 #include "vkTypeUtil.hpp" 40 #include "vkWsiPlatform.hpp" 41 #include "vkWsiUtil.hpp" 42 #include "vkAllocationCallbackUtil.hpp" 43 44 #include "tcuTestLog.hpp" 45 #include "tcuFormatUtil.hpp" 46 #include "tcuPlatform.hpp" 47 #include "tcuResultCollector.hpp" 48 49 #include "deUniquePtr.hpp" 50 #include "deStringUtil.hpp" 51 #include "deArrayUtil.hpp" 52 #include "deSharedPtr.hpp" 53 54 #include <limits> 55 56 #include "vktProtectedMemContext.hpp" 57 #include "vktProtectedMemUtils.hpp" 58 59 namespace vkt 60 { 61 namespace ProtectedMem 62 { 63 64 namespace 65 { 66 67 typedef std::vector<vk::VkExtensionProperties> Extensions; 68 69 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions) 70 { 71 for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin(); 72 requiredExtName != requiredExtensions.end(); 73 ++requiredExtName) 74 { 75 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName))) 76 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str()); 77 } 78 } 79 80 std::vector<std::string> getRequiredWsiExtensions (const Extensions& supportedExtensions, 81 vk::wsi::Type wsiType) 82 { 83 std::vector<std::string> extensions; 84 85 extensions.push_back("VK_KHR_surface"); 86 extensions.push_back(getExtensionName(wsiType)); 87 88 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate 89 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled, 90 // but using them without enabling the extension is not allowed. Thus we have 91 // two options: 92 // 93 // 1) Filter out non-core formats to stay within valid usage. 94 // 95 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver. 96 // 97 // We opt for (2) as it provides basic coverage for the extension as a bonus. 98 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace"))) 99 extensions.push_back("VK_EXT_swapchain_colorspace"); 100 101 checkAllSupported(supportedExtensions, extensions); 102 103 return extensions; 104 } 105 106 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform, 107 const Extensions& supportedExtensions, 108 vk::wsi::Type wsiType) 109 { 110 try 111 { 112 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType)); 113 } 114 catch (const tcu::NotSupportedError& e) 115 { 116 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType)))) 117 { 118 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation 119 // must support creating native display & window for that WSI type. 120 throw tcu::TestError(e.getMessage()); 121 } 122 else 123 throw; 124 } 125 } 126 127 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize) 128 { 129 try 130 { 131 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize)); 132 } 133 catch (const tcu::NotSupportedError& e) 134 { 135 // See createDisplay - assuming that wsi::Display was supported platform port 136 // should also support creating a window. 137 throw tcu::TestError(e.getMessage()); 138 } 139 } 140 141 struct NativeObjects 142 { 143 const de::UniquePtr<vk::wsi::Display> display; 144 const de::UniquePtr<vk::wsi::Window> window; 145 146 NativeObjects (Context& context, 147 const Extensions& supportedExtensions, 148 vk::wsi::Type wsiType, 149 const tcu::Maybe<tcu::UVec2>& initialWindowSize = tcu::nothing<tcu::UVec2>()) 150 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType)) 151 , window (createWindow(*display, initialWindowSize)) 152 {} 153 }; 154 155 enum TestDimension 156 { 157 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts 158 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats 159 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents 160 TEST_DIMENSION_IMAGE_ARRAY_LAYERS, 161 TEST_DIMENSION_IMAGE_USAGE, 162 TEST_DIMENSION_IMAGE_SHARING_MODE, 163 TEST_DIMENSION_PRE_TRANSFORM, 164 TEST_DIMENSION_COMPOSITE_ALPHA, 165 TEST_DIMENSION_PRESENT_MODE, 166 TEST_DIMENSION_CLIPPED, 167 168 TEST_DIMENSION_LAST 169 }; 170 171 const char* getTestDimensionName (TestDimension dimension) 172 { 173 static const char* const s_names[] = 174 { 175 "min_image_count", 176 "image_format", 177 "image_extent", 178 "image_array_layers", 179 "image_usage", 180 "image_sharing_mode", 181 "pre_transform", 182 "composite_alpha", 183 "present_mode", 184 "clipped" 185 }; 186 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension); 187 } 188 189 struct TestParameters 190 { 191 vk::wsi::Type wsiType; 192 TestDimension dimension; 193 194 TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_) 195 : wsiType (wsiType_) 196 , dimension (dimension_) 197 {} 198 199 TestParameters (void) 200 : wsiType (vk::wsi::TYPE_LAST) 201 , dimension (TEST_DIMENSION_LAST) 202 {} 203 }; 204 205 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType, 206 TestDimension dimension, 207 const ProtectedContext& context, 208 const vk::VkSurfaceCapabilitiesKHR& capabilities, 209 const std::vector<vk::VkSurfaceFormatKHR>& formats, 210 const std::vector<vk::VkPresentModeKHR>& presentModes) 211 { 212 std::vector<vk::VkSwapchainCreateInfoKHR> cases; 213 const vk::wsi::PlatformProperties& platformProperties = getPlatformProperties(wsiType); 214 const vk::VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) 215 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform; 216 const vk::VkSwapchainCreateInfoKHR baseParameters = 217 { 218 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 219 DE_NULL, 220 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR, 221 (vk::VkSurfaceKHR)0, 222 capabilities.minImageCount, 223 formats[0].format, 224 formats[0].colorSpace, 225 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE 226 ? capabilities.minImageExtent : capabilities.currentExtent), 227 1u, // imageArrayLayers 228 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 229 vk::VK_SHARING_MODE_EXCLUSIVE, 230 0u, 231 (const deUint32*)DE_NULL, 232 defaultTransform, 233 vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 234 vk::VK_PRESENT_MODE_FIFO_KHR, 235 VK_FALSE, // clipped 236 (vk::VkSwapchainKHR)0 // oldSwapchain 237 }; 238 239 switch (dimension) 240 { 241 case TEST_DIMENSION_MIN_IMAGE_COUNT: 242 { 243 // Estimate how much memory each swapchain image consumes. This isn't perfect, since 244 // swapchain images may have additional constraints that equivalent non-swapchain 245 // images don't have. But it's the best we can do. 246 const vk::DeviceInterface& vkd = context.getDeviceInterface(); 247 vk::VkDevice device = context.getDevice(); 248 vk::VkMemoryRequirements memoryRequirements; 249 { 250 const vk::VkImageCreateInfo imageInfo = 251 { 252 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 253 DE_NULL, 254 vk::VK_IMAGE_CREATE_PROTECTED_BIT, 255 vk::VK_IMAGE_TYPE_2D, 256 baseParameters.imageFormat, 257 { 258 baseParameters.imageExtent.width, 259 baseParameters.imageExtent.height, 260 1, 261 }, 262 1, // mipLevels 263 baseParameters.imageArrayLayers, 264 vk::VK_SAMPLE_COUNT_1_BIT, 265 vk::VK_IMAGE_TILING_OPTIMAL, 266 baseParameters.imageUsage, 267 baseParameters.imageSharingMode, 268 baseParameters.queueFamilyIndexCount, 269 baseParameters.pQueueFamilyIndices, 270 vk::VK_IMAGE_LAYOUT_UNDEFINED 271 }; 272 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo); 273 274 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image); 275 } 276 277 // Determine the maximum memory heap space available for protected images 278 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice()); 279 vk::VkDeviceSize protectedHeapSize = 0; 280 deUint32 protectedHeapMask = 0; 281 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++) 282 { 283 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex; 284 if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 && 285 (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 && 286 (protectedHeapMask & (1u << heapIndex)) == 0) 287 { 288 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size); 289 protectedHeapMask |= 1u << heapIndex; 290 } 291 } 292 293 // If the implementation doesn't have a max image count, min+16 means we won't clamp. 294 // Limit it to how many protected images we estimate can be allocated, with one image 295 // worth of slack for alignment, swapchain-specific constraints, etc. 296 const deUint32 maxImageCount = de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u, 297 deUint32(protectedHeapSize / memoryRequirements.size) - 1); 298 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, maxImageCount); 299 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount) 300 { 301 cases.push_back(baseParameters); 302 cases.back().minImageCount = imageCount; 303 } 304 305 break; 306 } 307 308 case TEST_DIMENSION_IMAGE_FORMAT: 309 { 310 for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt) 311 { 312 cases.push_back(baseParameters); 313 cases.back().imageFormat = curFmt->format; 314 cases.back().imageColorSpace = curFmt->colorSpace; 315 } 316 317 break; 318 } 319 320 case TEST_DIMENSION_IMAGE_EXTENT: 321 { 322 static const vk::VkExtent2D s_testSizes[] = 323 { 324 { 1, 1 }, 325 { 16, 32 }, 326 { 32, 16 }, 327 { 632, 231 }, 328 { 117, 998 }, 329 }; 330 331 if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE || 332 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE) 333 { 334 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx) 335 { 336 cases.push_back(baseParameters); 337 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); 338 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); 339 } 340 } 341 342 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE) 343 { 344 cases.push_back(baseParameters); 345 cases.back().imageExtent = capabilities.currentExtent; 346 } 347 348 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE) 349 { 350 cases.push_back(baseParameters); 351 cases.back().imageExtent = capabilities.minImageExtent; 352 353 cases.push_back(baseParameters); 354 cases.back().imageExtent = capabilities.maxImageExtent; 355 } 356 357 break; 358 } 359 360 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS: 361 { 362 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u); 363 364 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers) 365 { 366 cases.push_back(baseParameters); 367 cases.back().imageArrayLayers = numLayers; 368 } 369 370 break; 371 } 372 373 case TEST_DIMENSION_IMAGE_USAGE: 374 { 375 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags) 376 { 377 if ((flags & ~capabilities.supportedUsageFlags) == 0) 378 { 379 cases.push_back(baseParameters); 380 cases.back().imageUsage = flags; 381 } 382 } 383 384 break; 385 } 386 387 case TEST_DIMENSION_IMAGE_SHARING_MODE: 388 { 389 cases.push_back(baseParameters); 390 cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE; 391 392 cases.push_back(baseParameters); 393 cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT; 394 395 break; 396 } 397 398 case TEST_DIMENSION_PRE_TRANSFORM: 399 { 400 for (deUint32 transform = 1u; 401 transform <= capabilities.supportedTransforms; 402 transform = transform<<1u) 403 { 404 if ((transform & capabilities.supportedTransforms) != 0) 405 { 406 cases.push_back(baseParameters); 407 cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform; 408 } 409 } 410 411 break; 412 } 413 414 case TEST_DIMENSION_COMPOSITE_ALPHA: 415 { 416 for (deUint32 alphaMode = 1u; 417 alphaMode <= capabilities.supportedCompositeAlpha; 418 alphaMode = alphaMode<<1u) 419 { 420 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0) 421 { 422 cases.push_back(baseParameters); 423 cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode; 424 } 425 } 426 427 break; 428 } 429 430 case TEST_DIMENSION_PRESENT_MODE: 431 { 432 for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode) 433 { 434 cases.push_back(baseParameters); 435 cases.back().presentMode = *curMode; 436 } 437 438 break; 439 } 440 441 case TEST_DIMENSION_CLIPPED: 442 { 443 cases.push_back(baseParameters); 444 cases.back().clipped = VK_FALSE; 445 446 cases.push_back(baseParameters); 447 cases.back().clipped = VK_TRUE; 448 449 break; 450 } 451 452 default: 453 DE_FATAL("Impossible"); 454 } 455 456 DE_ASSERT(!cases.empty()); 457 return cases; 458 } 459 460 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType, 461 TestDimension dimension, 462 const ProtectedContext& context, 463 vk::VkSurfaceKHR surface) 464 { 465 const vk::InstanceInterface& vki = context.getInstanceDriver(); 466 vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); 467 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki, 468 physicalDevice, 469 surface); 470 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki, 471 physicalDevice, 472 surface); 473 const std::vector<vk::VkPresentModeKHR> presentModes = vk::wsi::getPhysicalDeviceSurfacePresentModes(vki, 474 physicalDevice, 475 surface); 476 477 return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes); 478 } 479 480 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params) 481 { 482 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL)); 483 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, params.wsiType); 484 std::vector<std::string> devExts; 485 devExts.push_back("VK_KHR_swapchain"); 486 487 const NativeObjects native (baseCtx, supportedExtensions, params.wsiType); 488 ProtectedContext context (baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts); 489 vk::VkSurfaceKHR surface = context.getSurface(); 490 const std::vector<vk::VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, 491 params.dimension, 492 context, 493 surface)); 494 deUint32 queueIdx = context.getQueueFamilyIndex(); 495 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx) 496 { 497 vk::VkSwapchainCreateInfoKHR curParams = cases[caseNdx]; 498 499 curParams.surface = surface; 500 curParams.queueFamilyIndexCount = 1u; 501 curParams.pQueueFamilyIndices = &queueIdx; 502 503 context.getTestContext().getLog() 504 << tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage; 505 506 { 507 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams)); 508 } 509 } 510 511 return tcu::TestStatus::pass("Creating swapchain succeeded"); 512 } 513 514 struct GroupParameters 515 { 516 typedef FunctionInstance1<TestParameters>::Function Function; 517 518 vk::wsi::Type wsiType; 519 Function function; 520 521 GroupParameters (vk::wsi::Type wsiType_, Function function_) 522 : wsiType (wsiType_) 523 , function (function_) 524 {} 525 526 GroupParameters (void) 527 : wsiType (vk::wsi::TYPE_LAST) 528 , function ((Function)DE_NULL) 529 {} 530 }; 531 532 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params) 533 { 534 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx) 535 { 536 const TestDimension testDimension = (TestDimension)dimensionNdx; 537 538 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension)); 539 } 540 } 541 542 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type wsiType, 543 const vk::InstanceInterface& vki, 544 vk::VkPhysicalDevice physicalDevice, 545 vk::VkSurfaceKHR surface, 546 const tcu::UVec2& desiredSize, 547 deUint32 desiredImageCount) 548 { 549 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki, 550 physicalDevice, 551 surface); 552 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki, 553 physicalDevice, 554 surface); 555 const vk::wsi::PlatformProperties& platformProperties = vk::wsi::getPlatformProperties(wsiType); 556 const vk::VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) 557 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform; 558 const vk::VkSwapchainCreateInfoKHR parameters = 559 { 560 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 561 DE_NULL, 562 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR, 563 surface, 564 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount), 565 formats[0].format, 566 formats[0].colorSpace, 567 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE 568 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())), 569 1u, // imageArrayLayers 570 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 571 vk::VK_SHARING_MODE_EXCLUSIVE, 572 0u, 573 (const deUint32*)DE_NULL, 574 transform, 575 vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 576 vk::VK_PRESENT_MODE_FIFO_KHR, 577 VK_FALSE, // clipped 578 (vk::VkSwapchainKHR)0 // oldSwapchain 579 }; 580 581 return parameters; 582 } 583 584 typedef de::SharedPtr<vk::Unique<vk::VkImageView> > ImageViewSp; 585 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> > FramebufferSp; 586 587 class TriangleRenderer 588 { 589 public: 590 TriangleRenderer (ProtectedContext& context, 591 const vk::BinaryCollection& binaryRegistry, 592 const std::vector<vk::VkImage> swapchainImages, 593 const vk::VkFormat framebufferFormat, 594 const tcu::UVec2& renderSize); 595 ~TriangleRenderer (void); 596 597 void recordFrame (vk::VkCommandBuffer cmdBuffer, 598 deUint32 imageNdx, 599 deUint32 frameNdx) const; 600 601 static void getPrograms (vk::SourceCollections& dst); 602 603 private: 604 static vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd, 605 const vk::VkDevice device, 606 const vk::VkFormat colorAttachmentFormat); 607 static vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface& vkd, 608 vk::VkDevice device); 609 static vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd, 610 const vk::VkDevice device, 611 const vk::VkRenderPass renderPass, 612 const vk::VkPipelineLayout pipelineLayout, 613 const vk::BinaryCollection& binaryCollection, 614 const tcu::UVec2& renderSize); 615 616 const vk::DeviceInterface& m_vkd; 617 618 const std::vector<vk::VkImage> m_swapchainImages; 619 const tcu::UVec2 m_renderSize; 620 621 const vk::Unique<vk::VkRenderPass> m_renderPass; 622 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout; 623 const vk::Unique<vk::VkPipeline> m_pipeline; 624 625 const de::UniquePtr<vk::BufferWithMemory> m_vertexBuffer; 626 627 std::vector<ImageViewSp> m_attachmentViews; 628 std::vector<FramebufferSp> m_framebuffers; 629 }; 630 631 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface& vkd, 632 const vk::VkDevice device, 633 const vk::VkFormat colorAttachmentFormat) 634 { 635 const vk::VkAttachmentDescription colorAttDesc = 636 { 637 (vk::VkAttachmentDescriptionFlags)0, 638 colorAttachmentFormat, 639 vk::VK_SAMPLE_COUNT_1_BIT, 640 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, 641 vk::VK_ATTACHMENT_STORE_OP_STORE, 642 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, 643 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, 644 vk::VK_IMAGE_LAYOUT_UNDEFINED, 645 vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 646 }; 647 const vk::VkAttachmentReference colorAttRef = 648 { 649 0u, 650 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 651 }; 652 const vk::VkSubpassDescription subpassDesc = 653 { 654 (vk::VkSubpassDescriptionFlags)0u, 655 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 656 0u, // inputAttachmentCount 657 DE_NULL, // pInputAttachments 658 1u, // colorAttachmentCount 659 &colorAttRef, // pColorAttachments 660 DE_NULL, // pResolveAttachments 661 DE_NULL, // depthStencilAttachment 662 0u, // preserveAttachmentCount 663 DE_NULL, // pPreserveAttachments 664 }; 665 const vk::VkSubpassDependency dependencies[] = 666 { 667 { 668 VK_SUBPASS_EXTERNAL, // srcSubpass 669 0u, // dstSubpass 670 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 671 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 672 vk::VK_ACCESS_MEMORY_READ_BIT, 673 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT| 674 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), 675 vk::VK_DEPENDENCY_BY_REGION_BIT 676 }, 677 { 678 0u, // srcSubpass 679 VK_SUBPASS_EXTERNAL, // dstSubpass 680 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 681 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 682 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT| 683 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), 684 vk::VK_ACCESS_MEMORY_READ_BIT, 685 vk::VK_DEPENDENCY_BY_REGION_BIT 686 }, 687 }; 688 const vk::VkRenderPassCreateInfo renderPassParams = 689 { 690 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 691 DE_NULL, 692 (vk::VkRenderPassCreateFlags)0, 693 1u, 694 &colorAttDesc, 695 1u, 696 &subpassDesc, 697 DE_LENGTH_OF_ARRAY(dependencies), 698 dependencies, 699 }; 700 701 return vk::createRenderPass(vkd, device, &renderPassParams); 702 } 703 704 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface& vkd, 705 const vk::VkDevice device) 706 { 707 const vk::VkPushConstantRange pushConstantRange = 708 { 709 vk::VK_SHADER_STAGE_VERTEX_BIT, 710 0u, // offset 711 (deUint32)sizeof(deUint32), // size 712 }; 713 const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams = 714 { 715 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 716 DE_NULL, 717 (vk::VkPipelineLayoutCreateFlags)0, 718 0u, // setLayoutCount 719 DE_NULL, // pSetLayouts 720 1u, 721 &pushConstantRange, 722 }; 723 724 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams); 725 } 726 727 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface& vkd, 728 const vk::VkDevice device, 729 const vk::VkRenderPass renderPass, 730 const vk::VkPipelineLayout pipelineLayout, 731 const vk::BinaryCollection& binaryCollection, 732 const tcu::UVec2& renderSize) 733 { 734 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines() 735 // and can be deleted immediately following that call. 736 const vk::Unique<vk::VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0)); 737 const vk::Unique<vk::VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0)); 738 739 const vk::VkPipelineShaderStageCreateInfo shaderStageParams[] = 740 { 741 { 742 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 743 DE_NULL, 744 (vk::VkPipelineShaderStageCreateFlags)0, 745 vk::VK_SHADER_STAGE_VERTEX_BIT, 746 *vertShaderModule, 747 "main", 748 DE_NULL 749 }, 750 { 751 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 752 DE_NULL, 753 (vk::VkPipelineShaderStageCreateFlags)0, 754 vk::VK_SHADER_STAGE_FRAGMENT_BIT, 755 *fragShaderModule, 756 "main", 757 DE_NULL 758 } 759 }; 760 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilParams = 761 { 762 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 763 DE_NULL, 764 (vk::VkPipelineDepthStencilStateCreateFlags)0, 765 DE_FALSE, // depthTestEnable 766 DE_FALSE, // depthWriteEnable 767 vk::VK_COMPARE_OP_ALWAYS, // depthCompareOp 768 DE_FALSE, // depthBoundsTestEnable 769 DE_FALSE, // stencilTestEnable 770 { 771 vk::VK_STENCIL_OP_KEEP, // failOp 772 vk::VK_STENCIL_OP_KEEP, // passOp 773 vk::VK_STENCIL_OP_KEEP, // depthFailOp 774 vk::VK_COMPARE_OP_ALWAYS, // compareOp 775 0u, // compareMask 776 0u, // writeMask 777 0u, // reference 778 }, // front 779 { 780 vk::VK_STENCIL_OP_KEEP, // failOp 781 vk::VK_STENCIL_OP_KEEP, // passOp 782 vk::VK_STENCIL_OP_KEEP, // depthFailOp 783 vk::VK_COMPARE_OP_ALWAYS, // compareOp 784 0u, // compareMask 785 0u, // writeMask 786 0u, // reference 787 }, // back 788 -1.0f, // minDepthBounds 789 +1.0f, // maxDepthBounds 790 }; 791 const vk::VkViewport viewport0 = 792 { 793 0.0f, // x 794 0.0f, // y 795 (float)renderSize.x(), // width 796 (float)renderSize.y(), // height 797 0.0f, // minDepth 798 1.0f, // maxDepth 799 }; 800 const vk::VkRect2D scissor0 = 801 { 802 { 0u, 0u, }, // offset 803 { renderSize.x(), renderSize.y() }, // extent 804 }; 805 const vk::VkPipelineViewportStateCreateInfo viewportParams = 806 { 807 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 808 DE_NULL, 809 (vk::VkPipelineViewportStateCreateFlags)0, 810 1u, 811 &viewport0, 812 1u, 813 &scissor0 814 }; 815 const vk::VkPipelineMultisampleStateCreateInfo multisampleParams = 816 { 817 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 818 DE_NULL, 819 (vk::VkPipelineMultisampleStateCreateFlags)0, 820 vk::VK_SAMPLE_COUNT_1_BIT, // rasterizationSamples 821 VK_FALSE, // sampleShadingEnable 822 0.0f, // minSampleShading 823 (const vk::VkSampleMask*)DE_NULL, // sampleMask 824 VK_FALSE, // alphaToCoverageEnable 825 VK_FALSE, // alphaToOneEnable 826 }; 827 const vk::VkPipelineRasterizationStateCreateInfo rasterParams = 828 { 829 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 830 DE_NULL, 831 (vk::VkPipelineRasterizationStateCreateFlags)0, 832 VK_FALSE, // depthClampEnable 833 VK_FALSE, // rasterizerDiscardEnable 834 vk::VK_POLYGON_MODE_FILL, // polygonMode 835 vk::VK_CULL_MODE_NONE, // cullMode 836 vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace 837 VK_FALSE, // depthBiasEnable 838 0.0f, // depthBiasConstantFactor 839 0.0f, // depthBiasClamp 840 0.0f, // depthBiasSlopeFactor 841 1.0f, // lineWidth 842 }; 843 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyParams = 844 { 845 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 846 DE_NULL, 847 (vk::VkPipelineInputAssemblyStateCreateFlags)0, 848 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 849 DE_FALSE, // primitiveRestartEnable 850 }; 851 const vk::VkVertexInputBindingDescription vertexBinding0 = 852 { 853 0u, // binding 854 (deUint32)sizeof(tcu::Vec4), // stride 855 vk::VK_VERTEX_INPUT_RATE_VERTEX, // inputRate 856 }; 857 const vk::VkVertexInputAttributeDescription vertexAttrib0 = 858 { 859 0u, // location 860 0u, // binding 861 vk::VK_FORMAT_R32G32B32A32_SFLOAT, // format 862 0u, // offset 863 }; 864 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateParams = 865 { 866 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 867 DE_NULL, 868 (vk::VkPipelineVertexInputStateCreateFlags)0, 869 1u, 870 &vertexBinding0, 871 1u, 872 &vertexAttrib0, 873 }; 874 const vk::VkPipelineColorBlendAttachmentState attBlendParams0 = 875 { 876 VK_FALSE, // blendEnable 877 vk::VK_BLEND_FACTOR_ONE, // srcColorBlendFactor 878 vk::VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor 879 vk::VK_BLEND_OP_ADD, // colorBlendOp 880 vk::VK_BLEND_FACTOR_ONE, // srcAlphaBlendFactor 881 vk::VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor 882 vk::VK_BLEND_OP_ADD, // alphaBlendOp 883 (vk::VK_COLOR_COMPONENT_R_BIT| 884 vk::VK_COLOR_COMPONENT_G_BIT| 885 vk::VK_COLOR_COMPONENT_B_BIT| 886 vk::VK_COLOR_COMPONENT_A_BIT), // colorWriteMask 887 }; 888 const vk::VkPipelineColorBlendStateCreateInfo blendParams = 889 { 890 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 891 DE_NULL, 892 (vk::VkPipelineColorBlendStateCreateFlags)0, 893 VK_FALSE, // logicOpEnable 894 vk::VK_LOGIC_OP_COPY, 895 1u, 896 &attBlendParams0, 897 { 0.0f, 0.0f, 0.0f, 0.0f }, // blendConstants[4] 898 }; 899 const vk::VkGraphicsPipelineCreateInfo pipelineParams = 900 { 901 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 902 DE_NULL, 903 (vk::VkPipelineCreateFlags)0, 904 (deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams), 905 shaderStageParams, 906 &vertexInputStateParams, 907 &inputAssemblyParams, 908 (const vk::VkPipelineTessellationStateCreateInfo*)DE_NULL, 909 &viewportParams, 910 &rasterParams, 911 &multisampleParams, 912 &depthStencilParams, 913 &blendParams, 914 (const vk::VkPipelineDynamicStateCreateInfo*)DE_NULL, 915 pipelineLayout, 916 renderPass, 917 0u, // subpass 918 DE_NULL, // basePipelineHandle 919 0u, // basePipelineIndex 920 }; 921 922 return vk::createGraphicsPipeline(vkd, device, (vk::VkPipelineCache)0, &pipelineParams); 923 } 924 925 TriangleRenderer::TriangleRenderer (ProtectedContext& context, 926 const vk::BinaryCollection& binaryRegistry, 927 const std::vector<vk::VkImage> swapchainImages, 928 const vk::VkFormat framebufferFormat, 929 const tcu::UVec2& renderSize) 930 : m_vkd (context.getDeviceInterface()) 931 , m_swapchainImages (swapchainImages) 932 , m_renderSize (renderSize) 933 , m_renderPass (createRenderPass(m_vkd, context.getDevice(), framebufferFormat)) 934 , m_pipelineLayout (createPipelineLayout(m_vkd, context.getDevice())) 935 , m_pipeline (createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize)) 936 , m_vertexBuffer (makeBuffer(context, 937 PROTECTION_DISABLED, 938 context.getQueueFamilyIndex(), 939 (deUint32)(sizeof(float)*4*3), 940 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 941 vk::MemoryRequirement::HostVisible)) 942 { 943 m_attachmentViews.resize(swapchainImages.size()); 944 m_framebuffers.resize(swapchainImages.size()); 945 946 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx) 947 { 948 m_attachmentViews[imageNdx] = ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat))); 949 m_framebuffers[imageNdx] = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context, 950 renderSize.x(), 951 renderSize.y(), 952 *m_renderPass, 953 **m_attachmentViews[imageNdx]))); 954 } 955 956 // Upload vertex data 957 { 958 const tcu::Vec4 vertices[] = 959 { 960 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), 961 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f), 962 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f) 963 }; 964 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3); 965 966 deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices)); 967 vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices)); 968 } 969 } 970 971 TriangleRenderer::~TriangleRenderer (void) 972 { 973 } 974 975 void TriangleRenderer::recordFrame (vk::VkCommandBuffer cmdBuffer, 976 deUint32 imageNdx, 977 deUint32 frameNdx) const 978 { 979 const vk::VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx]; 980 981 beginCommandBuffer(m_vkd, cmdBuffer); 982 983 { 984 const vk::VkClearValue clearValue = vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f); 985 const vk::VkRenderPassBeginInfo passBeginParams = 986 { 987 vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 988 DE_NULL, 989 *m_renderPass, 990 curFramebuffer, 991 { 992 { 0, 0 }, 993 { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() } 994 }, // renderArea 995 1u, // clearValueCount 996 &clearValue, // pClearValues 997 }; 998 m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, vk::VK_SUBPASS_CONTENTS_INLINE); 999 } 1000 1001 m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 1002 1003 { 1004 const vk::VkDeviceSize bindingOffset = 0; 1005 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset); 1006 } 1007 1008 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx); 1009 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u); 1010 m_vkd.cmdEndRenderPass(cmdBuffer); 1011 1012 VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer)); 1013 } 1014 1015 void TriangleRenderer::getPrograms (vk::SourceCollections& dst) 1016 { 1017 dst.glslSources.add("tri-vert") << glu::VertexSource( 1018 "#version 310 es\n" 1019 "layout(location = 0) in highp vec4 a_position;\n" 1020 "layout(push_constant) uniform FrameData\n" 1021 "{\n" 1022 " highp uint frameNdx;\n" 1023 "} frameData;\n" 1024 "void main (void)\n" 1025 "{\n" 1026 " highp float angle = float(frameData.frameNdx) / 100.0;\n" 1027 " highp float c = cos(angle);\n" 1028 " highp float s = sin(angle);\n" 1029 " highp mat4 t = mat4( c, -s, 0, 0,\n" 1030 " s, c, 0, 0,\n" 1031 " 0, 0, 1, 0,\n" 1032 " 0, 0, 0, 1);\n" 1033 " gl_Position = t * a_position;\n" 1034 "}\n"); 1035 dst.glslSources.add("tri-frag") << glu::FragmentSource( 1036 "#version 310 es\n" 1037 "layout(location = 0) out lowp vec4 o_color;\n" 1038 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n"); 1039 } 1040 1041 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> > CommandBufferSp; 1042 typedef de::SharedPtr<vk::Unique<vk::VkFence> > FenceSp; 1043 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> > SemaphoreSp; 1044 1045 std::vector<FenceSp> createFences (const vk::DeviceInterface& vkd, 1046 const vk::VkDevice device, 1047 size_t numFences) 1048 { 1049 std::vector<FenceSp> fences(numFences); 1050 1051 for (size_t ndx = 0; ndx < numFences; ++ndx) 1052 fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device))); 1053 1054 return fences; 1055 } 1056 1057 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface& vkd, 1058 const vk::VkDevice device, 1059 size_t numSemaphores) 1060 { 1061 std::vector<SemaphoreSp> semaphores(numSemaphores); 1062 1063 for (size_t ndx = 0; ndx < numSemaphores; ++ndx) 1064 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device))); 1065 1066 return semaphores; 1067 } 1068 1069 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface& vkd, 1070 const vk::VkDevice device, 1071 const vk::VkCommandPool commandPool, 1072 const vk::VkCommandBufferLevel level, 1073 const size_t numCommandBuffers) 1074 { 1075 std::vector<CommandBufferSp> buffers (numCommandBuffers); 1076 1077 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx) 1078 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level))); 1079 1080 return buffers; 1081 } 1082 1083 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType) 1084 { 1085 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL)); 1086 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, wsiType); 1087 std::vector<std::string> devExts; 1088 devExts.push_back("VK_KHR_swapchain"); 1089 1090 const tcu::UVec2 desiredSize (256, 256); 1091 const NativeObjects native (baseCtx, supportedExtensions, wsiType, tcu::just(desiredSize)); 1092 ProtectedContext context (baseCtx, wsiType, *native.display, *native.window, instExts, devExts); 1093 vk::VkSurfaceKHR surface = context.getSurface(); 1094 const vk::DeviceInterface& vkd = context.getDeviceInterface(); 1095 const vk::VkDevice device = context.getDevice(); 1096 const vk::VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, 1097 context.getInstanceDriver(), 1098 context.getPhysicalDevice(), 1099 surface, 1100 desiredSize, 1101 2); 1102 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo)); 1103 const std::vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain); 1104 1105 const TriangleRenderer renderer (context, 1106 context.getBinaryCollection(), 1107 swapchainImages, 1108 swapchainInfo.imageFormat, 1109 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height)); 1110 1111 const vk::Unique<vk::VkCommandPool> commandPool (makeCommandPool(vkd, device, PROTECTION_ENABLED, 1112 context.getQueueFamilyIndex())); 1113 1114 const size_t maxQueuedFrames = swapchainImages.size()*2; 1115 1116 // We need to keep hold of fences from vkAcquireNextImageKHR to actually 1117 // limit number of frames we allow to be queued. 1118 const std::vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames)); 1119 1120 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass 1121 // the semaphore in same time as the fence we use to meter rendering. 1122 const std::vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1)); 1123 1124 // For rest we simply need maxQueuedFrames as we will wait for image 1125 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that 1126 // previous uses must have completed. 1127 const std::vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames)); 1128 const std::vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, 1129 device, 1130 *commandPool, 1131 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1132 maxQueuedFrames)); 1133 1134 try 1135 { 1136 const deUint32 numFramesToRender = 60*10; 1137 1138 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx) 1139 { 1140 const vk::VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()]; 1141 const vk::VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()]; 1142 deUint32 imageNdx = ~0u; 1143 1144 if (frameNdx >= maxQueuedFrames) 1145 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max())); 1146 1147 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence)); 1148 1149 { 1150 const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device, 1151 *swapchain, 1152 std::numeric_limits<deUint64>::max(), 1153 imageReadySemaphore, 1154 imageReadyFence, 1155 &imageNdx); 1156 1157 if (acquireResult == vk::VK_SUBOPTIMAL_KHR) 1158 context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage; 1159 else 1160 VK_CHECK(acquireResult); 1161 } 1162 1163 TCU_CHECK((size_t)imageNdx < swapchainImages.size()); 1164 1165 { 1166 const vk::VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()]; 1167 const vk::VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()]; 1168 const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 1169 vk::VkSubmitInfo submitInfo = 1170 { 1171 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, 1172 DE_NULL, 1173 1u, 1174 &imageReadySemaphore, 1175 &waitDstStage, 1176 1u, 1177 &commandBuffer, 1178 1u, 1179 &renderingCompleteSemaphore 1180 }; 1181 1182 const vk::VkProtectedSubmitInfo protectedInfo = 1183 { 1184 vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, // sType 1185 DE_NULL, // pNext 1186 VK_TRUE, // protectedSubmit 1187 }; 1188 submitInfo.pNext = &protectedInfo; 1189 1190 const vk::VkPresentInfoKHR presentInfo = 1191 { 1192 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 1193 DE_NULL, 1194 1u, 1195 &renderingCompleteSemaphore, 1196 1u, 1197 &*swapchain, 1198 &imageNdx, 1199 (vk::VkResult*)DE_NULL 1200 }; 1201 1202 renderer.recordFrame(commandBuffer, imageNdx, frameNdx); 1203 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, (vk::VkFence)0)); 1204 VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo)); 1205 } 1206 } 1207 1208 VK_CHECK(vkd.deviceWaitIdle(device)); 1209 } 1210 catch (...) 1211 { 1212 // Make sure device is idle before destroying resources 1213 vkd.deviceWaitIdle(device); 1214 throw; 1215 } 1216 1217 return tcu::TestStatus::pass("Rendering tests succeeded"); 1218 } 1219 1220 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type) 1221 { 1222 TriangleRenderer::getPrograms(dst); 1223 } 1224 1225 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType) 1226 { 1227 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType); 1228 } 1229 1230 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType) 1231 { 1232 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest)); 1233 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType); 1234 } 1235 1236 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType) 1237 { 1238 addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType); 1239 } 1240 1241 } // anonymous 1242 1243 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx) 1244 { 1245 de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests")); 1246 1247 for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx) 1248 { 1249 const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx; 1250 1251 addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType); 1252 } 1253 1254 return wsiTestGroup.release(); 1255 } 1256 1257 } // wsi 1258 } // vkt 1259