1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Tests for shared presentable image extension
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSharedPresentableImageTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkWsiPlatform.hpp"
31 #include "vkWsiUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkDeviceUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkObjUtil.hpp"
39
40 #include "vkWsiUtil.hpp"
41
42 #include "tcuPlatform.hpp"
43 #include "tcuResultCollector.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuCommandLine.hpp"
46
47 #include <vector>
48 #include <string>
49
50 using std::string;
51 using std::vector;
52
53 using tcu::Maybe;
54 using tcu::TestLog;
55 using tcu::UVec2;
56
57 namespace vkt
58 {
59 namespace wsi
60 {
61 namespace
62 {
63 enum Scaling
64 {
65 SCALING_NONE,
66 SCALING_UP,
67 SCALING_DOWN
68 };
69
70 typedef vector<vk::VkExtensionProperties> Extensions;
71
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)72 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
73 {
74 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
75 requiredExtName != requiredExtensions.end(); ++requiredExtName)
76 {
77 if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79 }
80 }
81
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,vk::wsi::Type wsiType)82 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, vk::wsi::Type wsiType)
83 {
84 const uint32_t version = context.getUsedApiVersion();
85 vector<string> extensions;
86
87 if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
88 extensions.push_back("VK_KHR_get_physical_device_properties2");
89
90 extensions.push_back("VK_KHR_surface");
91 extensions.push_back("VK_KHR_get_surface_capabilities2");
92 // Required for device extension to expose new physical device bits (in this
93 // case, presentation mode enums)
94 extensions.push_back(getExtensionName(wsiType));
95 if (isDisplaySurface(wsiType))
96 extensions.push_back("VK_KHR_display");
97
98 checkAllSupported(supportedExtensions, extensions);
99
100 return vkt::createCustomInstanceWithExtensions(context, extensions);
101 }
102
getDeviceNullFeatures(void)103 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures(void)
104 {
105 vk::VkPhysicalDeviceFeatures features;
106 deMemset(&features, 0, sizeof(features));
107 return features;
108 }
109
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const uint32_t queueFamilyIndex,bool requiresSharedPresentableImage,bool validationEnabled,const vk::VkAllocationCallbacks * pAllocator=DE_NULL)110 vk::Move<vk::VkDevice> createDeviceWithWsi(const vk::PlatformInterface &vkp, vk::VkInstance instance,
111 const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
112 const Extensions &supportedExtensions, const uint32_t queueFamilyIndex,
113 bool requiresSharedPresentableImage, bool validationEnabled,
114 const vk::VkAllocationCallbacks *pAllocator = DE_NULL)
115 {
116 const float queuePriorities[] = {1.0f};
117 const vk::VkDeviceQueueCreateInfo queueInfos[] = {{vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
118 (vk::VkDeviceQueueCreateFlags)0, queueFamilyIndex,
119 DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
120 const vk::VkPhysicalDeviceFeatures features = getDeviceNullFeatures();
121 const char *const extensions[] = {"VK_KHR_swapchain", "VK_KHR_shared_presentable_image"};
122
123 const vk::VkDeviceCreateInfo deviceParams = {vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
124 DE_NULL,
125 (vk::VkDeviceCreateFlags)0,
126 DE_LENGTH_OF_ARRAY(queueInfos),
127 &queueInfos[0],
128 0u,
129 DE_NULL,
130 requiresSharedPresentableImage ? 2u : 1u,
131 DE_ARRAY_BEGIN(extensions),
132 &features};
133
134 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
135 {
136 if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
137 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
138 }
139
140 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
141 }
142
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)143 de::MovePtr<vk::wsi::Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions,
144 vk::wsi::Type wsiType)
145 {
146 try
147 {
148 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
149 }
150 catch (const tcu::NotSupportedError &e)
151 {
152 if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
153 platform.hasDisplay(wsiType))
154 {
155 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
156 // must support creating native display & window for that WSI type.
157 throw tcu::TestError(e.getMessage());
158 }
159 else
160 throw;
161 }
162 }
163
createWindow(const vk::wsi::Display & display,const Maybe<UVec2> & initialSize)164 de::MovePtr<vk::wsi::Window> createWindow(const vk::wsi::Display &display, const Maybe<UVec2> &initialSize)
165 {
166 try
167 {
168 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
169 }
170 catch (const tcu::NotSupportedError &e)
171 {
172 // See createDisplay - assuming that wsi::Display was supported platform port
173 // should also support creating a window.
174 throw tcu::TestError(e.getMessage());
175 }
176 }
177
wsiTypeSupportsScaling(vk::wsi::Type wsiType)178 bool wsiTypeSupportsScaling(vk::wsi::Type wsiType)
179 {
180 return vk::wsi::getPlatformProperties(wsiType).swapchainExtent ==
181 vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
182 }
183
initSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)184 void initSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
185 {
186 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
187 semaphores[ndx] = createSemaphore(vkd, device).disown();
188 }
189
deinitSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)190 void deinitSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
191 {
192 for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
193 {
194 if (semaphores[ndx] != (vk::VkSemaphore)0)
195 vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
196
197 semaphores[ndx] = (vk::VkSemaphore)0;
198 }
199
200 semaphores.clear();
201 }
202
initFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)203 void initFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
204 {
205 for (size_t ndx = 0; ndx < fences.size(); ndx++)
206 fences[ndx] = createFence(vkd, device).disown();
207 }
208
deinitFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)209 void deinitFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
210 {
211 for (size_t ndx = 0; ndx < fences.size(); ndx++)
212 {
213 if (fences[ndx] != (vk::VkFence)0)
214 vkd.destroyFence(device, fences[ndx], DE_NULL);
215
216 fences[ndx] = (vk::VkFence)0;
217 }
218
219 fences.clear();
220 }
221
cmdRenderFrame(const vk::DeviceInterface & vkd,vk::VkCommandBuffer commandBuffer,vk::VkPipelineLayout pipelineLayout,vk::VkPipeline pipeline,size_t frameNdx,uint32_t quadCount)222 void cmdRenderFrame(const vk::DeviceInterface &vkd, vk::VkCommandBuffer commandBuffer,
223 vk::VkPipelineLayout pipelineLayout, vk::VkPipeline pipeline, size_t frameNdx, uint32_t quadCount)
224 {
225 const uint32_t frameNdxValue = (uint32_t)frameNdx;
226
227 vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
228 vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
229 vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
230 }
231
createCommandBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass,vk::VkFramebuffer framebuffer,vk::VkPipeline pipeline,size_t frameNdx,uint32_t quadCount,uint32_t imageWidth,uint32_t imageHeight)232 vk::Move<vk::VkCommandBuffer> createCommandBuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
233 vk::VkCommandPool commandPool, vk::VkPipelineLayout pipelineLayout,
234 vk::VkRenderPass renderPass, vk::VkFramebuffer framebuffer,
235 vk::VkPipeline pipeline, size_t frameNdx, uint32_t quadCount,
236 uint32_t imageWidth, uint32_t imageHeight)
237 {
238 const vk::VkCommandBufferAllocateInfo allocateInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
239
240 commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
241
242 vk::Move<vk::VkCommandBuffer> commandBuffer(vk::allocateCommandBuffer(vkd, device, &allocateInfo));
243 beginCommandBuffer(vkd, *commandBuffer, 0u);
244
245 beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, vk::makeRect2D(0, 0, imageWidth, imageHeight),
246 tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
247
248 cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
249
250 endRenderPass(vkd, *commandBuffer);
251
252 endCommandBuffer(vkd, *commandBuffer);
253 return commandBuffer;
254 }
255
deinitCommandBuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,std::vector<vk::VkCommandBuffer> & commandBuffers)256 void deinitCommandBuffers(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool commandPool,
257 std::vector<vk::VkCommandBuffer> &commandBuffers)
258 {
259 for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
260 {
261 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
262 vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
263
264 commandBuffers[ndx] = (vk::VkCommandBuffer)0;
265 }
266
267 commandBuffers.clear();
268 }
269
createCommandPool(const vk::DeviceInterface & vkd,vk::VkDevice device,uint32_t queueFamilyIndex)270 vk::Move<vk::VkCommandPool> createCommandPool(const vk::DeviceInterface &vkd, vk::VkDevice device,
271 uint32_t queueFamilyIndex)
272 {
273 const vk::VkCommandPoolCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, DE_NULL, 0u,
274 queueFamilyIndex};
275
276 return vk::createCommandPool(vkd, device, &createInfo);
277 }
278
createFramebuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkImageView imageView,uint32_t width,uint32_t height)279 vk::Move<vk::VkFramebuffer> createFramebuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
280 vk::VkRenderPass renderPass, vk::VkImageView imageView, uint32_t width,
281 uint32_t height)
282 {
283 const vk::VkFramebufferCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
284 DE_NULL,
285
286 0u,
287 renderPass,
288 1u,
289 &imageView,
290 width,
291 height,
292 1u};
293
294 return vk::createFramebuffer(vkd, device, &createInfo);
295 }
296
createImageView(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,vk::VkFormat format)297 vk::Move<vk::VkImageView> createImageView(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkImage image,
298 vk::VkFormat format)
299 {
300 const vk::VkImageViewCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
301 DE_NULL,
302
303 0u,
304 image,
305 vk::VK_IMAGE_VIEW_TYPE_2D,
306 format,
307 vk::makeComponentMappingRGBA(),
308 {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
309
310 return vk::createImageView(vkd, device, &createInfo, DE_NULL);
311 }
312
createRenderPass(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format)313 vk::Move<vk::VkRenderPass> createRenderPass(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkFormat format)
314 {
315 const vk::VkAttachmentDescription attachments[] = {
316 {0u, format, vk::VK_SAMPLE_COUNT_1_BIT,
317
318 vk::VK_ATTACHMENT_LOAD_OP_LOAD, vk::VK_ATTACHMENT_STORE_OP_STORE,
319
320 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
321
322 // This differs from the usual layout handling in that the
323 // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
324 // the time. We should not ever transition it away (or discard the
325 // contents with a transition from UNDEFINED) as the PE is accessing
326 // the image concurrently with our rendering.
327 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR}};
328 const vk::VkAttachmentReference colorAttachmentRefs[] = {{0u, vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR}};
329 const vk::VkSubpassDescription subpasses[] = {{0u, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, DE_NULL,
330
331 DE_LENGTH_OF_ARRAY(colorAttachmentRefs), colorAttachmentRefs,
332 DE_NULL,
333
334 DE_NULL, 0u, DE_NULL}};
335
336 const vk::VkRenderPassCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
337 DE_NULL,
338 0u,
339
340 DE_LENGTH_OF_ARRAY(attachments),
341 attachments,
342
343 DE_LENGTH_OF_ARRAY(subpasses),
344 subpasses,
345
346 0u,
347 DE_NULL};
348
349 return vk::createRenderPass(vkd, device, &createInfo);
350 }
351
createPipeline(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkPipelineLayout layout,vk::VkShaderModule vertexShaderModule,vk::VkShaderModule fragmentShaderModule,uint32_t width,uint32_t height)352 vk::Move<vk::VkPipeline> createPipeline(const vk::DeviceInterface &vkd, vk::VkDevice device,
353 vk::VkRenderPass renderPass, vk::VkPipelineLayout layout,
354 vk::VkShaderModule vertexShaderModule, vk::VkShaderModule fragmentShaderModule,
355 uint32_t width, uint32_t height)
356 {
357 const vk::VkPipelineVertexInputStateCreateInfo vertexInputState = {
358 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, 0u, 0u, DE_NULL, 0u, DE_NULL};
359 const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(tcu::UVec2(width, height)));
360 const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(tcu::UVec2(width, height)));
361
362 return vk::makeGraphicsPipeline(
363 vkd, // const DeviceInterface& vk
364 device, // const VkDevice device
365 layout, // const VkPipelineLayout pipelineLayout
366 vertexShaderModule, // const VkShaderModule vertexShaderModule
367 DE_NULL, // const VkShaderModule tessellationControlShaderModule
368 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
369 DE_NULL, // const VkShaderModule geometryShaderModule
370 fragmentShaderModule, // const VkShaderModule fragmentShaderModule
371 renderPass, // const VkRenderPass renderPass
372 viewports, // const std::vector<VkViewport>& viewports
373 scissors, // const std::vector<VkRect2D>& scissors
374 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
375 0u, // const uint32_t subpass
376 0u, // const uint32_t patchControlPoints
377 &vertexInputState); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
378 }
379
createPipelineLayout(const vk::DeviceInterface & vkd,vk::VkDevice device)380 vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface &vkd, vk::VkDevice device)
381 {
382 const vk::VkPushConstantRange pushConstants[] = {{vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u}};
383 const vk::VkPipelineLayoutCreateInfo createInfo = {
384 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
385 DE_NULL,
386 0u,
387
388 0u,
389 DE_NULL,
390
391 DE_LENGTH_OF_ARRAY(pushConstants),
392 pushConstants,
393 };
394
395 return vk::createPipelineLayout(vkd, device, &createInfo);
396 }
397
398 struct TestConfig
399 {
400 vk::wsi::Type wsiType;
401 Scaling scaling;
402 bool useSharedPresentableImage;
403 vk::VkPresentModeKHR presentMode;
404 vk::VkSurfaceTransformFlagsKHR transform;
405 vk::VkCompositeAlphaFlagsKHR alpha;
406 };
407
408 class SharedPresentableImageTestInstance : public TestInstance
409 {
410 public:
411 SharedPresentableImageTestInstance(Context &context, const TestConfig &testConfig);
412 ~SharedPresentableImageTestInstance(void);
413
414 tcu::TestStatus iterate(void);
415
416 private:
417 const TestConfig m_testConfig;
418 const uint32_t m_quadCount;
419 const vk::PlatformInterface &m_vkp;
420 const Extensions m_instanceExtensions;
421 const CustomInstance m_instance;
422 const vk::InstanceDriver &m_vki;
423 const vk::VkPhysicalDevice m_physicalDevice;
424 const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
425 const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
426 const vk::Unique<vk::VkSurfaceKHR> m_surface;
427
428 const uint32_t m_queueFamilyIndex;
429 const Extensions m_deviceExtensions;
430 const vk::Unique<vk::VkDevice> m_device;
431 const vk::DeviceDriver m_vkd;
432 const vk::VkQueue m_queue;
433
434 const vk::Unique<vk::VkCommandPool> m_commandPool;
435 const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
436 const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
437 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
438
439 vk::VkImageUsageFlags m_supportedUsageFlags;
440 const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
441 const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
442 const vector<vk::VkPresentModeKHR> m_presentModes;
443
444 tcu::ResultCollector m_resultCollector;
445
446 vk::Move<vk::VkSwapchainKHR> m_swapchain;
447 vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain
448 vk::Move<vk::VkImageView> m_swapchainImageView;
449 vk::Move<vk::VkFramebuffer> m_framebuffer;
450
451 vk::Move<vk::VkRenderPass> m_renderPass;
452 vk::Move<vk::VkPipeline> m_pipeline;
453
454 std::vector<vk::VkCommandBuffer> m_commandBuffers;
455 std::vector<vk::VkSemaphore> m_renderSemaphores;
456 std::vector<vk::VkFence> m_fences;
457
458 std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs;
459 size_t m_swapchainConfigNdx;
460
461 const size_t m_frameCount;
462 size_t m_frameNdx;
463
464 const size_t m_maxOutOfDateCount;
465 size_t m_outOfDateCount;
466
467 void initSwapchainResources(void);
468 void deinitSwapchainResources(void);
469 void render(void);
470 };
471
generateSwapchainConfigs(const vk::InstanceDriver & vki,const vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,uint32_t queueFamilyIndex,Scaling scaling,const vk::VkSurfaceCapabilitiesKHR & properties,const vector<vk::VkSurfaceFormatKHR> & formats,const vector<vk::VkPresentModeKHR> & presentModes,vk::VkPresentModeKHR presentMode,vk::VkImageUsageFlags supportedImageUsage,const vk::VkSurfaceTransformFlagsKHR transform,const vk::VkCompositeAlphaFlagsKHR alpha)472 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs(
473 const vk::InstanceDriver &vki, const vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface,
474 uint32_t queueFamilyIndex, Scaling scaling, const vk::VkSurfaceCapabilitiesKHR &properties,
475 const vector<vk::VkSurfaceFormatKHR> &formats, const vector<vk::VkPresentModeKHR> &presentModes,
476 vk::VkPresentModeKHR presentMode, vk::VkImageUsageFlags supportedImageUsage,
477 const vk::VkSurfaceTransformFlagsKHR transform, const vk::VkCompositeAlphaFlagsKHR alpha)
478 {
479 const uint32_t imageLayers = 1u;
480 const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage;
481 const vk::VkBool32 clipped = VK_FALSE;
482 vector<vk::VkSwapchainCreateInfoKHR> createInfos;
483
484 const uint32_t currentWidth =
485 properties.currentExtent.width != 0xFFFFFFFFu ?
486 properties.currentExtent.width :
487 de::min(1024u, properties.minImageExtent.width +
488 ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
489 const uint32_t currentHeight =
490 properties.currentExtent.height != 0xFFFFFFFFu ?
491 properties.currentExtent.height :
492 de::min(1024u, properties.minImageExtent.height +
493 ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
494
495 const uint32_t imageWidth =
496 scaling == SCALING_NONE ?
497 currentWidth :
498 (scaling == SCALING_UP ?
499 de::max(31u, properties.minImageExtent.width) :
500 de::min(deSmallestGreaterOrEquallPowerOfTwoU32(currentWidth + 1), properties.maxImageExtent.width));
501 const uint32_t imageHeight =
502 scaling == SCALING_NONE ?
503 currentHeight :
504 (scaling == SCALING_UP ?
505 de::max(31u, properties.minImageExtent.height) :
506 de::min(deSmallestGreaterOrEquallPowerOfTwoU32(currentHeight + 1), properties.maxImageExtent.height));
507 const vk::VkExtent2D imageSize = {imageWidth, imageHeight};
508
509 {
510 size_t presentModeNdx;
511
512 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
513 {
514 if (presentModes[presentModeNdx] == presentMode)
515 break;
516 }
517
518 if (presentModeNdx == presentModes.size())
519 TCU_THROW(NotSupportedError, "Present mode not supported");
520
521 if ((properties.supportedTransforms & transform) == 0)
522 TCU_THROW(NotSupportedError, "Transform not supported");
523
524 if ((properties.supportedCompositeAlpha & alpha) == 0)
525 TCU_THROW(NotSupportedError, "Composite alpha not supported");
526 }
527
528 for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
529 {
530 const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
531 const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
532 const vk::VkFormat imageFormat = formats[formatNdx].format;
533 const vk::VkColorSpaceKHR imageColorSpace = formats[formatNdx].colorSpace;
534 const vk::VkSwapchainCreateInfoKHR createInfo = {vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
535 DE_NULL,
536 0u,
537 surface,
538 1, // Always 1 image for a shared presentable image swapchain.
539 imageFormat,
540 imageColorSpace,
541 imageSize,
542 imageLayers,
543 imageUsage,
544 vk::VK_SHARING_MODE_EXCLUSIVE,
545 1u,
546 &queueFamilyIndex,
547 preTransform,
548 compositeAlpha,
549 presentMode,
550 clipped,
551 (vk::VkSwapchainKHR)0};
552
553 {
554 vk::VkImageFormatProperties imageFormatProperties;
555
556 deMemset(&imageFormatProperties, 0, sizeof(imageFormatProperties));
557
558 vk::VkResult result = vki.getPhysicalDeviceImageFormatProperties(
559 physicalDevice, imageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, imageUsage, 0,
560 &imageFormatProperties);
561
562 if (result == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
563 continue;
564 }
565
566 createInfos.push_back(createInfo);
567 }
568
569 return createInfos;
570 }
571
getPhysicalDeviceSurfaceCapabilities(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,vk::VkImageUsageFlags * usage)572 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities(const vk::InstanceInterface &vki,
573 vk::VkPhysicalDevice physicalDevice,
574 vk::VkSurfaceKHR surface,
575 vk::VkImageUsageFlags *usage)
576 {
577 const vk::VkPhysicalDeviceSurfaceInfo2KHR info = {vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, DE_NULL,
578
579 surface};
580 vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities;
581 vk::VkSurfaceCapabilities2KHR capabilities;
582
583 sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
584 sharedCapabilities.pNext = DE_NULL;
585
586 capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
587 capabilities.pNext = &sharedCapabilities;
588
589 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
590
591 TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
592 *usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
593
594 return capabilities.surfaceCapabilities;
595 }
596
SharedPresentableImageTestInstance(Context & context,const TestConfig & testConfig)597 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance(Context &context, const TestConfig &testConfig)
598 : TestInstance(context)
599 , m_testConfig(testConfig)
600 , m_quadCount(16u)
601 , m_vkp(context.getPlatformInterface())
602 , m_instanceExtensions(vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
603 , m_instance(createInstanceWithWsi(context, m_instanceExtensions, testConfig.wsiType))
604 , m_vki(m_instance.getDriver())
605 , m_physicalDevice(vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
606 , m_nativeDisplay(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions,
607 testConfig.wsiType))
608 , m_nativeWindow(createWindow(*m_nativeDisplay, tcu::Nothing))
609 , m_surface(vk::wsi::createSurface(m_vki, m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow,
610 context.getTestContext().getCommandLine()))
611
612 , m_queueFamilyIndex(vk::wsi::chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
613 , m_deviceExtensions(vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
614 , m_device(createDeviceWithWsi(m_vkp, m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex,
615 testConfig.useSharedPresentableImage,
616 context.getTestContext().getCommandLine().isValidationEnabled()))
617 , m_vkd(m_vkp, m_instance, *m_device, context.getUsedApiVersion(), context.getTestContext().getCommandLine())
618 , m_queue(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
619
620 , m_commandPool(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
621 , m_vertexShaderModule(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
622 , m_fragmentShaderModule(
623 vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
624 , m_pipelineLayout(createPipelineLayout(m_vkd, *m_device))
625
626 , m_supportedUsageFlags(0u)
627 , m_surfaceProperties(
628 getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
629 , m_surfaceFormats(vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
630 , m_presentModes(vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
631
632 , m_swapchainConfigs(generateSwapchainConfigs(m_vki, m_physicalDevice, *m_surface, m_queueFamilyIndex,
633 testConfig.scaling, m_surfaceProperties, m_surfaceFormats,
634 m_presentModes, testConfig.presentMode, m_supportedUsageFlags,
635 testConfig.transform, testConfig.alpha))
636 , m_swapchainConfigNdx(0u)
637
638 , m_frameCount(60u * 5u)
639 , m_frameNdx(0u)
640
641 , m_maxOutOfDateCount(20u)
642 , m_outOfDateCount(0u)
643 {
644 {
645 const tcu::ScopedLogSection surfaceInfo(m_context.getTestContext().getLog(), "SurfaceCapabilities",
646 "SurfaceCapabilities");
647 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
648 m_context.getTestContext().getLog()
649 << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
650 }
651 }
652
~SharedPresentableImageTestInstance(void)653 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance(void)
654 {
655 deinitSwapchainResources();
656 }
657
initSwapchainResources(void)658 void SharedPresentableImageTestInstance::initSwapchainResources(void)
659 {
660 const size_t fenceCount = 6;
661 const uint32_t imageWidth = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
662 const uint32_t imageHeight = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
663 const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
664
665 m_swapchain = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
666 m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
667
668 m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
669 m_pipeline = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule,
670 *m_fragmentShaderModule, imageWidth, imageHeight);
671
672 m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
673 m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
674
675 m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
676 m_fences = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
677 m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
678
679 initSemaphores(m_vkd, *m_device, m_renderSemaphores);
680
681 initFences(m_vkd, *m_device, m_fences);
682
683 // Unlike a traditional swapchain, where we'd acquire a new image from the
684 // PE every frame, a shared image swapchain has a single image that is
685 // acquired upfront. We acquire it here, transition it to the proper layout,
686 // and present it.
687
688 // Acquire the one image
689 const uint64_t foreverNs = 0xFFFFFFFFFFFFFFFFul;
690 vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device));
691 uint32_t imageIndex = 42; // initialize to junk value
692
693 VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
694 TCU_CHECK(imageIndex == 0);
695
696 // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
697 const vk::VkCommandBufferAllocateInfo allocateInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
698 *m_commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
699
700 const vk::Unique<vk::VkCommandBuffer> commandBuffer(vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
701 beginCommandBuffer(m_vkd, *commandBuffer, 0u);
702
703 const vk::VkImageMemoryBarrier barrier = {
704 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
705 DE_NULL,
706 0,
707 0,
708 vk::VK_IMAGE_LAYOUT_UNDEFINED,
709 vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
710 VK_QUEUE_FAMILY_IGNORED,
711 VK_QUEUE_FAMILY_IGNORED,
712 m_swapchainImage,
713 {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
714 };
715
716 m_vkd.cmdPipelineBarrier(*commandBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
717 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0u, 0, DE_NULL, 0, DE_NULL, 1, &barrier);
718
719 endCommandBuffer(m_vkd, *commandBuffer);
720
721 const vk::VkPipelineStageFlags waitDstStages[] = {vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
722 const vk::VkSubmitInfo submitInfo = {
723 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, DE_NULL, 1, &*semaphore, waitDstStages, 1, &*commandBuffer, 0, DE_NULL,
724 };
725
726 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
727 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
728 }
729
deinitSwapchainResources(void)730 void SharedPresentableImageTestInstance::deinitSwapchainResources(void)
731 {
732 VK_CHECK(m_vkd.queueWaitIdle(m_queue));
733
734 deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
735 deinitFences(m_vkd, *m_device, m_fences);
736 deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
737
738 m_framebuffer = vk::Move<vk::VkFramebuffer>();
739 m_swapchainImageView = vk::Move<vk::VkImageView>();
740 m_swapchainImage = (vk::VkImage)0;
741
742 m_swapchain = vk::Move<vk::VkSwapchainKHR>();
743 m_renderPass = vk::Move<vk::VkRenderPass>();
744 m_pipeline = vk::Move<vk::VkPipeline>();
745 }
746
render(void)747 void SharedPresentableImageTestInstance::render(void)
748 {
749 const uint64_t foreverNs = 0xFFFFFFFFFFFFFFFFul;
750 const vk::VkFence fence = m_fences[m_frameNdx % m_fences.size()];
751 const uint32_t width = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
752 const uint32_t height = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
753
754 // Throttle execution
755 if (m_frameNdx >= m_fences.size())
756 {
757 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
758 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
759
760 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u,
761 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
762 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
763 }
764
765 uint32_t imageIndex = 0; // There is only one image.
766 const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
767
768 const bool willPresent =
769 m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
770 !m_frameNdx;
771
772 // Create command buffer
773 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] =
774 createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, *m_framebuffer,
775 *m_pipeline, m_frameNdx, m_quadCount, width, height)
776 .disown();
777
778 // Submit command buffer
779 {
780 const vk::VkSubmitInfo submitInfo = {
781 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
782 DE_NULL,
783 0u,
784 DE_NULL,
785 DE_NULL,
786 1u,
787 &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
788 willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent.
789 ¤tRenderSemaphore};
790
791 // With a traditional swapchain, we'd fence on completion of
792 // AcquireNextImage. We never call that for a shared image swapchain, so
793 // fence on completion of the rendering work instead. A real shared
794 // image application would want a more substantial pacing mechanism.
795 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
796 }
797
798 // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
799 // assured the PE has picked up a new frame. The PE /may/ also pick up
800 // changes whenever it likes.
801 //
802 // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
803 // first frame to kick things off.
804 if (willPresent)
805 {
806
807 // Present frame
808 vk::VkResult result;
809 const vk::VkPresentInfoKHR presentInfo = {vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
810 DE_NULL,
811 1u,
812 ¤tRenderSemaphore,
813 1u,
814 &*m_swapchain,
815 &imageIndex,
816 &result};
817
818 VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
819 VK_CHECK_WSI(result);
820 }
821
822 // With either present mode, we can call GetSwapchainStatus at any time
823 // to detect possible OUT_OF_DATE conditions. Let's do that every frame.
824
825 const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
826 VK_CHECK(swapchainStatus);
827 }
828
iterate(void)829 tcu::TestStatus SharedPresentableImageTestInstance::iterate(void)
830 {
831 // Initialize swapchain specific resources
832 // Render test
833 try
834 {
835 if (m_frameNdx == 0)
836 {
837 if (m_outOfDateCount == 0)
838 m_context.getTestContext().getLog()
839 << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx]
840 << tcu::TestLog::EndMessage;
841
842 initSwapchainResources();
843 }
844
845 render();
846 }
847 catch (const vk::Error &error)
848 {
849 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
850 {
851 m_swapchainConfigs = generateSwapchainConfigs(
852 m_vki, m_physicalDevice, *m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties,
853 m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags,
854 m_testConfig.transform, m_testConfig.alpha);
855
856 if (m_outOfDateCount < m_maxOutOfDateCount)
857 {
858 m_context.getTestContext().getLog()
859 << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources."
860 << TestLog::EndMessage;
861 deinitSwapchainResources();
862 m_frameNdx = 0;
863 m_outOfDateCount++;
864
865 return tcu::TestStatus::incomplete();
866 }
867 else
868 {
869 m_context.getTestContext().getLog()
870 << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
871 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " +
872 de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
873 }
874 }
875 else
876 {
877 m_resultCollector.fail(error.what());
878 }
879
880 deinitSwapchainResources();
881
882 m_swapchainConfigNdx++;
883 m_frameNdx = 0;
884 m_outOfDateCount = 0;
885
886 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
887 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
888 else
889 return tcu::TestStatus::incomplete();
890 }
891
892 m_frameNdx++;
893
894 if (m_frameNdx >= m_frameCount)
895 {
896 m_frameNdx = 0;
897 m_outOfDateCount = 0;
898 m_swapchainConfigNdx++;
899
900 deinitSwapchainResources();
901
902 if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
903 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
904 else
905 return tcu::TestStatus::incomplete();
906 }
907 else
908 return tcu::TestStatus::incomplete();
909 }
910
911 struct Programs
912 {
initvkt::wsi::__anon5b90bc810111::Programs913 static void init(vk::SourceCollections &dst, TestConfig)
914 {
915 dst.glslSources.add("quad-vert") << glu::VertexSource(
916 "#version 450\n"
917 "out gl_PerVertex {\n"
918 "\tvec4 gl_Position;\n"
919 "};\n"
920 "layout(location = 0) out highp uint quadIndex;\n"
921 "highp float;\n"
922 "void main (void) {\n"
923 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
924 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
925 "\tquadIndex = gl_VertexIndex / 6;\n"
926 "}\n");
927 dst.glslSources.add("quad-frag") << glu::FragmentSource(
928 "#version 310 es\n"
929 "layout(location = 0) flat in highp uint quadIndex;\n"
930 "layout(location = 0) out highp vec4 o_color;\n"
931 "layout(push_constant) uniform PushConstant {\n"
932 "\thighp uint frameNdx;\n"
933 "} pushConstants;\n"
934 "void main (void)\n"
935 "{\n"
936 "\thighp uint frameNdx = pushConstants.frameNdx;\n"
937 "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
938 "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
939 "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
940 "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
941 "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
942 "\t + 64u * bitfieldExtract(y, 1, 1)\n"
943 "\t + 32u * bitfieldExtract(x, 3, 1);\n"
944 "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
945 "\t + 64u * bitfieldExtract(x, 2, 1)\n"
946 "\t + 32u * bitfieldExtract(y, 3, 1);\n"
947 "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
948 "\t + 64u * bitfieldExtract(y, 2, 1)\n"
949 "\t + 32u * bitfieldExtract(x, 4, 1);\n"
950 "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
951 "}\n");
952 }
953 };
954
955 } // namespace
956
createSharedPresentableImageTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)957 void createSharedPresentableImageTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
958 {
959 const struct
960 {
961 Scaling scaling;
962 const char *name;
963 } scaling[] = {{SCALING_NONE, "scale_none"}, {SCALING_UP, "scale_up"}, {SCALING_DOWN, "scale_down"}};
964 const struct
965 {
966 vk::VkPresentModeKHR mode;
967 const char *name;
968 } presentModes[] = {
969 {vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand"},
970 {vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous"},
971 };
972 const struct
973 {
974 vk::VkSurfaceTransformFlagsKHR transform;
975 const char *name;
976 } transforms[] = {{vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, "identity"},
977 {vk::VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, "rotate_90"},
978 {vk::VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, "rotate_180"},
979 {vk::VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, "rotate_270"},
980 {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, "horizontal_mirror"},
981 {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR, "horizontal_mirror_rotate_90"},
982 {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR, "horizontal_mirror_rotate_180"},
983 {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR, "horizontal_mirror_rotate_270"},
984 {vk::VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR, "inherit"}};
985 const struct
986 {
987 vk::VkCompositeAlphaFlagsKHR alpha;
988 const char *name;
989 } alphas[] = {{vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, "opaque"},
990 {vk::VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, "pre_multiplied"},
991 {vk::VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, "post_multiplied"},
992 {vk::VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, "inherit"}};
993
994 for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
995 {
996 if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
997 {
998 de::MovePtr<tcu::TestCaseGroup> scaleGroup(
999 new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name));
1000
1001 for (size_t transformNdx = 0; transformNdx < DE_LENGTH_OF_ARRAY(transforms); transformNdx++)
1002 {
1003 de::MovePtr<tcu::TestCaseGroup> transformGroup(
1004 new tcu::TestCaseGroup(testGroup->getTestContext(), transforms[transformNdx].name));
1005
1006 for (size_t alphaNdx = 0; alphaNdx < DE_LENGTH_OF_ARRAY(alphas); alphaNdx++)
1007 {
1008 de::MovePtr<tcu::TestCaseGroup> alphaGroup(
1009 new tcu::TestCaseGroup(testGroup->getTestContext(), alphas[alphaNdx].name));
1010
1011 for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1012 {
1013 const char *const name = presentModes[presentModeNdx].name;
1014 TestConfig config;
1015
1016 config.wsiType = wsiType;
1017 config.useSharedPresentableImage = true;
1018 config.scaling = scaling[scalingNdx].scaling;
1019 config.transform = transforms[transformNdx].transform;
1020 config.alpha = alphas[alphaNdx].alpha;
1021 config.presentMode = presentModes[presentModeNdx].mode;
1022
1023 alphaGroup->addChild(
1024 new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(
1025 testGroup->getTestContext(), name, Programs(), config));
1026 }
1027
1028 transformGroup->addChild(alphaGroup.release());
1029 }
1030
1031 scaleGroup->addChild(transformGroup.release());
1032 }
1033
1034 testGroup->addChild(scaleGroup.release());
1035 }
1036 }
1037 }
1038
1039 } // namespace wsi
1040 } // namespace vkt
1041