1 /*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 Google Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Tests for shared presentable image extension 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktWsiSharedPresentableImageTests.hpp" 25 26 #include "vktTestCaseUtil.hpp" 27 #include "vktTestGroupUtil.hpp" 28 #include "vkRefUtil.hpp" 29 #include "vkWsiPlatform.hpp" 30 #include "vkWsiUtil.hpp" 31 #include "vkQueryUtil.hpp" 32 #include "vkDeviceUtil.hpp" 33 #include "vkPlatform.hpp" 34 #include "vkTypeUtil.hpp" 35 #include "vkPrograms.hpp" 36 37 #include "vkWsiUtil.hpp" 38 39 #include "tcuPlatform.hpp" 40 #include "tcuResultCollector.hpp" 41 #include "tcuTestLog.hpp" 42 43 #include <vector> 44 #include <string> 45 46 using std::vector; 47 using std::string; 48 49 using tcu::Maybe; 50 using tcu::UVec2; 51 using tcu::TestLog; 52 53 namespace vkt 54 { 55 namespace wsi 56 { 57 namespace 58 { 59 enum Scaling 60 { 61 SCALING_NONE, 62 SCALING_UP, 63 SCALING_DOWN 64 }; 65 66 typedef vector<vk::VkExtensionProperties> Extensions; 67 68 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions) 69 { 70 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin(); 71 requiredExtName != requiredExtensions.end(); 72 ++requiredExtName) 73 { 74 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName))) 75 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str()); 76 } 77 } 78 79 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface& vkp, 80 deUint32 version, 81 const Extensions& supportedExtensions, 82 vk::wsi::Type wsiType) 83 { 84 vector<string> extensions; 85 86 if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2")) 87 extensions.push_back("VK_KHR_get_physical_device_properties2"); 88 89 extensions.push_back("VK_KHR_surface"); 90 extensions.push_back("VK_KHR_get_surface_capabilities2"); 91 // Required for device extension to expose new physical device bits (in this 92 // case, presentation mode enums) 93 extensions.push_back(getExtensionName(wsiType)); 94 95 checkAllSupported(supportedExtensions, extensions); 96 97 return vk::createDefaultInstance(vkp, version, vector<string>(), extensions); 98 } 99 100 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void) 101 { 102 vk::VkPhysicalDeviceFeatures features; 103 deMemset(&features, 0, sizeof(features)); 104 return features; 105 } 106 107 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice) 108 { 109 deUint32 numFamilies = 0; 110 111 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL); 112 113 return numFamilies; 114 } 115 116 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface) 117 { 118 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice); 119 vector<deUint32> supportedFamilyIndices; 120 121 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx) 122 { 123 if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE) 124 supportedFamilyIndices.push_back(queueFamilyNdx); 125 } 126 127 return supportedFamilyIndices; 128 } 129 130 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface) 131 { 132 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface); 133 134 if (supportedFamilyIndices.empty()) 135 TCU_THROW(NotSupportedError, "Device doesn't support presentation"); 136 137 return supportedFamilyIndices[0]; 138 } 139 140 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::InstanceInterface& vki, 141 vk::VkPhysicalDevice physicalDevice, 142 const Extensions& supportedExtensions, 143 const deUint32 queueFamilyIndex, 144 bool requiresSharedPresentableImage, 145 const vk::VkAllocationCallbacks* pAllocator = DE_NULL) 146 { 147 const float queuePriorities[] = { 1.0f }; 148 const vk::VkDeviceQueueCreateInfo queueInfos[] = 149 { 150 { 151 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 152 DE_NULL, 153 (vk::VkDeviceQueueCreateFlags)0, 154 queueFamilyIndex, 155 DE_LENGTH_OF_ARRAY(queuePriorities), 156 &queuePriorities[0] 157 } 158 }; 159 const vk::VkPhysicalDeviceFeatures features = getDeviceNullFeatures(); 160 const char* const extensions[] = 161 { 162 "VK_KHR_swapchain", 163 "VK_KHR_shared_presentable_image" 164 }; 165 166 const vk::VkDeviceCreateInfo deviceParams = 167 { 168 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 169 DE_NULL, 170 (vk::VkDeviceCreateFlags)0, 171 DE_LENGTH_OF_ARRAY(queueInfos), 172 &queueInfos[0], 173 0u, 174 DE_NULL, 175 requiresSharedPresentableImage ? 2u : 1u, 176 DE_ARRAY_BEGIN(extensions), 177 &features 178 }; 179 180 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx) 181 { 182 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx]))) 183 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str()); 184 } 185 186 return createDevice(vki, physicalDevice, &deviceParams, pAllocator); 187 } 188 189 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform, 190 const Extensions& supportedExtensions, 191 vk::wsi::Type wsiType) 192 { 193 try 194 { 195 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType)); 196 } 197 catch (const tcu::NotSupportedError& e) 198 { 199 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType)))) 200 { 201 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation 202 // must support creating native display & window for that WSI type. 203 throw tcu::TestError(e.getMessage()); 204 } 205 else 206 throw; 207 } 208 } 209 210 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize) 211 { 212 try 213 { 214 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize)); 215 } 216 catch (const tcu::NotSupportedError& e) 217 { 218 // See createDisplay - assuming that wsi::Display was supported platform port 219 // should also support creating a window. 220 throw tcu::TestError(e.getMessage()); 221 } 222 } 223 224 bool wsiTypeSupportsScaling (vk::wsi::Type wsiType) 225 { 226 return vk::wsi::getPlatformProperties(wsiType).swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE; 227 } 228 229 void initSemaphores (const vk::DeviceInterface& vkd, 230 vk::VkDevice device, 231 std::vector<vk::VkSemaphore>& semaphores) 232 { 233 for (size_t ndx = 0; ndx < semaphores.size(); ndx++) 234 semaphores[ndx] = createSemaphore(vkd, device).disown(); 235 } 236 237 void deinitSemaphores (const vk::DeviceInterface& vkd, 238 vk::VkDevice device, 239 std::vector<vk::VkSemaphore>& semaphores) 240 { 241 for (size_t ndx = 0; ndx < semaphores.size(); ndx++) 242 { 243 if (semaphores[ndx] != (vk::VkSemaphore)0) 244 vkd.destroySemaphore(device, semaphores[ndx], DE_NULL); 245 246 semaphores[ndx] = (vk::VkSemaphore)0; 247 } 248 249 semaphores.clear(); 250 } 251 252 void initFences (const vk::DeviceInterface& vkd, 253 vk::VkDevice device, 254 std::vector<vk::VkFence>& fences) 255 { 256 for (size_t ndx = 0; ndx < fences.size(); ndx++) 257 fences[ndx] = createFence(vkd, device).disown(); 258 } 259 260 void deinitFences (const vk::DeviceInterface& vkd, 261 vk::VkDevice device, 262 std::vector<vk::VkFence>& fences) 263 { 264 for (size_t ndx = 0; ndx < fences.size(); ndx++) 265 { 266 if (fences[ndx] != (vk::VkFence)0) 267 vkd.destroyFence(device, fences[ndx], DE_NULL); 268 269 fences[ndx] = (vk::VkFence)0; 270 } 271 272 fences.clear(); 273 } 274 275 void cmdRenderFrame (const vk::DeviceInterface& vkd, 276 vk::VkCommandBuffer commandBuffer, 277 vk::VkPipelineLayout pipelineLayout, 278 vk::VkPipeline pipeline, 279 size_t frameNdx, 280 deUint32 quadCount) 281 { 282 const deUint32 frameNdxValue = (deUint32)frameNdx; 283 284 vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue); 285 vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); 286 vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u); 287 } 288 289 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface& vkd, 290 vk::VkDevice device, 291 vk::VkCommandPool commandPool, 292 vk::VkPipelineLayout pipelineLayout, 293 vk::VkRenderPass renderPass, 294 vk::VkFramebuffer framebuffer, 295 vk::VkPipeline pipeline, 296 size_t frameNdx, 297 deUint32 quadCount, 298 deUint32 imageWidth, 299 deUint32 imageHeight) 300 { 301 const vk::VkCommandBufferAllocateInfo allocateInfo = 302 { 303 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 304 DE_NULL, 305 306 commandPool, 307 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 308 1 309 }; 310 const vk::VkCommandBufferBeginInfo beginInfo = 311 { 312 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 313 DE_NULL, 314 0u, 315 DE_NULL 316 }; 317 318 vk::Move<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(vkd, device, &allocateInfo)); 319 VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo)); 320 321 { 322 const vk::VkClearValue clearValue = vk::makeClearValueColorF32(0.25f, 0.50f, 0.75f, 1.00f); 323 const vk::VkRenderPassBeginInfo renderPassBeginInfo = 324 { 325 vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 326 DE_NULL, 327 328 renderPass, 329 framebuffer, 330 331 { 332 { (deInt32)0, (deInt32)0 }, 333 { imageWidth, imageHeight } 334 }, 335 1u, 336 &clearValue 337 }; 338 vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE); 339 } 340 341 cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount); 342 343 vkd.cmdEndRenderPass(*commandBuffer); 344 345 VK_CHECK(vkd.endCommandBuffer(*commandBuffer)); 346 return commandBuffer; 347 } 348 349 void deinitCommandBuffers (const vk::DeviceInterface& vkd, 350 vk::VkDevice device, 351 vk::VkCommandPool commandPool, 352 std::vector<vk::VkCommandBuffer>& commandBuffers) 353 { 354 for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++) 355 { 356 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0) 357 vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]); 358 359 commandBuffers[ndx] = (vk::VkCommandBuffer)0; 360 } 361 362 commandBuffers.clear(); 363 } 364 365 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vkd, 366 vk::VkDevice device, 367 deUint32 queueFamilyIndex) 368 { 369 const vk::VkCommandPoolCreateInfo createInfo = 370 { 371 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 372 DE_NULL, 373 0u, 374 queueFamilyIndex 375 }; 376 377 return vk::createCommandPool(vkd, device, &createInfo); 378 } 379 380 vk::Move<vk::VkFramebuffer> createFramebuffer (const vk::DeviceInterface& vkd, 381 vk::VkDevice device, 382 vk::VkRenderPass renderPass, 383 vk::VkImageView imageView, 384 deUint32 width, 385 deUint32 height) 386 { 387 const vk::VkFramebufferCreateInfo createInfo = 388 { 389 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 390 DE_NULL, 391 392 0u, 393 renderPass, 394 1u, 395 &imageView, 396 width, 397 height, 398 1u 399 }; 400 401 return vk::createFramebuffer(vkd, device, &createInfo); 402 } 403 404 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd, 405 vk::VkDevice device, 406 vk::VkImage image, 407 vk::VkFormat format) 408 { 409 const vk::VkImageViewCreateInfo createInfo = 410 { 411 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 412 DE_NULL, 413 414 0u, 415 image, 416 vk::VK_IMAGE_VIEW_TYPE_2D, 417 format, 418 vk::makeComponentMappingRGBA(), 419 { 420 vk::VK_IMAGE_ASPECT_COLOR_BIT, 421 0u, 422 1u, 423 0u, 424 1u 425 } 426 }; 427 428 return vk::createImageView(vkd, device, &createInfo, DE_NULL); 429 } 430 431 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd, 432 vk::VkDevice device, 433 vk::VkFormat format) 434 { 435 const vk::VkAttachmentDescription attachments[] = 436 { 437 { 438 0u, 439 format, 440 vk::VK_SAMPLE_COUNT_1_BIT, 441 442 vk::VK_ATTACHMENT_LOAD_OP_LOAD, 443 vk::VK_ATTACHMENT_STORE_OP_STORE, 444 445 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, 446 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, 447 448 // This differs from the usual layout handling in that the 449 // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all 450 // the time. We should not ever transition it away (or discard the 451 // contents with a transition from UNDEFINED) as the PE is accessing 452 // the image concurrently with our rendering. 453 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, 454 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR 455 } 456 }; 457 const vk::VkAttachmentReference colorAttachmentRefs[] = 458 { 459 { 460 0u, 461 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR 462 } 463 }; 464 const vk::VkSubpassDescription subpasses[] = 465 { 466 { 467 0u, 468 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 469 0u, 470 DE_NULL, 471 472 DE_LENGTH_OF_ARRAY(colorAttachmentRefs), 473 colorAttachmentRefs, 474 DE_NULL, 475 476 DE_NULL, 477 0u, 478 DE_NULL 479 } 480 }; 481 482 const vk::VkRenderPassCreateInfo createInfo = 483 { 484 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 485 DE_NULL, 486 0u, 487 488 DE_LENGTH_OF_ARRAY(attachments), 489 attachments, 490 491 DE_LENGTH_OF_ARRAY(subpasses), 492 subpasses, 493 494 0u, 495 DE_NULL 496 }; 497 498 return vk::createRenderPass(vkd, device, &createInfo); 499 } 500 501 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd, 502 vk::VkDevice device, 503 vk::VkRenderPass renderPass, 504 vk::VkPipelineLayout layout, 505 vk::VkShaderModule vertexShaderModule, 506 vk::VkShaderModule fragmentShaderModule, 507 deUint32 width, 508 deUint32 height) 509 { 510 const vk::VkSpecializationInfo shaderSpecialization = 511 { 512 0u, 513 DE_NULL, 514 0, 515 DE_NULL 516 }; 517 const vk::VkPipelineShaderStageCreateInfo stages[] = 518 { 519 { 520 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 521 DE_NULL, 522 0u, 523 vk::VK_SHADER_STAGE_VERTEX_BIT, 524 vertexShaderModule, 525 "main", 526 &shaderSpecialization 527 }, 528 { 529 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 530 DE_NULL, 531 0u, 532 vk::VK_SHADER_STAGE_FRAGMENT_BIT, 533 fragmentShaderModule, 534 "main", 535 &shaderSpecialization 536 } 537 }; 538 const vk::VkPipelineVertexInputStateCreateInfo vertexInputState = 539 { 540 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 541 DE_NULL, 542 0u, 543 0u, 544 DE_NULL, 545 0u, 546 DE_NULL 547 }; 548 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = 549 { 550 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 551 DE_NULL, 552 0u, 553 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 554 VK_FALSE 555 }; 556 const vk::VkViewport viewports[] = 557 { 558 { 559 0.0f, 0.0f, 560 (float)width, (float)height, 561 0.0f, 1.0f 562 } 563 }; 564 const vk::VkRect2D scissors[] = 565 { 566 { 567 { 0u, 0u }, 568 { width, height } 569 } 570 }; 571 const vk::VkPipelineViewportStateCreateInfo viewportState = 572 { 573 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 574 DE_NULL, 575 0u, 576 577 DE_LENGTH_OF_ARRAY(viewports), 578 viewports, 579 DE_LENGTH_OF_ARRAY(scissors), 580 scissors 581 }; 582 const vk::VkPipelineRasterizationStateCreateInfo rasterizationState = 583 { 584 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 585 DE_NULL, 586 0u, 587 VK_TRUE, 588 VK_FALSE, 589 vk::VK_POLYGON_MODE_FILL, 590 vk::VK_CULL_MODE_NONE, 591 vk::VK_FRONT_FACE_CLOCKWISE, 592 VK_FALSE, 593 0.0f, 594 0.0f, 595 0.0f, 596 1.0f 597 }; 598 const vk::VkSampleMask sampleMask = ~0u; 599 const vk::VkPipelineMultisampleStateCreateInfo multisampleState = 600 { 601 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 602 DE_NULL, 603 0u, 604 vk::VK_SAMPLE_COUNT_1_BIT, 605 VK_FALSE, 606 0.0f, 607 &sampleMask, 608 VK_FALSE, 609 VK_FALSE 610 }; 611 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState = 612 { 613 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 614 DE_NULL, 615 0u, 616 DE_FALSE, 617 DE_FALSE, 618 vk::VK_COMPARE_OP_ALWAYS, 619 DE_FALSE, 620 DE_FALSE, 621 { 622 vk::VK_STENCIL_OP_KEEP, 623 vk::VK_STENCIL_OP_KEEP, 624 vk::VK_STENCIL_OP_KEEP, 625 vk::VK_COMPARE_OP_ALWAYS, 626 0u, 627 0u, 628 0u, 629 }, 630 { 631 vk::VK_STENCIL_OP_KEEP, 632 vk::VK_STENCIL_OP_KEEP, 633 vk::VK_STENCIL_OP_KEEP, 634 vk::VK_COMPARE_OP_ALWAYS, 635 0u, 636 0u, 637 0u, 638 }, 639 0.0f, 640 1.0f 641 }; 642 const vk::VkPipelineColorBlendAttachmentState attachmentBlendState = 643 { 644 VK_FALSE, 645 vk::VK_BLEND_FACTOR_ONE, 646 vk::VK_BLEND_FACTOR_ZERO, 647 vk::VK_BLEND_OP_ADD, 648 vk::VK_BLEND_FACTOR_ONE, 649 vk::VK_BLEND_FACTOR_ZERO, 650 vk::VK_BLEND_OP_ADD, 651 (vk::VK_COLOR_COMPONENT_R_BIT| 652 vk::VK_COLOR_COMPONENT_G_BIT| 653 vk::VK_COLOR_COMPONENT_B_BIT| 654 vk::VK_COLOR_COMPONENT_A_BIT), 655 }; 656 const vk::VkPipelineColorBlendStateCreateInfo blendState = 657 { 658 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 659 DE_NULL, 660 0u, 661 DE_FALSE, 662 vk::VK_LOGIC_OP_COPY, 663 1u, 664 &attachmentBlendState, 665 { 0.0f, 0.0f, 0.0f, 0.0f } 666 }; 667 const vk::VkDynamicState dynamicStates[] = 668 { 669 vk::VK_DYNAMIC_STATE_SCISSOR 670 }; 671 const vk::VkPipelineDynamicStateCreateInfo dynamicState = 672 { 673 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 674 DE_NULL, 675 0u, 676 677 DE_LENGTH_OF_ARRAY(dynamicStates), 678 dynamicStates 679 }; 680 const vk::VkGraphicsPipelineCreateInfo createInfo = 681 { 682 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 683 DE_NULL, 684 0u, 685 686 DE_LENGTH_OF_ARRAY(stages), 687 stages, 688 &vertexInputState, 689 &inputAssemblyState, 690 DE_NULL, 691 &viewportState, 692 &rasterizationState, 693 &multisampleState, 694 &depthStencilState, 695 &blendState, 696 &dynamicState, 697 layout, 698 renderPass, 699 0u, 700 DE_NULL, 701 0u 702 }; 703 704 return vk::createGraphicsPipeline(vkd, device, DE_NULL, &createInfo); 705 } 706 707 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vkd, 708 vk::VkDevice device) 709 { 710 const vk::VkPushConstantRange pushConstants[] = 711 { 712 { 713 vk::VK_SHADER_STAGE_FRAGMENT_BIT, 714 0u, 715 4u 716 } 717 }; 718 const vk::VkPipelineLayoutCreateInfo createInfo = 719 { 720 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 721 DE_NULL, 722 0u, 723 724 0u, 725 DE_NULL, 726 727 DE_LENGTH_OF_ARRAY(pushConstants), 728 pushConstants, 729 }; 730 731 return vk::createPipelineLayout(vkd, device, &createInfo); 732 } 733 734 struct TestConfig 735 { 736 vk::wsi::Type wsiType; 737 Scaling scaling; 738 bool useSharedPresentableImage; 739 vk::VkPresentModeKHR presentMode; 740 }; 741 742 class SharedPresentableImageTestInstance : public TestInstance 743 { 744 public: 745 SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig); 746 ~SharedPresentableImageTestInstance (void); 747 748 tcu::TestStatus iterate (void); 749 750 private: 751 const TestConfig m_testConfig; 752 const deUint32 m_quadCount; 753 const vk::PlatformInterface& m_vkp; 754 const Extensions m_instanceExtensions; 755 const vk::Unique<vk::VkInstance> m_instance; 756 const vk::InstanceDriver m_vki; 757 const vk::VkPhysicalDevice m_physicalDevice; 758 const de::UniquePtr<vk::wsi::Display> m_nativeDisplay; 759 const de::UniquePtr<vk::wsi::Window> m_nativeWindow; 760 const vk::Unique<vk::VkSurfaceKHR> m_surface; 761 762 const deUint32 m_queueFamilyIndex; 763 const Extensions m_deviceExtensions; 764 const vk::Unique<vk::VkDevice> m_device; 765 const vk::DeviceDriver m_vkd; 766 const vk::VkQueue m_queue; 767 768 const vk::Unique<vk::VkCommandPool> m_commandPool; 769 const vk::Unique<vk::VkShaderModule> m_vertexShaderModule; 770 const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule; 771 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout; 772 773 vk::VkImageUsageFlags m_supportedUsageFlags; 774 const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties; 775 const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats; 776 const vector<vk::VkPresentModeKHR> m_presentModes; 777 778 tcu::ResultCollector m_resultCollector; 779 780 vk::Move<vk::VkSwapchainKHR> m_swapchain; 781 vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain 782 vk::Move<vk::VkImageView> m_swapchainImageView; 783 vk::Move<vk::VkFramebuffer> m_framebuffer; 784 785 vk::Move<vk::VkRenderPass> m_renderPass; 786 vk::Move<vk::VkPipeline> m_pipeline; 787 788 std::vector<vk::VkCommandBuffer> m_commandBuffers; 789 std::vector<vk::VkSemaphore> m_renderSemaphores; 790 std::vector<vk::VkFence> m_fences; 791 792 std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs; 793 size_t m_swapchainConfigNdx; 794 795 const size_t m_frameCount; 796 size_t m_frameNdx; 797 798 const size_t m_maxOutOfDateCount; 799 size_t m_outOfDateCount; 800 801 void initSwapchainResources (void); 802 void deinitSwapchainResources (void); 803 void render (void); 804 }; 805 806 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs (vk::VkSurfaceKHR surface, 807 deUint32 queueFamilyIndex, 808 Scaling scaling, 809 const vk::VkSurfaceCapabilitiesKHR& properties, 810 const vector<vk::VkSurfaceFormatKHR>& formats, 811 const vector<vk::VkPresentModeKHR>& presentModes, 812 vk::VkPresentModeKHR presentMode, 813 vk::VkImageUsageFlags supportedImageUsage) 814 { 815 const deUint32 imageLayers = 1u; 816 const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage; 817 const vk::VkBool32 clipped = VK_FALSE; 818 vector<vk::VkSwapchainCreateInfoKHR> createInfos; 819 820 const deUint32 imageWidth = scaling == SCALING_NONE 821 ? (properties.currentExtent.width != 0xFFFFFFFFu 822 ? properties.currentExtent.width 823 : de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2))) 824 : (scaling == SCALING_UP 825 ? de::max(31u, properties.minImageExtent.width) 826 : properties.maxImageExtent.width); 827 const deUint32 imageHeight = scaling == SCALING_NONE 828 ? (properties.currentExtent.height != 0xFFFFFFFFu 829 ? properties.currentExtent.height 830 : de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2))) 831 : (scaling == SCALING_UP 832 ? de::max(31u, properties.minImageExtent.height) 833 : properties.maxImageExtent.height); 834 const vk::VkExtent2D imageSize = { imageWidth, imageHeight }; 835 836 { 837 size_t presentModeNdx; 838 839 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++) 840 { 841 if (presentModes[presentModeNdx] == presentMode) 842 break; 843 } 844 845 if (presentModeNdx == presentModes.size()) 846 TCU_THROW(NotSupportedError, "Present mode not supported"); 847 } 848 849 for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++) 850 { 851 for (vk::VkSurfaceTransformFlagsKHR transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u) 852 { 853 if ((properties.supportedTransforms & transform) == 0) 854 continue; 855 856 for (vk::VkCompositeAlphaFlagsKHR alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u) 857 { 858 if ((alpha & properties.supportedCompositeAlpha) == 0) 859 continue; 860 861 const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform; 862 const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha; 863 const vk::VkFormat imageFormat = formats[formatNdx].format; 864 const vk::VkColorSpaceKHR imageColorSpace = formats[formatNdx].colorSpace; 865 const vk::VkSwapchainCreateInfoKHR createInfo = 866 { 867 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 868 DE_NULL, 869 0u, 870 surface, 871 1, // Always 1 image for a shared presentable image swapchain. 872 imageFormat, 873 imageColorSpace, 874 imageSize, 875 imageLayers, 876 imageUsage, 877 vk::VK_SHARING_MODE_EXCLUSIVE, 878 1u, 879 &queueFamilyIndex, 880 preTransform, 881 compositeAlpha, 882 presentMode, 883 clipped, 884 (vk::VkSwapchainKHR)0 885 }; 886 887 createInfos.push_back(createInfo); 888 } 889 } 890 } 891 892 return createInfos; 893 } 894 895 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface& vki, 896 vk::VkPhysicalDevice physicalDevice, 897 vk::VkSurfaceKHR surface, 898 vk::VkImageUsageFlags* usage) 899 { 900 const vk::VkPhysicalDeviceSurfaceInfo2KHR info = 901 { 902 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, 903 DE_NULL, 904 905 surface 906 }; 907 vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities; 908 vk::VkSurfaceCapabilities2KHR capabilities; 909 910 sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR; 911 sharedCapabilities.pNext = DE_NULL; 912 913 capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, 914 capabilities.pNext = &sharedCapabilities; 915 916 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities)); 917 918 TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); 919 *usage = sharedCapabilities.sharedPresentSupportedUsageFlags; 920 921 return capabilities.surfaceCapabilities; 922 } 923 924 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig) 925 : TestInstance (context) 926 , m_testConfig (testConfig) 927 , m_quadCount (16u) 928 , m_vkp (context.getPlatformInterface()) 929 , m_instanceExtensions (vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL)) 930 , m_instance (createInstanceWithWsi(m_vkp, context.getUsedApiVersion(), m_instanceExtensions, testConfig.wsiType)) 931 , m_vki (m_vkp, *m_instance) 932 , m_physicalDevice (vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine())) 933 , m_nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType)) 934 , m_nativeWindow (createWindow(*m_nativeDisplay, tcu::nothing<UVec2>())) 935 , m_surface (vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow)) 936 937 , m_queueFamilyIndex (chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface)) 938 , m_deviceExtensions (vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL)) 939 , m_device (createDeviceWithWsi(m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useSharedPresentableImage)) 940 , m_vkd (m_vki, *m_device) 941 , m_queue (getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u)) 942 943 , m_commandPool (createCommandPool(m_vkd, *m_device, m_queueFamilyIndex)) 944 , m_vertexShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u)) 945 , m_fragmentShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u)) 946 , m_pipelineLayout (createPipelineLayout(m_vkd, *m_device)) 947 948 , m_supportedUsageFlags (0u) 949 , m_surfaceProperties (getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags)) 950 , m_surfaceFormats (vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface)) 951 , m_presentModes (vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface)) 952 953 , m_swapchainConfigs (generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode, m_supportedUsageFlags)) 954 , m_swapchainConfigNdx (0u) 955 956 , m_frameCount (60u * 5u) 957 , m_frameNdx (0u) 958 959 , m_maxOutOfDateCount (20u) 960 , m_outOfDateCount (0u) 961 { 962 { 963 const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities"); 964 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage; 965 m_context.getTestContext().getLog() << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage; 966 967 } 968 } 969 970 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance (void) 971 { 972 deinitSwapchainResources(); 973 } 974 975 void SharedPresentableImageTestInstance::initSwapchainResources (void) 976 { 977 const size_t fenceCount = 6; 978 const deUint32 imageWidth = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width; 979 const deUint32 imageHeight = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height; 980 const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat; 981 982 m_swapchain = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]); 983 m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front(); 984 985 m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat); 986 m_pipeline = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight); 987 988 m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat); 989 m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight); 990 991 m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0); 992 m_fences = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0); 993 m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0); 994 995 initSemaphores(m_vkd, *m_device, m_renderSemaphores); 996 997 initFences(m_vkd, *m_device, m_fences); 998 999 // Unlike a traditional swapchain, where we'd acquire a new image from the 1000 // PE every frame, a shared image swapchain has a single image that is 1001 // acquired upfront. We acquire it here, transition it to the proper layout, 1002 // and present it. 1003 1004 // Acquire the one image 1005 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul; 1006 vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device)); 1007 deUint32 imageIndex = 42; // initialize to junk value 1008 1009 VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex)); 1010 TCU_CHECK(imageIndex == 0); 1011 1012 // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR 1013 const vk::VkCommandBufferAllocateInfo allocateInfo = 1014 { 1015 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1016 DE_NULL, 1017 *m_commandPool, 1018 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1019 1 1020 }; 1021 const vk::VkCommandBufferBeginInfo beginInfo = 1022 { 1023 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 1024 DE_NULL, 1025 0u, 1026 DE_NULL 1027 }; 1028 1029 const vk::Unique<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo)); 1030 VK_CHECK(m_vkd.beginCommandBuffer(*commandBuffer, &beginInfo)); 1031 1032 const vk::VkImageMemoryBarrier barrier = { 1033 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 1034 DE_NULL, 1035 0, 1036 0, 1037 vk::VK_IMAGE_LAYOUT_UNDEFINED, 1038 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, 1039 VK_QUEUE_FAMILY_IGNORED, 1040 VK_QUEUE_FAMILY_IGNORED, 1041 m_swapchainImage, 1042 { 1043 vk::VK_IMAGE_ASPECT_COLOR_BIT, 1044 0, 1045 1, 1046 0, 1047 1 1048 }, 1049 }; 1050 1051 m_vkd.cmdPipelineBarrier(*commandBuffer, 1052 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 1053 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1054 0u, 1055 0, DE_NULL, 1056 0, DE_NULL, 1057 1, &barrier); 1058 1059 VK_CHECK(m_vkd.endCommandBuffer(*commandBuffer)); 1060 1061 const vk::VkPipelineStageFlags waitDstStages[] = { vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; 1062 const vk::VkSubmitInfo submitInfo = 1063 { 1064 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, 1065 DE_NULL, 1066 1, &*semaphore, waitDstStages, 1067 1, &*commandBuffer, 1068 0, DE_NULL, 1069 }; 1070 1071 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0)); 1072 VK_CHECK(m_vkd.queueWaitIdle(m_queue)); 1073 } 1074 1075 void SharedPresentableImageTestInstance::deinitSwapchainResources (void) 1076 { 1077 VK_CHECK(m_vkd.queueWaitIdle(m_queue)); 1078 1079 deinitSemaphores(m_vkd, *m_device, m_renderSemaphores); 1080 deinitFences(m_vkd, *m_device, m_fences); 1081 deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers); 1082 1083 m_framebuffer = vk::Move<vk::VkFramebuffer>(); 1084 m_swapchainImageView = vk::Move<vk::VkImageView>(); 1085 m_swapchainImage = (vk::VkImage)0; 1086 1087 m_swapchain = vk::Move<vk::VkSwapchainKHR>(); 1088 m_renderPass = vk::Move<vk::VkRenderPass>(); 1089 m_pipeline = vk::Move<vk::VkPipeline>(); 1090 } 1091 1092 void SharedPresentableImageTestInstance::render (void) 1093 { 1094 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul; 1095 const vk::VkFence fence = m_fences[m_frameNdx % m_fences.size()]; 1096 const deUint32 width = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width; 1097 const deUint32 height = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height; 1098 1099 // Throttle execution 1100 if (m_frameNdx >= m_fences.size()) 1101 { 1102 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs)); 1103 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence)); 1104 1105 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]); 1106 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0; 1107 } 1108 1109 deUint32 imageIndex = 0; // There is only one image. 1110 const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()]; 1111 1112 const bool willPresent = m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || !m_frameNdx; 1113 1114 // Create command buffer 1115 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, *m_framebuffer, *m_pipeline, m_frameNdx, m_quadCount, width, height).disown(); 1116 1117 // Submit command buffer 1118 { 1119 const vk::VkSubmitInfo submitInfo = 1120 { 1121 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, 1122 DE_NULL, 1123 0u, 1124 DE_NULL, 1125 DE_NULL, 1126 1u, 1127 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()], 1128 willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent. 1129 ¤tRenderSemaphore 1130 }; 1131 1132 // With a traditional swapchain, we'd fence on completion of 1133 // AcquireNextImage. We never call that for a shared image swapchain, so 1134 // fence on completion of the rendering work instead. A real shared 1135 // image application would want a more substantial pacing mechanism. 1136 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence)); 1137 } 1138 1139 // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be 1140 // assured the PE has picked up a new frame. The PE /may/ also pick up 1141 // changes whenever it likes. 1142 // 1143 // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the 1144 // first frame to kick things off. 1145 if (willPresent) 1146 { 1147 1148 // Present frame 1149 vk::VkResult result; 1150 const vk::VkPresentInfoKHR presentInfo = 1151 { 1152 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 1153 DE_NULL, 1154 1u, 1155 ¤tRenderSemaphore, 1156 1u, 1157 &*m_swapchain, 1158 &imageIndex, 1159 &result 1160 }; 1161 1162 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo)); 1163 VK_CHECK(result); 1164 1165 } 1166 1167 // With either present mode, we can call GetSwapchainStatus at any time 1168 // to detect possible OUT_OF_DATE conditions. Let's do that every frame. 1169 1170 const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain); 1171 VK_CHECK(swapchainStatus); 1172 } 1173 1174 tcu::TestStatus SharedPresentableImageTestInstance::iterate (void) 1175 { 1176 // Initialize swapchain specific resources 1177 // Render test 1178 try 1179 { 1180 if (m_frameNdx == 0) 1181 { 1182 if (m_outOfDateCount == 0) 1183 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx] << tcu::TestLog::EndMessage; 1184 1185 initSwapchainResources(); 1186 } 1187 1188 render(); 1189 } 1190 catch (const vk::Error& error) 1191 { 1192 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR) 1193 { 1194 m_swapchainConfigs = generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags); 1195 1196 if (m_outOfDateCount < m_maxOutOfDateCount) 1197 { 1198 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage; 1199 deinitSwapchainResources(); 1200 m_frameNdx = 0; 1201 m_outOfDateCount++; 1202 1203 return tcu::TestStatus::incomplete(); 1204 } 1205 else 1206 { 1207 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage; 1208 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount)); 1209 } 1210 } 1211 else 1212 { 1213 m_resultCollector.fail(error.what()); 1214 } 1215 1216 deinitSwapchainResources(); 1217 1218 m_swapchainConfigNdx++; 1219 m_frameNdx = 0; 1220 m_outOfDateCount = 0; 1221 1222 if (m_swapchainConfigNdx >= m_swapchainConfigs.size()) 1223 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); 1224 else 1225 return tcu::TestStatus::incomplete(); 1226 } 1227 1228 m_frameNdx++; 1229 1230 if (m_frameNdx >= m_frameCount) 1231 { 1232 m_frameNdx = 0; 1233 m_outOfDateCount = 0; 1234 m_swapchainConfigNdx++; 1235 1236 deinitSwapchainResources(); 1237 1238 if (m_swapchainConfigNdx >= m_swapchainConfigs.size()) 1239 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); 1240 else 1241 return tcu::TestStatus::incomplete(); 1242 } 1243 else 1244 return tcu::TestStatus::incomplete(); 1245 } 1246 1247 struct Programs 1248 { 1249 static void init (vk::SourceCollections& dst, TestConfig) 1250 { 1251 dst.glslSources.add("quad-vert") << glu::VertexSource( 1252 "#version 450\n" 1253 "out gl_PerVertex {\n" 1254 "\tvec4 gl_Position;\n" 1255 "};\n" 1256 "layout(location = 0) out highp uint quadIndex;\n" 1257 "highp float;\n" 1258 "void main (void) {\n" 1259 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" 1260 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" 1261 "\tquadIndex = gl_VertexIndex / 6;\n" 1262 "}\n"); 1263 dst.glslSources.add("quad-frag") << glu::FragmentSource( 1264 "#version 310 es\n" 1265 "layout(location = 0) flat in highp uint quadIndex;\n" 1266 "layout(location = 0) out highp vec4 o_color;\n" 1267 "layout(push_constant) uniform PushConstant {\n" 1268 "\thighp uint frameNdx;\n" 1269 "} pushConstants;\n" 1270 "void main (void)\n" 1271 "{\n" 1272 "\thighp uint frameNdx = pushConstants.frameNdx;\n" 1273 "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n" 1274 "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n" 1275 "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n" 1276 "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n" 1277 "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n" 1278 "\t + 64u * bitfieldExtract(y, 1, 1)\n" 1279 "\t + 32u * bitfieldExtract(x, 3, 1);\n" 1280 "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n" 1281 "\t + 64u * bitfieldExtract(x, 2, 1)\n" 1282 "\t + 32u * bitfieldExtract(y, 3, 1);\n" 1283 "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n" 1284 "\t + 64u * bitfieldExtract(y, 2, 1)\n" 1285 "\t + 32u * bitfieldExtract(x, 4, 1);\n" 1286 "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n" 1287 "}\n"); 1288 } 1289 }; 1290 1291 } // anonymous 1292 1293 void createSharedPresentableImageTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType) 1294 { 1295 const struct 1296 { 1297 Scaling scaling; 1298 const char* name; 1299 } scaling [] = 1300 { 1301 { SCALING_NONE, "scale_none" }, 1302 { SCALING_UP, "scale_up" }, 1303 { SCALING_DOWN, "scale_down" } 1304 }; 1305 const struct 1306 { 1307 vk::VkPresentModeKHR mode; 1308 const char* name; 1309 } presentModes[] = 1310 { 1311 { vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand" }, 1312 { vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous" }, 1313 }; 1314 1315 for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++) 1316 { 1317 if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType)) 1318 { 1319 de::MovePtr<tcu::TestCaseGroup> scaleGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name, scaling[scalingNdx].name)); 1320 1321 for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++) 1322 { 1323 1324 const char* const name = presentModes[presentModeNdx].name; 1325 TestConfig config; 1326 1327 config.wsiType = wsiType; 1328 config.useSharedPresentableImage= true; 1329 config.scaling = scaling[scalingNdx].scaling; 1330 config.presentMode = presentModes[presentModeNdx].mode; 1331 1332 scaleGroup->addChild(new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config)); 1333 } 1334 1335 testGroup->addChild(scaleGroup.release()); 1336 } 1337 } 1338 } 1339 1340 } // wsi 1341 } // vkt 1342