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