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