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"
65 typedef vector<vk::VkExtensionProperties> Extensions;
67 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
69 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
70 requiredExtName != requiredExtensions.end();
73 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
74 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
78 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface& vkp,
79 const Extensions& supportedExtensions,
80 vk::wsi::Type wsiType)
82 vector<string> extensions;
84 extensions.push_back("VK_KHR_surface");
85 extensions.push_back("VK_KHR_get_surface_capabilities2");
86 // Required for device extension to expose new physical device bits (in this
87 // case, presentation mode enums)
88 extensions.push_back("VK_KHR_get_physical_device_properties2");
89 extensions.push_back(getExtensionName(wsiType));
91 checkAllSupported(supportedExtensions, extensions);
93 return vk::createDefaultInstance(vkp, vector<string>(), extensions);
96 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
98 vk::VkPhysicalDeviceFeatures features;
99 deMemset(&features, 0, sizeof(features));
103 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
105 deUint32 numFamilies = 0;
107 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
112 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
114 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
115 vector<deUint32> supportedFamilyIndices;
117 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
119 if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
120 supportedFamilyIndices.push_back(queueFamilyNdx);
123 return supportedFamilyIndices;
126 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
128 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
130 if (supportedFamilyIndices.empty())
131 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
133 return supportedFamilyIndices[0];
136 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::InstanceInterface& vki,
137 vk::VkPhysicalDevice physicalDevice,
138 const Extensions& supportedExtensions,
139 const deUint32 queueFamilyIndex,
140 bool requiresSharedPresentableImage,
141 const vk::VkAllocationCallbacks* pAllocator = DE_NULL)
143 const float queuePriorities[] = { 1.0f };
144 const vk::VkDeviceQueueCreateInfo queueInfos[] =
147 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
149 (vk::VkDeviceQueueCreateFlags)0,
151 DE_LENGTH_OF_ARRAY(queuePriorities),
155 const vk::VkPhysicalDeviceFeatures features = getDeviceNullFeatures();
156 const char* const extensions[] =
159 "VK_KHR_shared_presentable_image"
162 const vk::VkDeviceCreateInfo deviceParams =
164 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
166 (vk::VkDeviceCreateFlags)0,
167 DE_LENGTH_OF_ARRAY(queueInfos),
171 requiresSharedPresentableImage ? 2u : 1u,
172 DE_ARRAY_BEGIN(extensions),
176 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
178 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
179 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
182 return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
185 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
186 const Extensions& supportedExtensions,
187 vk::wsi::Type wsiType)
191 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
193 catch (const tcu::NotSupportedError& e)
195 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
197 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
198 // must support creating native display & window for that WSI type.
199 throw tcu::TestError(e.getMessage());
206 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
210 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
212 catch (const tcu::NotSupportedError& e)
214 // See createDisplay - assuming that wsi::Display was supported platform port
215 // should also support creating a window.
216 throw tcu::TestError(e.getMessage());
220 bool wsiTypeSupportsScaling (vk::wsi::Type wsiType)
222 return vk::wsi::getPlatformProperties(wsiType).swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
225 vk::VkQueue getDeviceQueue (const vk::DeviceInterface& vkd, vk::VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex)
227 vk::VkQueue queue = (vk::VkQueue)0;
228 vkd.getDeviceQueue(device, queueFamilyIndex, queueIndex, &queue);
232 vk::Move<vk::VkSemaphore> createSemaphore (const vk::DeviceInterface& vkd,
235 const vk::VkSemaphoreCreateInfo createInfo =
237 vk::VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
241 return vk::createSemaphore(vkd, device, &createInfo);
244 void initSemaphores (const vk::DeviceInterface& vkd,
246 std::vector<vk::VkSemaphore>& semaphores)
248 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
249 semaphores[ndx] = createSemaphore(vkd, device).disown();
252 void deinitSemaphores (const vk::DeviceInterface& vkd,
254 std::vector<vk::VkSemaphore>& semaphores)
256 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
258 if (semaphores[ndx] != (vk::VkSemaphore)0)
259 vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
261 semaphores[ndx] = (vk::VkSemaphore)0;
267 vk::Move<vk::VkFence> createFence (const vk::DeviceInterface& vkd,
270 const vk::VkFenceCreateInfo createInfo =
272 vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
276 return vk::createFence(vkd, device, &createInfo);
279 void initFences (const vk::DeviceInterface& vkd,
281 std::vector<vk::VkFence>& fences)
283 for (size_t ndx = 0; ndx < fences.size(); ndx++)
284 fences[ndx] = createFence(vkd, device).disown();
287 void deinitFences (const vk::DeviceInterface& vkd,
289 std::vector<vk::VkFence>& fences)
291 for (size_t ndx = 0; ndx < fences.size(); ndx++)
293 if (fences[ndx] != (vk::VkFence)0)
294 vkd.destroyFence(device, fences[ndx], DE_NULL);
296 fences[ndx] = (vk::VkFence)0;
302 void cmdRenderFrame (const vk::DeviceInterface& vkd,
303 vk::VkCommandBuffer commandBuffer,
304 vk::VkPipelineLayout pipelineLayout,
305 vk::VkPipeline pipeline,
309 const deUint32 frameNdxValue = (deUint32)frameNdx;
311 vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
312 vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
313 vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
316 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface& vkd,
318 vk::VkCommandPool commandPool,
319 vk::VkPipelineLayout pipelineLayout,
320 vk::VkRenderPass renderPass,
321 vk::VkFramebuffer framebuffer,
322 vk::VkPipeline pipeline,
326 deUint32 imageHeight)
328 const vk::VkCommandBufferAllocateInfo allocateInfo =
330 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
334 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
337 const vk::VkCommandBufferBeginInfo beginInfo =
339 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
345 vk::Move<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(vkd, device, &allocateInfo));
346 VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
349 const vk::VkClearValue clearValue = vk::makeClearValueColorF32(0.25f, 0.50f, 0.75f, 1.00f);
350 const vk::VkRenderPassBeginInfo renderPassBeginInfo =
352 vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
359 { (deInt32)0, (deInt32)0 },
360 { imageWidth, imageHeight }
365 vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
368 cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
370 vkd.cmdEndRenderPass(*commandBuffer);
372 VK_CHECK(vkd.endCommandBuffer(*commandBuffer));
373 return commandBuffer;
376 void deinitCommandBuffers (const vk::DeviceInterface& vkd,
378 vk::VkCommandPool commandPool,
379 std::vector<vk::VkCommandBuffer>& commandBuffers)
381 for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
383 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
384 vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
386 commandBuffers[ndx] = (vk::VkCommandBuffer)0;
389 commandBuffers.clear();
392 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vkd,
394 deUint32 queueFamilyIndex)
396 const vk::VkCommandPoolCreateInfo createInfo =
398 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
404 return vk::createCommandPool(vkd, device, &createInfo);
407 vk::Move<vk::VkFramebuffer> createFramebuffer (const vk::DeviceInterface& vkd,
409 vk::VkRenderPass renderPass,
410 vk::VkImageView imageView,
414 const vk::VkFramebufferCreateInfo createInfo =
416 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
428 return vk::createFramebuffer(vkd, device, &createInfo);
431 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd,
436 const vk::VkImageViewCreateInfo createInfo =
438 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
443 vk::VK_IMAGE_VIEW_TYPE_2D,
445 vk::makeComponentMappingRGBA(),
447 vk::VK_IMAGE_ASPECT_COLOR_BIT,
455 return vk::createImageView(vkd, device, &createInfo, DE_NULL);
458 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
462 const vk::VkAttachmentDescription attachments[] =
467 vk::VK_SAMPLE_COUNT_1_BIT,
469 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
470 vk::VK_ATTACHMENT_STORE_OP_STORE,
472 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
473 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
475 // This differs from the usual layout handling in that the
476 // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
477 // the time. We should not ever transition it away (or discard the
478 // contents with a transition from UNDEFINED) as the PE is accessing
479 // the image concurrently with our rendering.
480 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
481 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
484 const vk::VkAttachmentReference colorAttachmentRefs[] =
488 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
491 const vk::VkSubpassDescription subpasses[] =
495 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
499 DE_LENGTH_OF_ARRAY(colorAttachmentRefs),
509 const vk::VkRenderPassCreateInfo createInfo =
511 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
515 DE_LENGTH_OF_ARRAY(attachments),
518 DE_LENGTH_OF_ARRAY(subpasses),
525 return vk::createRenderPass(vkd, device, &createInfo);
528 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd,
530 vk::VkRenderPass renderPass,
531 vk::VkPipelineLayout layout,
532 vk::VkShaderModule vertexShaderModule,
533 vk::VkShaderModule fragmentShaderModule,
537 const vk::VkSpecializationInfo shaderSpecialization =
544 const vk::VkPipelineShaderStageCreateInfo stages[] =
547 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
550 vk::VK_SHADER_STAGE_VERTEX_BIT,
553 &shaderSpecialization
556 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
559 vk::VK_SHADER_STAGE_FRAGMENT_BIT,
560 fragmentShaderModule,
562 &shaderSpecialization
565 const vk::VkPipelineVertexInputStateCreateInfo vertexInputState =
567 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
575 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
577 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
580 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
583 const vk::VkViewport viewports[] =
587 (float)width, (float)height,
591 const vk::VkRect2D scissors[] =
598 const vk::VkPipelineViewportStateCreateInfo viewportState =
600 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
604 DE_LENGTH_OF_ARRAY(viewports),
606 DE_LENGTH_OF_ARRAY(scissors),
609 const vk::VkPipelineRasterizationStateCreateInfo rasterizationState =
611 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
616 vk::VK_POLYGON_MODE_FILL,
617 vk::VK_CULL_MODE_NONE,
618 vk::VK_FRONT_FACE_CLOCKWISE,
625 const vk::VkSampleMask sampleMask = ~0u;
626 const vk::VkPipelineMultisampleStateCreateInfo multisampleState =
628 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
631 vk::VK_SAMPLE_COUNT_1_BIT,
638 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState =
640 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
645 vk::VK_COMPARE_OP_ALWAYS,
649 vk::VK_STENCIL_OP_KEEP,
650 vk::VK_STENCIL_OP_KEEP,
651 vk::VK_STENCIL_OP_KEEP,
652 vk::VK_COMPARE_OP_ALWAYS,
658 vk::VK_STENCIL_OP_KEEP,
659 vk::VK_STENCIL_OP_KEEP,
660 vk::VK_STENCIL_OP_KEEP,
661 vk::VK_COMPARE_OP_ALWAYS,
669 const vk::VkPipelineColorBlendAttachmentState attachmentBlendState =
672 vk::VK_BLEND_FACTOR_ONE,
673 vk::VK_BLEND_FACTOR_ZERO,
675 vk::VK_BLEND_FACTOR_ONE,
676 vk::VK_BLEND_FACTOR_ZERO,
678 (vk::VK_COLOR_COMPONENT_R_BIT|
679 vk::VK_COLOR_COMPONENT_G_BIT|
680 vk::VK_COLOR_COMPONENT_B_BIT|
681 vk::VK_COLOR_COMPONENT_A_BIT),
683 const vk::VkPipelineColorBlendStateCreateInfo blendState =
685 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
689 vk::VK_LOGIC_OP_COPY,
691 &attachmentBlendState,
692 { 0.0f, 0.0f, 0.0f, 0.0f }
694 const vk::VkDynamicState dynamicStates[] =
696 vk::VK_DYNAMIC_STATE_SCISSOR
698 const vk::VkPipelineDynamicStateCreateInfo dynamicState =
700 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
704 DE_LENGTH_OF_ARRAY(dynamicStates),
707 const vk::VkGraphicsPipelineCreateInfo createInfo =
709 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
713 DE_LENGTH_OF_ARRAY(stages),
731 return vk::createGraphicsPipeline(vkd, device, DE_NULL, &createInfo);
734 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vkd,
737 const vk::VkPushConstantRange pushConstants[] =
740 vk::VK_SHADER_STAGE_FRAGMENT_BIT,
745 const vk::VkPipelineLayoutCreateInfo createInfo =
747 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
754 DE_LENGTH_OF_ARRAY(pushConstants),
758 return vk::createPipelineLayout(vkd, device, &createInfo);
763 vk::wsi::Type wsiType;
765 bool useSharedPresentableImage;
766 vk::VkPresentModeKHR presentMode;
769 class SharedPresentableImageTestInstance : public TestInstance
772 SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig);
773 ~SharedPresentableImageTestInstance (void);
775 tcu::TestStatus iterate (void);
778 const TestConfig m_testConfig;
779 const deUint32 m_quadCount;
780 const vk::PlatformInterface& m_vkp;
781 const Extensions m_instanceExtensions;
782 const vk::Unique<vk::VkInstance> m_instance;
783 const vk::InstanceDriver m_vki;
784 const vk::VkPhysicalDevice m_physicalDevice;
785 const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
786 const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
787 const vk::Unique<vk::VkSurfaceKHR> m_surface;
789 const deUint32 m_queueFamilyIndex;
790 const Extensions m_deviceExtensions;
791 const vk::Unique<vk::VkDevice> m_device;
792 const vk::DeviceDriver m_vkd;
793 const vk::VkQueue m_queue;
795 const vk::Unique<vk::VkCommandPool> m_commandPool;
796 const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
797 const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
798 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
800 vk::VkImageUsageFlags m_supportedUsageFlags;
801 const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
802 const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
803 const vector<vk::VkPresentModeKHR> m_presentModes;
805 tcu::ResultCollector m_resultCollector;
807 vk::Move<vk::VkSwapchainKHR> m_swapchain;
808 vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain
809 vk::Move<vk::VkImageView> m_swapchainImageView;
810 vk::Move<vk::VkFramebuffer> m_framebuffer;
812 vk::Move<vk::VkRenderPass> m_renderPass;
813 vk::Move<vk::VkPipeline> m_pipeline;
815 std::vector<vk::VkCommandBuffer> m_commandBuffers;
816 std::vector<vk::VkSemaphore> m_renderSemaphores;
817 std::vector<vk::VkFence> m_fences;
819 std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs;
820 size_t m_swapchainConfigNdx;
822 const size_t m_frameCount;
825 const size_t m_maxOutOfDateCount;
826 size_t m_outOfDateCount;
828 void initSwapchainResources (void);
829 void deinitSwapchainResources (void);
833 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs (vk::VkSurfaceKHR surface,
834 deUint32 queueFamilyIndex,
836 const vk::VkSurfaceCapabilitiesKHR& properties,
837 const vector<vk::VkSurfaceFormatKHR>& formats,
838 const vector<vk::VkPresentModeKHR>& presentModes,
839 vk::VkPresentModeKHR presentMode,
840 vk::VkImageUsageFlags supportedImageUsage)
842 const deUint32 imageLayers = 1u;
843 const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage;
844 const vk::VkBool32 clipped = VK_FALSE;
845 vector<vk::VkSwapchainCreateInfoKHR> createInfos;
847 const deUint32 imageWidth = scaling == SCALING_NONE
848 ? (properties.currentExtent.width != 0xFFFFFFFFu
849 ? properties.currentExtent.width
850 : de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2)))
851 : (scaling == SCALING_UP
852 ? de::max(31u, properties.minImageExtent.width)
853 : properties.maxImageExtent.width);
854 const deUint32 imageHeight = scaling == SCALING_NONE
855 ? (properties.currentExtent.height != 0xFFFFFFFFu
856 ? properties.currentExtent.height
857 : de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2)))
858 : (scaling == SCALING_UP
859 ? de::max(31u, properties.minImageExtent.height)
860 : properties.maxImageExtent.height);
861 const vk::VkExtent2D imageSize = { imageWidth, imageHeight };
864 size_t presentModeNdx;
866 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
868 if (presentModes[presentModeNdx] == presentMode)
872 if (presentModeNdx == presentModes.size())
873 TCU_THROW(NotSupportedError, "Present mode not supported");
876 for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
878 for (vk::VkSurfaceTransformFlagsKHR transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
880 if ((properties.supportedTransforms & transform) == 0)
883 for (vk::VkCompositeAlphaFlagsKHR alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
885 if ((alpha & properties.supportedCompositeAlpha) == 0)
888 const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
889 const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
890 const vk::VkFormat imageFormat = formats[formatNdx].format;
891 const vk::VkColorSpaceKHR imageColorSpace = formats[formatNdx].colorSpace;
892 const vk::VkSwapchainCreateInfoKHR createInfo =
894 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
898 1, // Always 1 image for a shared presentable image swapchain.
904 vk::VK_SHARING_MODE_EXCLUSIVE,
911 (vk::VkSwapchainKHR)0
914 createInfos.push_back(createInfo);
922 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface& vki,
923 vk::VkPhysicalDevice physicalDevice,
924 vk::VkSurfaceKHR surface,
925 vk::VkImageUsageFlags* usage)
927 const vk::VkPhysicalDeviceSurfaceInfo2KHR info =
929 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
934 vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities;
935 vk::VkSurfaceCapabilities2KHR capabilities;
937 sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
938 sharedCapabilities.pNext = DE_NULL;
940 capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
941 capabilities.pNext = &sharedCapabilities;
943 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
945 TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
946 *usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
948 return capabilities.surfaceCapabilities;
951 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig)
952 : TestInstance (context)
953 , m_testConfig (testConfig)
955 , m_vkp (context.getPlatformInterface())
956 , m_instanceExtensions (vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
957 , m_instance (createInstanceWithWsi(m_vkp, m_instanceExtensions, testConfig.wsiType))
958 , m_vki (m_vkp, *m_instance)
959 , m_physicalDevice (vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
960 , m_nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
961 , m_nativeWindow (createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
962 , m_surface (vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
964 , m_queueFamilyIndex (chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
965 , m_deviceExtensions (vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
966 , m_device (createDeviceWithWsi(m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useSharedPresentableImage))
967 , m_vkd (m_vki, *m_device)
968 , m_queue (getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
970 , m_commandPool (createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
971 , m_vertexShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
972 , m_fragmentShaderModule (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
973 , m_pipelineLayout (createPipelineLayout(m_vkd, *m_device))
975 , m_supportedUsageFlags (0u)
976 , m_surfaceProperties (getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
977 , m_surfaceFormats (vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
978 , m_presentModes (vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
980 , m_swapchainConfigs (generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode, m_supportedUsageFlags))
981 , m_swapchainConfigNdx (0u)
983 , m_frameCount (60u * 5u)
986 , m_maxOutOfDateCount (20u)
987 , m_outOfDateCount (0u)
990 const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
991 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
992 m_context.getTestContext().getLog() << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
997 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance (void)
999 deinitSwapchainResources();
1002 void SharedPresentableImageTestInstance::initSwapchainResources (void)
1004 const size_t fenceCount = 6;
1005 const deUint32 imageWidth = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
1006 const deUint32 imageHeight = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
1007 const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
1009 m_swapchain = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
1010 m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
1012 m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
1013 m_pipeline = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
1015 m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
1016 m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
1018 m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
1019 m_fences = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
1020 m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
1022 initSemaphores(m_vkd, *m_device, m_renderSemaphores);
1024 initFences(m_vkd, *m_device, m_fences);
1026 // Unlike a traditional swapchain, where we'd acquire a new image from the
1027 // PE every frame, a shared image swapchain has a single image that is
1028 // acquired upfront. We acquire it here, transition it to the proper layout,
1031 // Acquire the one image
1032 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
1033 vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device));
1034 deUint32 imageIndex = 42; // initialize to junk value
1036 VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
1037 TCU_CHECK(imageIndex == 0);
1039 // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
1040 const vk::VkCommandBufferAllocateInfo allocateInfo =
1042 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1045 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1048 const vk::VkCommandBufferBeginInfo beginInfo =
1050 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1056 const vk::Unique<vk::VkCommandBuffer> commandBuffer (vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
1057 VK_CHECK(m_vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
1059 const vk::VkImageMemoryBarrier barrier = {
1060 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1064 vk::VK_IMAGE_LAYOUT_UNDEFINED,
1065 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
1066 VK_QUEUE_FAMILY_IGNORED,
1067 VK_QUEUE_FAMILY_IGNORED,
1070 vk::VK_IMAGE_ASPECT_COLOR_BIT,
1078 m_vkd.cmdPipelineBarrier(*commandBuffer,
1079 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1080 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1086 VK_CHECK(m_vkd.endCommandBuffer(*commandBuffer));
1088 const vk::VkSubmitInfo submitInfo =
1090 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1092 1, &*semaphore, DE_NULL,
1097 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
1098 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
1101 void SharedPresentableImageTestInstance::deinitSwapchainResources (void)
1103 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
1105 deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
1106 deinitFences(m_vkd, *m_device, m_fences);
1107 deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
1109 m_framebuffer = vk::Move<vk::VkFramebuffer>();
1110 m_swapchainImageView = vk::Move<vk::VkImageView>();
1111 m_swapchainImage = (vk::VkImage)0;
1113 m_swapchain = vk::Move<vk::VkSwapchainKHR>();
1114 m_renderPass = vk::Move<vk::VkRenderPass>();
1115 m_pipeline = vk::Move<vk::VkPipeline>();
1118 void SharedPresentableImageTestInstance::render (void)
1120 const deUint64 foreverNs = 0xFFFFFFFFFFFFFFFFul;
1121 const vk::VkFence fence = m_fences[m_frameNdx % m_fences.size()];
1122 const deUint32 width = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
1123 const deUint32 height = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
1125 // Throttle execution
1126 if (m_frameNdx >= m_fences.size())
1128 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
1129 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
1131 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
1132 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
1135 deUint32 imageIndex = 0; // There is only one image.
1136 const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
1138 const bool willPresent = m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || !m_frameNdx;
1140 // Create command buffer
1141 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();
1143 // Submit command buffer
1145 const vk::VkSubmitInfo submitInfo =
1147 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1153 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
1154 willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent.
1155 ¤tRenderSemaphore
1158 // With a traditional swapchain, we'd fence on completion of
1159 // AcquireNextImage. We never call that for a shared image swapchain, so
1160 // fence on completion of the rendering work instead. A real shared
1161 // image application would want a more substantial pacing mechanism.
1162 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
1165 // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
1166 // assured the PE has picked up a new frame. The PE /may/ also pick up
1167 // changes whenever it likes.
1169 // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
1170 // first frame to kick things off.
1175 vk::VkResult result;
1176 const vk::VkPresentInfoKHR presentInfo =
1178 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1181 ¤tRenderSemaphore,
1188 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1193 // With either present mode, we can call GetSwapchainStatus at any time
1194 // to detect possible OUT_OF_DATE conditions. Let's do that every frame.
1196 const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
1197 VK_CHECK(swapchainStatus);
1200 tcu::TestStatus SharedPresentableImageTestInstance::iterate (void)
1202 // Initialize swapchain specific resources
1206 if (m_frameNdx == 0)
1208 if (m_outOfDateCount == 0)
1209 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx] << tcu::TestLog::EndMessage;
1211 initSwapchainResources();
1216 catch (const vk::Error& error)
1218 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
1220 m_swapchainConfigs = generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags);
1222 if (m_outOfDateCount < m_maxOutOfDateCount)
1224 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
1225 deinitSwapchainResources();
1229 return tcu::TestStatus::incomplete();
1233 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1234 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1239 m_resultCollector.fail(error.what());
1242 deinitSwapchainResources();
1244 m_swapchainConfigNdx++;
1246 m_outOfDateCount = 0;
1248 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1249 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1251 return tcu::TestStatus::incomplete();
1256 if (m_frameNdx >= m_frameCount)
1259 m_outOfDateCount = 0;
1260 m_swapchainConfigNdx++;
1262 deinitSwapchainResources();
1264 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
1265 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1267 return tcu::TestStatus::incomplete();
1270 return tcu::TestStatus::incomplete();
1275 static void init (vk::SourceCollections& dst, TestConfig)
1277 dst.glslSources.add("quad-vert") << glu::VertexSource(
1279 "out gl_PerVertex {\n"
1280 "\tvec4 gl_Position;\n"
1282 "layout(location = 0) out highp uint quadIndex;\n"
1284 "void main (void) {\n"
1285 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1286 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1287 "\tquadIndex = gl_VertexIndex / 6;\n"
1289 dst.glslSources.add("quad-frag") << glu::FragmentSource(
1291 "layout(location = 0) flat in highp uint quadIndex;\n"
1292 "layout(location = 0) out highp vec4 o_color;\n"
1293 "layout(push_constant) uniform PushConstant {\n"
1294 "\thighp uint frameNdx;\n"
1295 "} pushConstants;\n"
1296 "void main (void)\n"
1298 "\thighp uint frameNdx = pushConstants.frameNdx;\n"
1299 "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
1300 "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
1301 "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
1302 "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
1303 "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1304 "\t + 64u * bitfieldExtract(y, 1, 1)\n"
1305 "\t + 32u * bitfieldExtract(x, 3, 1);\n"
1306 "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1307 "\t + 64u * bitfieldExtract(x, 2, 1)\n"
1308 "\t + 32u * bitfieldExtract(y, 3, 1);\n"
1309 "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1310 "\t + 64u * bitfieldExtract(y, 2, 1)\n"
1311 "\t + 32u * bitfieldExtract(x, 4, 1);\n"
1312 "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1319 void createSharedPresentableImageTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1327 { SCALING_NONE, "scale_none" },
1328 { SCALING_UP, "scale_up" },
1329 { SCALING_DOWN, "scale_down" }
1333 vk::VkPresentModeKHR mode;
1337 { vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand" },
1338 { vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous" },
1341 for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
1343 if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
1345 de::MovePtr<tcu::TestCaseGroup> scaleGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name, scaling[scalingNdx].name));
1347 for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1350 const char* const name = presentModes[presentModeNdx].name;
1353 config.wsiType = wsiType;
1354 config.useSharedPresentableImage= true;
1355 config.scaling = scaling[scalingNdx].scaling;
1356 config.presentMode = presentModes[presentModeNdx].mode;
1358 scaleGroup->addChild(new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
1361 testGroup->addChild(scaleGroup.release());