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