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"
37 #include "vkWsiUtil.hpp"
39 #include "tcuPlatform.hpp"
40 #include "tcuResultCollector.hpp"
41 #include "tcuTestLog.hpp"
66 typedef vector<vk::VkExtensionProperties> Extensions;
68 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
70 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
71 requiredExtName != requiredExtensions.end();
74 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
75 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface& vkp,
80 const Extensions& supportedExtensions,
81 vk::wsi::Type wsiType)
83 vector<string> extensions;
85 extensions.push_back("VK_KHR_surface");
86 extensions.push_back("VK_KHR_get_surface_capabilities2");
87 // Required for device extension to expose new physical device bits (in this
88 // case, presentation mode enums)
89 extensions.push_back("VK_KHR_get_physical_device_properties2");
90 extensions.push_back(getExtensionName(wsiType));
92 checkAllSupported(supportedExtensions, extensions);
94 return vk::createDefaultInstance(vkp, vector<string>(), extensions);
97 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
99 vk::VkPhysicalDeviceFeatures features;
100 deMemset(&features, 0, sizeof(features));
104 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
106 deUint32 numFamilies = 0;
108 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
113 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
115 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
116 vector<deUint32> supportedFamilyIndices;
118 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
120 if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
121 supportedFamilyIndices.push_back(queueFamilyNdx);
124 return supportedFamilyIndices;
127 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
129 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
131 if (supportedFamilyIndices.empty())
132 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
134 return supportedFamilyIndices[0];
137 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::InstanceInterface& vki,
138 vk::VkPhysicalDevice physicalDevice,
139 const Extensions& supportedExtensions,
140 const deUint32 queueFamilyIndex,
141 bool requiresSharedPresentableImage,
142 const vk::VkAllocationCallbacks* pAllocator = DE_NULL)
144 const float queuePriorities[] = { 1.0f };
145 const vk::VkDeviceQueueCreateInfo queueInfos[] =
148 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
150 (vk::VkDeviceQueueCreateFlags)0,
152 DE_LENGTH_OF_ARRAY(queuePriorities),
156 const vk::VkPhysicalDeviceFeatures features = getDeviceNullFeatures();
157 const char* const extensions[] =
160 "VK_KHR_shared_presentable_image"
163 const vk::VkDeviceCreateInfo deviceParams =
165 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
167 (vk::VkDeviceCreateFlags)0,
168 DE_LENGTH_OF_ARRAY(queueInfos),
172 requiresSharedPresentableImage ? 2u : 1u,
173 DE_ARRAY_BEGIN(extensions),
177 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
179 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
180 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
183 return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
186 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
187 const Extensions& supportedExtensions,
188 vk::wsi::Type wsiType)
192 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
194 catch (const tcu::NotSupportedError& e)
196 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
198 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
199 // must support creating native display & window for that WSI type.
200 throw tcu::TestError(e.getMessage());
207 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
211 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
213 catch (const tcu::NotSupportedError& e)
215 // See createDisplay - assuming that wsi::Display was supported platform port
216 // should also support creating a window.
217 throw tcu::TestError(e.getMessage());
221 bool wsiTypeSupportsScaling (vk::wsi::Type wsiType)
223 return vk::wsi::getPlatformProperties(wsiType).swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
226 void initSemaphores (const vk::DeviceInterface& vkd,
228 std::vector<vk::VkSemaphore>& semaphores)
230 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
231 semaphores[ndx] = createSemaphore(vkd, device).disown();
234 void deinitSemaphores (const vk::DeviceInterface& vkd,
236 std::vector<vk::VkSemaphore>& semaphores)
238 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
240 if (semaphores[ndx] != (vk::VkSemaphore)0)
241 vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
243 semaphores[ndx] = (vk::VkSemaphore)0;
249 void initFences (const vk::DeviceInterface& vkd,
251 std::vector<vk::VkFence>& fences)
253 for (size_t ndx = 0; ndx < fences.size(); ndx++)
254 fences[ndx] = createFence(vkd, device).disown();
257 void deinitFences (const vk::DeviceInterface& vkd,
259 std::vector<vk::VkFence>& fences)
261 for (size_t ndx = 0; ndx < fences.size(); ndx++)
263 if (fences[ndx] != (vk::VkFence)0)
264 vkd.destroyFence(device, fences[ndx], DE_NULL);
266 fences[ndx] = (vk::VkFence)0;
272 void cmdRenderFrame (const vk::DeviceInterface& vkd,
273 vk::VkCommandBuffer commandBuffer,
274 vk::VkPipelineLayout pipelineLayout,
275 vk::VkPipeline pipeline,
279 const deUint32 frameNdxValue = (deUint32)frameNdx;
281 vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
282 vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
283 vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
286 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface& vkd,
288 vk::VkCommandPool commandPool,
289 vk::VkPipelineLayout pipelineLayout,
290 vk::VkRenderPass renderPass,
291 vk::VkFramebuffer framebuffer,
292 vk::VkPipeline pipeline,
296 deUint32 imageHeight)
298 const vk::VkCommandBufferAllocateInfo allocateInfo =
300 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
304 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
307 const vk::VkCommandBufferBeginInfo beginInfo =
309 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
315 vk::Move<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(vkd, device, &allocateInfo));
316 VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
319 const vk::VkClearValue clearValue = vk::makeClearValueColorF32(0.25f, 0.50f, 0.75f, 1.00f);
320 const vk::VkRenderPassBeginInfo renderPassBeginInfo =
322 vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
329 { (deInt32)0, (deInt32)0 },
330 { imageWidth, imageHeight }
335 vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
338 cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
340 vkd.cmdEndRenderPass(*commandBuffer);
342 VK_CHECK(vkd.endCommandBuffer(*commandBuffer));
343 return commandBuffer;
346 void deinitCommandBuffers (const vk::DeviceInterface& vkd,
348 vk::VkCommandPool commandPool,
349 std::vector<vk::VkCommandBuffer>& commandBuffers)
351 for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
353 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
354 vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
356 commandBuffers[ndx] = (vk::VkCommandBuffer)0;
359 commandBuffers.clear();
362 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vkd,
364 deUint32 queueFamilyIndex)
366 const vk::VkCommandPoolCreateInfo createInfo =
368 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
374 return vk::createCommandPool(vkd, device, &createInfo);
377 vk::Move<vk::VkFramebuffer> createFramebuffer (const vk::DeviceInterface& vkd,
379 vk::VkRenderPass renderPass,
380 vk::VkImageView imageView,
384 const vk::VkFramebufferCreateInfo createInfo =
386 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
398 return vk::createFramebuffer(vkd, device, &createInfo);
401 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd,
406 const vk::VkImageViewCreateInfo createInfo =
408 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
413 vk::VK_IMAGE_VIEW_TYPE_2D,
415 vk::makeComponentMappingRGBA(),
417 vk::VK_IMAGE_ASPECT_COLOR_BIT,
425 return vk::createImageView(vkd, device, &createInfo, DE_NULL);
428 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
432 const vk::VkAttachmentDescription attachments[] =
437 vk::VK_SAMPLE_COUNT_1_BIT,
439 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
440 vk::VK_ATTACHMENT_STORE_OP_STORE,
442 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
443 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
445 // This differs from the usual layout handling in that the
446 // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
447 // the time. We should not ever transition it away (or discard the
448 // contents with a transition from UNDEFINED) as the PE is accessing
449 // the image concurrently with our rendering.
450 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
451 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
454 const vk::VkAttachmentReference colorAttachmentRefs[] =
458 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
461 const vk::VkSubpassDescription subpasses[] =
465 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
469 DE_LENGTH_OF_ARRAY(colorAttachmentRefs),
479 const vk::VkRenderPassCreateInfo createInfo =
481 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
485 DE_LENGTH_OF_ARRAY(attachments),
488 DE_LENGTH_OF_ARRAY(subpasses),
495 return vk::createRenderPass(vkd, device, &createInfo);
498 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd,
500 vk::VkRenderPass renderPass,
501 vk::VkPipelineLayout layout,
502 vk::VkShaderModule vertexShaderModule,
503 vk::VkShaderModule fragmentShaderModule,
507 const vk::VkSpecializationInfo shaderSpecialization =
514 const vk::VkPipelineShaderStageCreateInfo stages[] =
517 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
520 vk::VK_SHADER_STAGE_VERTEX_BIT,
523 &shaderSpecialization
526 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
529 vk::VK_SHADER_STAGE_FRAGMENT_BIT,
530 fragmentShaderModule,
532 &shaderSpecialization
535 const vk::VkPipelineVertexInputStateCreateInfo vertexInputState =
537 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
545 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
547 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
550 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
553 const vk::VkViewport viewports[] =
557 (float)width, (float)height,
561 const vk::VkRect2D scissors[] =
568 const vk::VkPipelineViewportStateCreateInfo viewportState =
570 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
574 DE_LENGTH_OF_ARRAY(viewports),
576 DE_LENGTH_OF_ARRAY(scissors),
579 const vk::VkPipelineRasterizationStateCreateInfo rasterizationState =
581 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
586 vk::VK_POLYGON_MODE_FILL,
587 vk::VK_CULL_MODE_NONE,
588 vk::VK_FRONT_FACE_CLOCKWISE,
595 const vk::VkSampleMask sampleMask = ~0u;
596 const vk::VkPipelineMultisampleStateCreateInfo multisampleState =
598 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
601 vk::VK_SAMPLE_COUNT_1_BIT,
608 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState =
610 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
615 vk::VK_COMPARE_OP_ALWAYS,
619 vk::VK_STENCIL_OP_KEEP,
620 vk::VK_STENCIL_OP_KEEP,
621 vk::VK_STENCIL_OP_KEEP,
622 vk::VK_COMPARE_OP_ALWAYS,
628 vk::VK_STENCIL_OP_KEEP,
629 vk::VK_STENCIL_OP_KEEP,
630 vk::VK_STENCIL_OP_KEEP,
631 vk::VK_COMPARE_OP_ALWAYS,
639 const vk::VkPipelineColorBlendAttachmentState attachmentBlendState =
642 vk::VK_BLEND_FACTOR_ONE,
643 vk::VK_BLEND_FACTOR_ZERO,
645 vk::VK_BLEND_FACTOR_ONE,
646 vk::VK_BLEND_FACTOR_ZERO,
648 (vk::VK_COLOR_COMPONENT_R_BIT|
649 vk::VK_COLOR_COMPONENT_G_BIT|
650 vk::VK_COLOR_COMPONENT_B_BIT|
651 vk::VK_COLOR_COMPONENT_A_BIT),
653 const vk::VkPipelineColorBlendStateCreateInfo blendState =
655 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
659 vk::VK_LOGIC_OP_COPY,
661 &attachmentBlendState,
662 { 0.0f, 0.0f, 0.0f, 0.0f }
664 const vk::VkDynamicState dynamicStates[] =
666 vk::VK_DYNAMIC_STATE_SCISSOR
668 const vk::VkPipelineDynamicStateCreateInfo dynamicState =
670 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
674 DE_LENGTH_OF_ARRAY(dynamicStates),
677 const vk::VkGraphicsPipelineCreateInfo createInfo =
679 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
683 DE_LENGTH_OF_ARRAY(stages),
701 return vk::createGraphicsPipeline(vkd, device, DE_NULL, &createInfo);
704 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vkd,
707 const vk::VkPushConstantRange pushConstants[] =
710 vk::VK_SHADER_STAGE_FRAGMENT_BIT,
715 const vk::VkPipelineLayoutCreateInfo createInfo =
717 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
724 DE_LENGTH_OF_ARRAY(pushConstants),
728 return vk::createPipelineLayout(vkd, device, &createInfo);
733 vk::wsi::Type wsiType;
735 bool useSharedPresentableImage;
736 vk::VkPresentModeKHR presentMode;
739 class SharedPresentableImageTestInstance : public TestInstance
742 SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig);
743 ~SharedPresentableImageTestInstance (void);
745 tcu::TestStatus iterate (void);
748 const TestConfig m_testConfig;
749 const deUint32 m_quadCount;
750 const vk::PlatformInterface& m_vkp;
751 const Extensions m_instanceExtensions;
752 const vk::Unique<vk::VkInstance> m_instance;
753 const vk::InstanceDriver m_vki;
754 const vk::VkPhysicalDevice m_physicalDevice;
755 const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
756 const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
757 const vk::Unique<vk::VkSurfaceKHR> m_surface;
759 const deUint32 m_queueFamilyIndex;
760 const Extensions m_deviceExtensions;
761 const vk::Unique<vk::VkDevice> m_device;
762 const vk::DeviceDriver m_vkd;
763 const vk::VkQueue m_queue;
765 const vk::Unique<vk::VkCommandPool> m_commandPool;
766 const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
767 const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
768 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
770 vk::VkImageUsageFlags m_supportedUsageFlags;
771 const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
772 const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
773 const vector<vk::VkPresentModeKHR> m_presentModes;
775 tcu::ResultCollector m_resultCollector;
777 vk::Move<vk::VkSwapchainKHR> m_swapchain;
778 vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain
779 vk::Move<vk::VkImageView> m_swapchainImageView;
780 vk::Move<vk::VkFramebuffer> m_framebuffer;
782 vk::Move<vk::VkRenderPass> m_renderPass;
783 vk::Move<vk::VkPipeline> m_pipeline;
785 std::vector<vk::VkCommandBuffer> m_commandBuffers;
786 std::vector<vk::VkSemaphore> m_renderSemaphores;
787 std::vector<vk::VkFence> m_fences;
789 std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs;
790 size_t m_swapchainConfigNdx;
792 const size_t m_frameCount;
795 const size_t m_maxOutOfDateCount;
796 size_t m_outOfDateCount;
798 void initSwapchainResources (void);
799 void deinitSwapchainResources (void);
803 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs (vk::VkSurfaceKHR surface,
804 deUint32 queueFamilyIndex,
806 const vk::VkSurfaceCapabilitiesKHR& properties,
807 const vector<vk::VkSurfaceFormatKHR>& formats,
808 const vector<vk::VkPresentModeKHR>& presentModes,
809 vk::VkPresentModeKHR presentMode,
810 vk::VkImageUsageFlags supportedImageUsage)
812 const deUint32 imageLayers = 1u;
813 const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage;
814 const vk::VkBool32 clipped = VK_FALSE;
815 vector<vk::VkSwapchainCreateInfoKHR> createInfos;
817 const deUint32 imageWidth = scaling == SCALING_NONE
818 ? (properties.currentExtent.width != 0xFFFFFFFFu
819 ? properties.currentExtent.width
820 : de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2)))
821 : (scaling == SCALING_UP
822 ? de::max(31u, properties.minImageExtent.width)
823 : properties.maxImageExtent.width);
824 const deUint32 imageHeight = scaling == SCALING_NONE
825 ? (properties.currentExtent.height != 0xFFFFFFFFu
826 ? properties.currentExtent.height
827 : de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2)))
828 : (scaling == SCALING_UP
829 ? de::max(31u, properties.minImageExtent.height)
830 : properties.maxImageExtent.height);
831 const vk::VkExtent2D imageSize = { imageWidth, imageHeight };
834 size_t presentModeNdx;
836 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
838 if (presentModes[presentModeNdx] == presentMode)
842 if (presentModeNdx == presentModes.size())
843 TCU_THROW(NotSupportedError, "Present mode not supported");
846 for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
848 for (vk::VkSurfaceTransformFlagsKHR transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
850 if ((properties.supportedTransforms & transform) == 0)
853 for (vk::VkCompositeAlphaFlagsKHR alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
855 if ((alpha & properties.supportedCompositeAlpha) == 0)
858 const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
859 const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
860 const vk::VkFormat imageFormat = formats[formatNdx].format;
861 const vk::VkColorSpaceKHR imageColorSpace = formats[formatNdx].colorSpace;
862 const vk::VkSwapchainCreateInfoKHR createInfo =
864 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
868 1, // Always 1 image for a shared presentable image swapchain.
874 vk::VK_SHARING_MODE_EXCLUSIVE,
881 (vk::VkSwapchainKHR)0
884 createInfos.push_back(createInfo);
892 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface& vki,
893 vk::VkPhysicalDevice physicalDevice,
894 vk::VkSurfaceKHR surface,
895 vk::VkImageUsageFlags* usage)
897 const vk::VkPhysicalDeviceSurfaceInfo2KHR info =
899 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
904 vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities;
905 vk::VkSurfaceCapabilities2KHR capabilities;
907 sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
908 sharedCapabilities.pNext = DE_NULL;
910 capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
911 capabilities.pNext = &sharedCapabilities;
913 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
915 TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
916 *usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
918 return capabilities.surfaceCapabilities;
921 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig)
922 : TestInstance (context)
923 , m_testConfig (testConfig)
925 , m_vkp (context.getPlatformInterface())
926 , m_instanceExtensions (vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
927 , m_instance (createInstanceWithWsi(m_vkp, m_instanceExtensions, testConfig.wsiType))
928 , m_vki (m_vkp, *m_instance)
929 , m_physicalDevice (vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
930 , m_nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
931 , m_nativeWindow (createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
932 , m_surface (vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
934 , m_queueFamilyIndex (chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
935 , m_deviceExtensions (vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
936 , m_device (createDeviceWithWsi(m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useSharedPresentableImage))
937 , m_vkd (m_vki, *m_device)
938 , m_queue (getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
940 , m_commandPool (createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
941 , m_vertexShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
942 , m_fragmentShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
943 , m_pipelineLayout (createPipelineLayout(m_vkd, *m_device))
945 , m_supportedUsageFlags (0u)
946 , m_surfaceProperties (getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
947 , m_surfaceFormats (vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
948 , m_presentModes (vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
950 , m_swapchainConfigs (generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode, m_supportedUsageFlags))
951 , m_swapchainConfigNdx (0u)
953 , m_frameCount (60u * 5u)
956 , m_maxOutOfDateCount (20u)
957 , m_outOfDateCount (0u)
960 const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
961 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
962 m_context.getTestContext().getLog() << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
967 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance (void)
969 deinitSwapchainResources();
972 void SharedPresentableImageTestInstance::initSwapchainResources (void)
974 const size_t fenceCount = 6;
975 const deUint32 imageWidth = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
976 const deUint32 imageHeight = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
977 const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
979 m_swapchain = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
980 m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
982 m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
983 m_pipeline = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
985 m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
986 m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
988 m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
989 m_fences = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
990 m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
992 initSemaphores(m_vkd, *m_device, m_renderSemaphores);
994 initFences(m_vkd, *m_device, m_fences);
996 // Unlike a traditional swapchain, where we'd acquire a new image from the
997 // PE every frame, a shared image swapchain has a single image that is
998 // acquired upfront. We acquire it here, transition it to the proper layout,
1001 // Acquire the one image
1002 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
1003 vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device));
1004 deUint32 imageIndex = 42; // initialize to junk value
1006 VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
1007 TCU_CHECK(imageIndex == 0);
1009 // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
1010 const vk::VkCommandBufferAllocateInfo allocateInfo =
1012 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1015 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1018 const vk::VkCommandBufferBeginInfo beginInfo =
1020 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1026 const vk::Unique<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
1027 VK_CHECK(m_vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
1029 const vk::VkImageMemoryBarrier barrier = {
1030 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1034 vk::VK_IMAGE_LAYOUT_UNDEFINED,
1035 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
1036 VK_QUEUE_FAMILY_IGNORED,
1037 VK_QUEUE_FAMILY_IGNORED,
1040 vk::VK_IMAGE_ASPECT_COLOR_BIT,
1048 m_vkd.cmdPipelineBarrier(*commandBuffer,
1049 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1050 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1056 VK_CHECK(m_vkd.endCommandBuffer(*commandBuffer));
1058 const vk::VkSubmitInfo submitInfo =
1060 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1062 1, &*semaphore, DE_NULL,
1067 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
1068 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
1071 void SharedPresentableImageTestInstance::deinitSwapchainResources (void)
1073 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
1075 deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
1076 deinitFences(m_vkd, *m_device, m_fences);
1077 deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
1079 m_framebuffer = vk::Move<vk::VkFramebuffer>();
1080 m_swapchainImageView = vk::Move<vk::VkImageView>();
1081 m_swapchainImage = (vk::VkImage)0;
1083 m_swapchain = vk::Move<vk::VkSwapchainKHR>();
1084 m_renderPass = vk::Move<vk::VkRenderPass>();
1085 m_pipeline = vk::Move<vk::VkPipeline>();
1088 void SharedPresentableImageTestInstance::render (void)
1090 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
1091 const vk::VkFence fence = m_fences[m_frameNdx % m_fences.size()];
1092 const deUint32 width = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
1093 const deUint32 height = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
1095 // Throttle execution
1096 if (m_frameNdx >= m_fences.size())
1098 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
1099 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
1101 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
1102 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
1105 deUint32 imageIndex = 0; // There is only one image.
1106 const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
1108 const bool willPresent = m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || !m_frameNdx;
1110 // Create command buffer
1111 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();
1113 // Submit command buffer
1115 const vk::VkSubmitInfo submitInfo =
1117 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1123 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
1124 willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent.
1125 ¤tRenderSemaphore
1128 // With a traditional swapchain, we'd fence on completion of
1129 // AcquireNextImage. We never call that for a shared image swapchain, so
1130 // fence on completion of the rendering work instead. A real shared
1131 // image application would want a more substantial pacing mechanism.
1132 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
1135 // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
1136 // assured the PE has picked up a new frame. The PE /may/ also pick up
1137 // changes whenever it likes.
1139 // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
1140 // first frame to kick things off.
1145 vk::VkResult result;
1146 const vk::VkPresentInfoKHR presentInfo =
1148 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1151 ¤tRenderSemaphore,
1158 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1163 // With either present mode, we can call GetSwapchainStatus at any time
1164 // to detect possible OUT_OF_DATE conditions. Let's do that every frame.
1166 const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
1167 VK_CHECK(swapchainStatus);
1170 tcu::TestStatus SharedPresentableImageTestInstance::iterate (void)
1172 // Initialize swapchain specific resources
1176 if (m_frameNdx == 0)
1178 if (m_outOfDateCount == 0)
1179 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx] << tcu::TestLog::EndMessage;
1181 initSwapchainResources();
1186 catch (const vk::Error& error)
1188 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
1190 m_swapchainConfigs = generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags);
1192 if (m_outOfDateCount < m_maxOutOfDateCount)
1194 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
1195 deinitSwapchainResources();
1199 return tcu::TestStatus::incomplete();
1203 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1204 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1209 m_resultCollector.fail(error.what());
1212 deinitSwapchainResources();
1214 m_swapchainConfigNdx++;
1216 m_outOfDateCount = 0;
1218 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1219 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1221 return tcu::TestStatus::incomplete();
1226 if (m_frameNdx >= m_frameCount)
1229 m_outOfDateCount = 0;
1230 m_swapchainConfigNdx++;
1232 deinitSwapchainResources();
1234 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1235 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1237 return tcu::TestStatus::incomplete();
1240 return tcu::TestStatus::incomplete();
1245 static void init (vk::SourceCollections& dst, TestConfig)
1247 dst.glslSources.add("quad-vert") << glu::VertexSource(
1249 "out gl_PerVertex {\n"
1250 "\tvec4 gl_Position;\n"
1252 "layout(location = 0) out highp uint quadIndex;\n"
1254 "void main (void) {\n"
1255 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1256 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1257 "\tquadIndex = gl_VertexIndex / 6;\n"
1259 dst.glslSources.add("quad-frag") << glu::FragmentSource(
1261 "layout(location = 0) flat in highp uint quadIndex;\n"
1262 "layout(location = 0) out highp vec4 o_color;\n"
1263 "layout(push_constant) uniform PushConstant {\n"
1264 "\thighp uint frameNdx;\n"
1265 "} pushConstants;\n"
1266 "void main (void)\n"
1268 "\thighp uint frameNdx = pushConstants.frameNdx;\n"
1269 "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
1270 "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
1271 "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
1272 "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
1273 "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1274 "\t + 64u * bitfieldExtract(y, 1, 1)\n"
1275 "\t + 32u * bitfieldExtract(x, 3, 1);\n"
1276 "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1277 "\t + 64u * bitfieldExtract(x, 2, 1)\n"
1278 "\t + 32u * bitfieldExtract(y, 3, 1);\n"
1279 "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1280 "\t + 64u * bitfieldExtract(y, 2, 1)\n"
1281 "\t + 32u * bitfieldExtract(x, 4, 1);\n"
1282 "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1289 void createSharedPresentableImageTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1297 { SCALING_NONE, "scale_none" },
1298 { SCALING_UP, "scale_up" },
1299 { SCALING_DOWN, "scale_down" }
1303 vk::VkPresentModeKHR mode;
1307 { vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand" },
1308 { vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous" },
1311 for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
1313 if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
1315 de::MovePtr<tcu::TestCaseGroup> scaleGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name, scaling[scalingNdx].name));
1317 for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1320 const char* const name = presentModes[presentModeNdx].name;
1323 config.wsiType = wsiType;
1324 config.useSharedPresentableImage= true;
1325 config.scaling = scaling[scalingNdx].scaling;
1326 config.presentMode = presentModes[presentModeNdx].mode;
1328 scaleGroup->addChild(new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
1331 testGroup->addChild(scaleGroup.release());