1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 Google Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Tests for shared presentable image extension
22 *//*--------------------------------------------------------------------*/
24 #include "vktWsiSharedPresentableImageTests.hpp"
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 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
39 #include "vkWsiUtil.hpp"
41 #include "tcuPlatform.hpp"
42 #include "tcuResultCollector.hpp"
43 #include "tcuTestLog.hpp"
68 typedef vector<vk::VkExtensionProperties> Extensions;
70 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
72 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
73 requiredExtName != requiredExtensions.end();
76 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
77 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
81 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface& vkp,
83 const Extensions& supportedExtensions,
84 vk::wsi::Type wsiType)
86 vector<string> extensions;
88 if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
89 extensions.push_back("VK_KHR_get_physical_device_properties2");
91 extensions.push_back("VK_KHR_surface");
92 extensions.push_back("VK_KHR_get_surface_capabilities2");
93 // Required for device extension to expose new physical device bits (in this
94 // case, presentation mode enums)
95 extensions.push_back(getExtensionName(wsiType));
97 checkAllSupported(supportedExtensions, extensions);
99 return vk::createDefaultInstance(vkp, version, vector<string>(), extensions);
102 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
104 vk::VkPhysicalDeviceFeatures features;
105 deMemset(&features, 0, sizeof(features));
109 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
111 deUint32 numFamilies = 0;
113 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
118 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
120 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
121 vector<deUint32> supportedFamilyIndices;
123 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
125 if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
126 supportedFamilyIndices.push_back(queueFamilyNdx);
129 return supportedFamilyIndices;
132 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
134 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
136 if (supportedFamilyIndices.empty())
137 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
139 return supportedFamilyIndices[0];
142 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::PlatformInterface& vkp,
143 vk::VkInstance instance,
144 const vk::InstanceInterface& vki,
145 vk::VkPhysicalDevice physicalDevice,
146 const Extensions& supportedExtensions,
147 const deUint32 queueFamilyIndex,
148 bool requiresSharedPresentableImage,
149 const vk::VkAllocationCallbacks* pAllocator = DE_NULL)
151 const float queuePriorities[] = { 1.0f };
152 const vk::VkDeviceQueueCreateInfo queueInfos[] =
155 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
157 (vk::VkDeviceQueueCreateFlags)0,
159 DE_LENGTH_OF_ARRAY(queuePriorities),
163 const vk::VkPhysicalDeviceFeatures features = getDeviceNullFeatures();
164 const char* const extensions[] =
167 "VK_KHR_shared_presentable_image"
170 const vk::VkDeviceCreateInfo deviceParams =
172 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
174 (vk::VkDeviceCreateFlags)0,
175 DE_LENGTH_OF_ARRAY(queueInfos),
179 requiresSharedPresentableImage ? 2u : 1u,
180 DE_ARRAY_BEGIN(extensions),
184 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
186 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
187 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
190 return createDevice(vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
193 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
194 const Extensions& supportedExtensions,
195 vk::wsi::Type wsiType)
199 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
201 catch (const tcu::NotSupportedError& e)
203 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
204 platform.hasDisplay(wsiType))
206 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
207 // must support creating native display & window for that WSI type.
208 throw tcu::TestError(e.getMessage());
215 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
219 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
221 catch (const tcu::NotSupportedError& e)
223 // See createDisplay - assuming that wsi::Display was supported platform port
224 // should also support creating a window.
225 throw tcu::TestError(e.getMessage());
229 bool wsiTypeSupportsScaling (vk::wsi::Type wsiType)
231 return vk::wsi::getPlatformProperties(wsiType).swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
234 void initSemaphores (const vk::DeviceInterface& vkd,
236 std::vector<vk::VkSemaphore>& semaphores)
238 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
239 semaphores[ndx] = createSemaphore(vkd, device).disown();
242 void deinitSemaphores (const vk::DeviceInterface& vkd,
244 std::vector<vk::VkSemaphore>& semaphores)
246 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
248 if (semaphores[ndx] != (vk::VkSemaphore)0)
249 vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
251 semaphores[ndx] = (vk::VkSemaphore)0;
257 void initFences (const vk::DeviceInterface& vkd,
259 std::vector<vk::VkFence>& fences)
261 for (size_t ndx = 0; ndx < fences.size(); ndx++)
262 fences[ndx] = createFence(vkd, device).disown();
265 void deinitFences (const vk::DeviceInterface& vkd,
267 std::vector<vk::VkFence>& fences)
269 for (size_t ndx = 0; ndx < fences.size(); ndx++)
271 if (fences[ndx] != (vk::VkFence)0)
272 vkd.destroyFence(device, fences[ndx], DE_NULL);
274 fences[ndx] = (vk::VkFence)0;
280 void cmdRenderFrame (const vk::DeviceInterface& vkd,
281 vk::VkCommandBuffer commandBuffer,
282 vk::VkPipelineLayout pipelineLayout,
283 vk::VkPipeline pipeline,
287 const deUint32 frameNdxValue = (deUint32)frameNdx;
289 vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
290 vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
291 vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
294 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface& vkd,
296 vk::VkCommandPool commandPool,
297 vk::VkPipelineLayout pipelineLayout,
298 vk::VkRenderPass renderPass,
299 vk::VkFramebuffer framebuffer,
300 vk::VkPipeline pipeline,
304 deUint32 imageHeight)
306 const vk::VkCommandBufferAllocateInfo allocateInfo =
308 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
312 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
316 vk::Move<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(vkd, device, &allocateInfo));
317 beginCommandBuffer(vkd, *commandBuffer, 0u);
319 beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, vk::makeRect2D(0, 0, imageWidth, imageHeight), tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
321 cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
323 endRenderPass(vkd, *commandBuffer);
325 endCommandBuffer(vkd, *commandBuffer);
326 return commandBuffer;
329 void deinitCommandBuffers (const vk::DeviceInterface& vkd,
331 vk::VkCommandPool commandPool,
332 std::vector<vk::VkCommandBuffer>& commandBuffers)
334 for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
336 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
337 vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
339 commandBuffers[ndx] = (vk::VkCommandBuffer)0;
342 commandBuffers.clear();
345 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vkd,
347 deUint32 queueFamilyIndex)
349 const vk::VkCommandPoolCreateInfo createInfo =
351 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
357 return vk::createCommandPool(vkd, device, &createInfo);
360 vk::Move<vk::VkFramebuffer> createFramebuffer (const vk::DeviceInterface& vkd,
362 vk::VkRenderPass renderPass,
363 vk::VkImageView imageView,
367 const vk::VkFramebufferCreateInfo createInfo =
369 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
381 return vk::createFramebuffer(vkd, device, &createInfo);
384 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd,
389 const vk::VkImageViewCreateInfo createInfo =
391 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
396 vk::VK_IMAGE_VIEW_TYPE_2D,
398 vk::makeComponentMappingRGBA(),
400 vk::VK_IMAGE_ASPECT_COLOR_BIT,
408 return vk::createImageView(vkd, device, &createInfo, DE_NULL);
411 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
415 const vk::VkAttachmentDescription attachments[] =
420 vk::VK_SAMPLE_COUNT_1_BIT,
422 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
423 vk::VK_ATTACHMENT_STORE_OP_STORE,
425 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
426 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
428 // This differs from the usual layout handling in that the
429 // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
430 // the time. We should not ever transition it away (or discard the
431 // contents with a transition from UNDEFINED) as the PE is accessing
432 // the image concurrently with our rendering.
433 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
434 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
437 const vk::VkAttachmentReference colorAttachmentRefs[] =
441 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
444 const vk::VkSubpassDescription subpasses[] =
448 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
452 DE_LENGTH_OF_ARRAY(colorAttachmentRefs),
462 const vk::VkRenderPassCreateInfo createInfo =
464 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
468 DE_LENGTH_OF_ARRAY(attachments),
471 DE_LENGTH_OF_ARRAY(subpasses),
478 return vk::createRenderPass(vkd, device, &createInfo);
481 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd,
483 vk::VkRenderPass renderPass,
484 vk::VkPipelineLayout layout,
485 vk::VkShaderModule vertexShaderModule,
486 vk::VkShaderModule fragmentShaderModule,
490 const vk::VkPipelineVertexInputStateCreateInfo vertexInputState =
492 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
500 const std::vector<vk::VkViewport> viewports (1, vk::makeViewport(tcu::UVec2(width, height)));
501 const std::vector<vk::VkRect2D> noScissors;
503 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
504 device, // const VkDevice device
505 layout, // const VkPipelineLayout pipelineLayout
506 vertexShaderModule, // const VkShaderModule vertexShaderModule
507 DE_NULL, // const VkShaderModule tessellationControlShaderModule
508 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
509 DE_NULL, // const VkShaderModule geometryShaderModule
510 fragmentShaderModule, // const VkShaderModule fragmentShaderModule
511 renderPass, // const VkRenderPass renderPass
512 viewports, // const std::vector<VkViewport>& viewports
513 noScissors, // const std::vector<VkRect2D>& scissors
514 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
515 0u, // const deUint32 subpass
516 0u, // const deUint32 patchControlPoints
517 &vertexInputState); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
520 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vkd,
523 const vk::VkPushConstantRange pushConstants[] =
526 vk::VK_SHADER_STAGE_FRAGMENT_BIT,
531 const vk::VkPipelineLayoutCreateInfo createInfo =
533 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
540 DE_LENGTH_OF_ARRAY(pushConstants),
544 return vk::createPipelineLayout(vkd, device, &createInfo);
549 vk::wsi::Type wsiType;
551 bool useSharedPresentableImage;
552 vk::VkPresentModeKHR presentMode;
555 class SharedPresentableImageTestInstance : public TestInstance
558 SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig);
559 ~SharedPresentableImageTestInstance (void);
561 tcu::TestStatus iterate (void);
564 const TestConfig m_testConfig;
565 const deUint32 m_quadCount;
566 const vk::PlatformInterface& m_vkp;
567 const Extensions m_instanceExtensions;
568 const vk::Unique<vk::VkInstance> m_instance;
569 const vk::InstanceDriver m_vki;
570 const vk::VkPhysicalDevice m_physicalDevice;
571 const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
572 const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
573 const vk::Unique<vk::VkSurfaceKHR> m_surface;
575 const deUint32 m_queueFamilyIndex;
576 const Extensions m_deviceExtensions;
577 const vk::Unique<vk::VkDevice> m_device;
578 const vk::DeviceDriver m_vkd;
579 const vk::VkQueue m_queue;
581 const vk::Unique<vk::VkCommandPool> m_commandPool;
582 const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
583 const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
584 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
586 vk::VkImageUsageFlags m_supportedUsageFlags;
587 const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
588 const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
589 const vector<vk::VkPresentModeKHR> m_presentModes;
591 tcu::ResultCollector m_resultCollector;
593 vk::Move<vk::VkSwapchainKHR> m_swapchain;
594 vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain
595 vk::Move<vk::VkImageView> m_swapchainImageView;
596 vk::Move<vk::VkFramebuffer> m_framebuffer;
598 vk::Move<vk::VkRenderPass> m_renderPass;
599 vk::Move<vk::VkPipeline> m_pipeline;
601 std::vector<vk::VkCommandBuffer> m_commandBuffers;
602 std::vector<vk::VkSemaphore> m_renderSemaphores;
603 std::vector<vk::VkFence> m_fences;
605 std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs;
606 size_t m_swapchainConfigNdx;
608 const size_t m_frameCount;
611 const size_t m_maxOutOfDateCount;
612 size_t m_outOfDateCount;
614 void initSwapchainResources (void);
615 void deinitSwapchainResources (void);
619 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs (vk::VkSurfaceKHR surface,
620 deUint32 queueFamilyIndex,
622 const vk::VkSurfaceCapabilitiesKHR& properties,
623 const vector<vk::VkSurfaceFormatKHR>& formats,
624 const vector<vk::VkPresentModeKHR>& presentModes,
625 vk::VkPresentModeKHR presentMode,
626 vk::VkImageUsageFlags supportedImageUsage)
628 const deUint32 imageLayers = 1u;
629 const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage;
630 const vk::VkBool32 clipped = VK_FALSE;
631 vector<vk::VkSwapchainCreateInfoKHR> createInfos;
633 const deUint32 imageWidth = scaling == SCALING_NONE
634 ? (properties.currentExtent.width != 0xFFFFFFFFu
635 ? properties.currentExtent.width
636 : de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2)))
637 : (scaling == SCALING_UP
638 ? de::max(31u, properties.minImageExtent.width)
639 : properties.maxImageExtent.width);
640 const deUint32 imageHeight = scaling == SCALING_NONE
641 ? (properties.currentExtent.height != 0xFFFFFFFFu
642 ? properties.currentExtent.height
643 : de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2)))
644 : (scaling == SCALING_UP
645 ? de::max(31u, properties.minImageExtent.height)
646 : properties.maxImageExtent.height);
647 const vk::VkExtent2D imageSize = { imageWidth, imageHeight };
650 size_t presentModeNdx;
652 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
654 if (presentModes[presentModeNdx] == presentMode)
658 if (presentModeNdx == presentModes.size())
659 TCU_THROW(NotSupportedError, "Present mode not supported");
662 for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
664 for (vk::VkSurfaceTransformFlagsKHR transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
666 if ((properties.supportedTransforms & transform) == 0)
669 for (vk::VkCompositeAlphaFlagsKHR alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
671 if ((alpha & properties.supportedCompositeAlpha) == 0)
674 const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
675 const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
676 const vk::VkFormat imageFormat = formats[formatNdx].format;
677 const vk::VkColorSpaceKHR imageColorSpace = formats[formatNdx].colorSpace;
678 const vk::VkSwapchainCreateInfoKHR createInfo =
680 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
684 1, // Always 1 image for a shared presentable image swapchain.
690 vk::VK_SHARING_MODE_EXCLUSIVE,
697 (vk::VkSwapchainKHR)0
700 createInfos.push_back(createInfo);
708 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface& vki,
709 vk::VkPhysicalDevice physicalDevice,
710 vk::VkSurfaceKHR surface,
711 vk::VkImageUsageFlags* usage)
713 const vk::VkPhysicalDeviceSurfaceInfo2KHR info =
715 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
720 vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities;
721 vk::VkSurfaceCapabilities2KHR capabilities;
723 sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
724 sharedCapabilities.pNext = DE_NULL;
726 capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
727 capabilities.pNext = &sharedCapabilities;
729 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
731 TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
732 *usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
734 return capabilities.surfaceCapabilities;
737 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig)
738 : TestInstance (context)
739 , m_testConfig (testConfig)
741 , m_vkp (context.getPlatformInterface())
742 , m_instanceExtensions (vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
743 , m_instance (createInstanceWithWsi(m_vkp, context.getUsedApiVersion(), m_instanceExtensions, testConfig.wsiType))
744 , m_vki (m_vkp, *m_instance)
745 , m_physicalDevice (vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
746 , m_nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
747 , m_nativeWindow (createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
748 , m_surface (vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
750 , m_queueFamilyIndex (chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
751 , m_deviceExtensions (vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
752 , m_device (createDeviceWithWsi(m_vkp, *m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useSharedPresentableImage))
753 , m_vkd (m_vkp, *m_instance, *m_device)
754 , m_queue (getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
756 , m_commandPool (createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
757 , m_vertexShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
758 , m_fragmentShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
759 , m_pipelineLayout (createPipelineLayout(m_vkd, *m_device))
761 , m_supportedUsageFlags (0u)
762 , m_surfaceProperties (getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
763 , m_surfaceFormats (vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
764 , m_presentModes (vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
766 , m_swapchainConfigs (generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode, m_supportedUsageFlags))
767 , m_swapchainConfigNdx (0u)
769 , m_frameCount (60u * 5u)
772 , m_maxOutOfDateCount (20u)
773 , m_outOfDateCount (0u)
776 const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
777 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
778 m_context.getTestContext().getLog() << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
783 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance (void)
785 deinitSwapchainResources();
788 void SharedPresentableImageTestInstance::initSwapchainResources (void)
790 const size_t fenceCount = 6;
791 const deUint32 imageWidth = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
792 const deUint32 imageHeight = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
793 const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
795 m_swapchain = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
796 m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
798 m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
799 m_pipeline = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
801 m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
802 m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
804 m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
805 m_fences = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
806 m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
808 initSemaphores(m_vkd, *m_device, m_renderSemaphores);
810 initFences(m_vkd, *m_device, m_fences);
812 // Unlike a traditional swapchain, where we'd acquire a new image from the
813 // PE every frame, a shared image swapchain has a single image that is
814 // acquired upfront. We acquire it here, transition it to the proper layout,
817 // Acquire the one image
818 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
819 vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device));
820 deUint32 imageIndex = 42; // initialize to junk value
822 VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
823 TCU_CHECK(imageIndex == 0);
825 // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
826 const vk::VkCommandBufferAllocateInfo allocateInfo =
828 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
831 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
835 const vk::Unique<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
836 beginCommandBuffer(m_vkd, *commandBuffer, 0u);
838 const vk::VkImageMemoryBarrier barrier = {
839 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
843 vk::VK_IMAGE_LAYOUT_UNDEFINED,
844 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
845 VK_QUEUE_FAMILY_IGNORED,
846 VK_QUEUE_FAMILY_IGNORED,
849 vk::VK_IMAGE_ASPECT_COLOR_BIT,
857 m_vkd.cmdPipelineBarrier(*commandBuffer,
858 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
859 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
865 endCommandBuffer(m_vkd, *commandBuffer);
867 const vk::VkPipelineStageFlags waitDstStages[] = { vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
868 const vk::VkSubmitInfo submitInfo =
870 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
872 1, &*semaphore, waitDstStages,
877 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
878 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
881 void SharedPresentableImageTestInstance::deinitSwapchainResources (void)
883 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
885 deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
886 deinitFences(m_vkd, *m_device, m_fences);
887 deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
889 m_framebuffer = vk::Move<vk::VkFramebuffer>();
890 m_swapchainImageView = vk::Move<vk::VkImageView>();
891 m_swapchainImage = (vk::VkImage)0;
893 m_swapchain = vk::Move<vk::VkSwapchainKHR>();
894 m_renderPass = vk::Move<vk::VkRenderPass>();
895 m_pipeline = vk::Move<vk::VkPipeline>();
898 void SharedPresentableImageTestInstance::render (void)
900 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
901 const vk::VkFence fence = m_fences[m_frameNdx % m_fences.size()];
902 const deUint32 width = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
903 const deUint32 height = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
905 // Throttle execution
906 if (m_frameNdx >= m_fences.size())
908 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
909 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
911 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
912 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
915 deUint32 imageIndex = 0; // There is only one image.
916 const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
918 const bool willPresent = m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || !m_frameNdx;
920 // Create command buffer
921 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();
923 // Submit command buffer
925 const vk::VkSubmitInfo submitInfo =
927 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
933 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
934 willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent.
935 ¤tRenderSemaphore
938 // With a traditional swapchain, we'd fence on completion of
939 // AcquireNextImage. We never call that for a shared image swapchain, so
940 // fence on completion of the rendering work instead. A real shared
941 // image application would want a more substantial pacing mechanism.
942 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
945 // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
946 // assured the PE has picked up a new frame. The PE /may/ also pick up
947 // changes whenever it likes.
949 // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
950 // first frame to kick things off.
956 const vk::VkPresentInfoKHR presentInfo =
958 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
961 ¤tRenderSemaphore,
968 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
973 // With either present mode, we can call GetSwapchainStatus at any time
974 // to detect possible OUT_OF_DATE conditions. Let's do that every frame.
976 const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
977 VK_CHECK(swapchainStatus);
980 tcu::TestStatus SharedPresentableImageTestInstance::iterate (void)
982 // Initialize swapchain specific resources
988 if (m_outOfDateCount == 0)
989 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx] << tcu::TestLog::EndMessage;
991 initSwapchainResources();
996 catch (const vk::Error& error)
998 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
1000 m_swapchainConfigs = generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags);
1002 if (m_outOfDateCount < m_maxOutOfDateCount)
1004 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
1005 deinitSwapchainResources();
1009 return tcu::TestStatus::incomplete();
1013 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1014 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1019 m_resultCollector.fail(error.what());
1022 deinitSwapchainResources();
1024 m_swapchainConfigNdx++;
1026 m_outOfDateCount = 0;
1028 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1029 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1031 return tcu::TestStatus::incomplete();
1036 if (m_frameNdx >= m_frameCount)
1039 m_outOfDateCount = 0;
1040 m_swapchainConfigNdx++;
1042 deinitSwapchainResources();
1044 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1045 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1047 return tcu::TestStatus::incomplete();
1050 return tcu::TestStatus::incomplete();
1055 static void init (vk::SourceCollections& dst, TestConfig)
1057 dst.glslSources.add("quad-vert") << glu::VertexSource(
1059 "out gl_PerVertex {\n"
1060 "\tvec4 gl_Position;\n"
1062 "layout(location = 0) out highp uint quadIndex;\n"
1064 "void main (void) {\n"
1065 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1066 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1067 "\tquadIndex = gl_VertexIndex / 6;\n"
1069 dst.glslSources.add("quad-frag") << glu::FragmentSource(
1071 "layout(location = 0) flat in highp uint quadIndex;\n"
1072 "layout(location = 0) out highp vec4 o_color;\n"
1073 "layout(push_constant) uniform PushConstant {\n"
1074 "\thighp uint frameNdx;\n"
1075 "} pushConstants;\n"
1076 "void main (void)\n"
1078 "\thighp uint frameNdx = pushConstants.frameNdx;\n"
1079 "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
1080 "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
1081 "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
1082 "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
1083 "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1084 "\t + 64u * bitfieldExtract(y, 1, 1)\n"
1085 "\t + 32u * bitfieldExtract(x, 3, 1);\n"
1086 "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1087 "\t + 64u * bitfieldExtract(x, 2, 1)\n"
1088 "\t + 32u * bitfieldExtract(y, 3, 1);\n"
1089 "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1090 "\t + 64u * bitfieldExtract(y, 2, 1)\n"
1091 "\t + 32u * bitfieldExtract(x, 4, 1);\n"
1092 "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1099 void createSharedPresentableImageTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1107 { SCALING_NONE, "scale_none" },
1108 { SCALING_UP, "scale_up" },
1109 { SCALING_DOWN, "scale_down" }
1113 vk::VkPresentModeKHR mode;
1117 { vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand" },
1118 { vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous" },
1121 for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
1123 if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
1125 de::MovePtr<tcu::TestCaseGroup> scaleGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name, scaling[scalingNdx].name));
1127 for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1130 const char* const name = presentModes[presentModeNdx].name;
1133 config.wsiType = wsiType;
1134 config.useSharedPresentableImage= true;
1135 config.scaling = scaling[scalingNdx].scaling;
1136 config.presentMode = presentModes[presentModeNdx].mode;
1138 scaleGroup->addChild(new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
1141 testGroup->addChild(scaleGroup.release());