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 VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSwapchainTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkWsiPlatform.hpp"
43 #include "vkWsiUtil.hpp"
44 #include "vkAllocationCallbackUtil.hpp"
45 #include "vkCmdUtil.hpp"
46 #include "vkObjUtil.hpp"
47 #include "tcuSurface.hpp"
48 #include "vkImageUtil.hpp"
49
50 #include "tcuTestLog.hpp"
51 #include "tcuFormatUtil.hpp"
52 #include "tcuPlatform.hpp"
53 #include "tcuResultCollector.hpp"
54 #include "tcuCommandLine.hpp"
55
56 #include "deUniquePtr.hpp"
57 #include "deStringUtil.hpp"
58 #include "deArrayUtil.hpp"
59 #include "deSharedPtr.hpp"
60
61 #include <limits>
62
63 namespace vkt
64 {
65 namespace wsi
66 {
67
68 namespace
69 {
70
71 using namespace vk;
72 using namespace vk::wsi;
73
74 using tcu::TestLog;
75 using tcu::Maybe;
76 using tcu::UVec2;
77
78 using de::MovePtr;
79 using de::UniquePtr;
80
81 using std::string;
82 using std::vector;
83
84 typedef vector<VkExtensionProperties> Extensions;
85
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)86 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
87 {
88 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
89 requiredExtName != requiredExtensions.end();
90 ++requiredExtName)
91 {
92 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
93 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
94 }
95 }
96
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)97 CustomInstance createInstanceWithWsi (Context& context,
98 const Extensions& supportedExtensions,
99 Type wsiType,
100 const VkAllocationCallbacks* pAllocator = DE_NULL)
101 {
102 vector<string> extensions;
103
104 extensions.push_back("VK_KHR_surface");
105 extensions.push_back(getExtensionName(wsiType));
106
107 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
108 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
109 // but using them without enabling the extension is not allowed. Thus we have
110 // two options:
111 //
112 // 1) Filter out non-core formats to stay within valid usage.
113 //
114 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
115 //
116 // We opt for (2) as it provides basic coverage for the extension as a bonus.
117 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
118 extensions.push_back("VK_EXT_swapchain_colorspace");
119
120 checkAllSupported(supportedExtensions, extensions);
121
122 return createCustomInstanceWithExtensions(context, extensions, pAllocator);
123 }
124
getDeviceFeaturesForWsi(void)125 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
126 {
127 VkPhysicalDeviceFeatures features;
128 deMemset(&features, 0, sizeof(features));
129 return features;
130 }
131
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,const VkAllocationCallbacks * pAllocator,bool validationEnabled)132 Move<VkDevice> createDeviceWithWsi (const vk::PlatformInterface& vkp,
133 vk::VkInstance instance,
134 const InstanceInterface& vki,
135 VkPhysicalDevice physicalDevice,
136 const Extensions& supportedExtensions,
137 const deUint32 queueFamilyIndex,
138 const VkAllocationCallbacks* pAllocator,
139 bool validationEnabled)
140 {
141 const float queuePriorities[] = { 1.0f };
142 const VkDeviceQueueCreateInfo queueInfos[] =
143 {
144 {
145 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
146 DE_NULL,
147 (VkDeviceQueueCreateFlags)0,
148 queueFamilyIndex,
149 DE_LENGTH_OF_ARRAY(queuePriorities),
150 &queuePriorities[0]
151 }
152 };
153 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
154 vector<const char*> extensions;
155
156 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_swapchain")))
157 TCU_THROW(NotSupportedError, "VK_KHR_swapchain is not supported");
158 extensions.push_back("VK_KHR_swapchain");
159
160 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
161 extensions.push_back("VK_EXT_hdr_metadata");
162
163 VkDeviceCreateInfo deviceParams =
164 {
165 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
166 DE_NULL,
167 (VkDeviceCreateFlags)0,
168 DE_LENGTH_OF_ARRAY(queueInfos),
169 &queueInfos[0],
170 0u, // enabledLayerCount
171 DE_NULL, // ppEnabledLayerNames
172 (deUint32)extensions.size(),
173 extensions.empty() ? DE_NULL : &extensions[0],
174 &features
175 };
176
177 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
178 }
179
180 struct InstanceHelper
181 {
182 const vector<VkExtensionProperties> supportedExtensions;
183 const CustomInstance instance;
184 const InstanceDriver& vki;
185
InstanceHelpervkt::wsi::__anonc6df9e660111::InstanceHelper186 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
187 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
188 DE_NULL))
189 , instance (createInstanceWithWsi(context,
190 supportedExtensions,
191 wsiType,
192 pAllocator))
193 , vki (instance.getDriver())
194 {}
195 };
196
197 struct DeviceHelper
198 {
199 const VkPhysicalDevice physicalDevice;
200 const deUint32 queueFamilyIndex;
201 const Unique<VkDevice> device;
202 const DeviceDriver vkd;
203 const VkQueue queue;
204
DeviceHelpervkt::wsi::__anonc6df9e660111::DeviceHelper205 DeviceHelper (Context& context,
206 const InstanceInterface& vki,
207 VkInstance instance,
208 VkSurfaceKHR surface,
209 const VkAllocationCallbacks* pAllocator = DE_NULL)
210 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
211 , queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
212 , device (createDeviceWithWsi(context.getPlatformInterface(),
213 instance,
214 vki,
215 physicalDevice,
216 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
217 queueFamilyIndex,
218 pAllocator,
219 context.getTestContext().getCommandLine().isValidationEnabled()))
220 , vkd (context.getPlatformInterface(), instance, *device)
221 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
222 {
223 }
224 };
225
226 enum TestDimension
227 {
228 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
229 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
230 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
231 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
232 TEST_DIMENSION_IMAGE_USAGE,
233 TEST_DIMENSION_IMAGE_SHARING_MODE,
234 TEST_DIMENSION_PRE_TRANSFORM,
235 TEST_DIMENSION_COMPOSITE_ALPHA,
236 TEST_DIMENSION_PRESENT_MODE,
237 TEST_DIMENSION_CLIPPED,
238
239 TEST_DIMENSION_LAST
240 };
241
242 struct TestParameters
243 {
244 Type wsiType;
245 TestDimension dimension;
246
TestParametersvkt::wsi::__anonc6df9e660111::TestParameters247 TestParameters (Type wsiType_, TestDimension dimension_)
248 : wsiType (wsiType_)
249 , dimension (dimension_)
250 {}
251
TestParametersvkt::wsi::__anonc6df9e660111::TestParameters252 TestParameters (void)
253 : wsiType (TYPE_LAST)
254 , dimension (TEST_DIMENSION_LAST)
255 {}
256 };
257
258 struct GroupParameters
259 {
260 typedef FunctionInstance1<TestParameters>::Function Function;
261
262 Type wsiType;
263 Function function;
264
GroupParametersvkt::wsi::__anonc6df9e660111::GroupParameters265 GroupParameters (Type wsiType_, Function function_)
266 : wsiType (wsiType_)
267 , function (function_)
268 {}
269
GroupParametersvkt::wsi::__anonc6df9e660111::GroupParameters270 GroupParameters (void)
271 : wsiType (TYPE_LAST)
272 , function ((Function)DE_NULL)
273 {}
274 };
275
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceFormatKHR surfaceFormat,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount,VkColorSpaceKHR desiredColorspace=VK_COLOR_SPACE_MAX_ENUM_KHR)276 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
277 const InstanceInterface& vki,
278 VkPhysicalDevice physicalDevice,
279 VkSurfaceKHR surface,
280 VkSurfaceFormatKHR surfaceFormat,
281 const tcu::UVec2& desiredSize,
282 deUint32 desiredImageCount,
283 VkColorSpaceKHR desiredColorspace = VK_COLOR_SPACE_MAX_ENUM_KHR)
284 {
285 bool setColorspaceManually = desiredColorspace != VK_COLOR_SPACE_MAX_ENUM_KHR;
286
287 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
288 physicalDevice,
289 surface);
290 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
291 const VkSurfaceCapabilitiesKHR surfaceCapabilities = getPhysicalDeviceSurfaceCapabilities(vki,physicalDevice, surface);
292
293 // Check that the device has at least one supported alpha compositing mode
294 // and pick the first supported mode to be used.
295 vk::VkCompositeAlphaFlagsKHR alpha = 0;
296 for (deUint32 i = 1u; i <= surfaceCapabilities.supportedCompositeAlpha; i <<= 1u)
297 {
298 if ((i & surfaceCapabilities.supportedCompositeAlpha) != 0)
299 {
300 alpha = i;
301 break;
302 }
303 }
304 if (alpha == 0)
305 TCU_THROW(NotSupportedError, "No supported composite alphas available.");
306
307 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
308 const VkSwapchainCreateInfoKHR parameters =
309 {
310 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
311 DE_NULL,
312 (VkSwapchainCreateFlagsKHR)0,
313 surface,
314 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
315 surfaceFormat.format,
316 (setColorspaceManually ? desiredColorspace : surfaceFormat.colorSpace),
317 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
318 1u, // imageArrayLayers
319 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
320 VK_SHARING_MODE_EXCLUSIVE,
321 0u,
322 (const deUint32*)DE_NULL,
323 transform,
324 static_cast<VkCompositeAlphaFlagBitsKHR>(alpha),
325 VK_PRESENT_MODE_FIFO_KHR,
326 VK_FALSE, // clipped
327 (VkSwapchainKHR)0 // oldSwapchain
328 };
329
330 return parameters;
331 }
332
333 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
334 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
335 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
336
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)337 vector<FenceSp> createFences (const DeviceInterface& vkd,
338 const VkDevice device,
339 size_t numFences)
340 {
341 vector<FenceSp> fences(numFences);
342
343 for (size_t ndx = 0; ndx < numFences; ++ndx)
344 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
345
346 return fences;
347 }
348
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)349 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
350 const VkDevice device,
351 size_t numSemaphores)
352 {
353 vector<SemaphoreSp> semaphores(numSemaphores);
354
355 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
356 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
357
358 return semaphores;
359 }
360
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)361 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
362 const VkDevice device,
363 const VkCommandPool commandPool,
364 const VkCommandBufferLevel level,
365 const size_t numCommandBuffers)
366 {
367 vector<CommandBufferSp> buffers (numCommandBuffers);
368
369 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
370 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
371
372 return buffers;
373 }
374
getPixel(const DeviceInterface & vkd,const VkDevice device,const VkQueue queue,const VkCommandPool & commandPool,Allocator & allocator,const tcu::UVec2 size,const tcu::TextureFormat textureFormat,const VkImage * image)375 tcu::Vec4 getPixel (const DeviceInterface& vkd,
376 const VkDevice device,
377 const VkQueue queue,
378 const VkCommandPool& commandPool,
379 Allocator& allocator,
380 const tcu::UVec2 size,
381 const tcu::TextureFormat textureFormat,
382 const VkImage* image)
383 {
384 Move<VkCommandBuffer> commandBuffer;
385 Move<VkBuffer> resultBuffer;
386 de::MovePtr<Allocation> resultBufferMemory;
387
388 commandBuffer = allocateCommandBuffer(vkd, device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
389
390 // Result Buffer
391 {
392 const VkDeviceSize bufferSize = textureFormat.getPixelSize() * size.x() * size.y();
393 const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
394
395 resultBuffer = createBuffer(vkd, device, &createInfo);
396 resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, device, *resultBuffer), MemoryRequirement::HostVisible);
397
398 VK_CHECK(vkd.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
399 }
400
401 beginCommandBuffer(vkd, *commandBuffer, 0u);
402 {
403 copyImageToBuffer(vkd, *commandBuffer, *image, *resultBuffer, tcu::IVec2(size.x(), size.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
404 }
405 endCommandBuffer(vkd, *commandBuffer);
406 submitCommandsAndWait(vkd, device, queue, commandBuffer.get());
407
408 tcu::ConstPixelBufferAccess resultAccess(textureFormat,
409 tcu::IVec3(size.x(), size.y(), 1),
410 resultBufferMemory->getHostPtr());
411
412 return (resultAccess.getPixel(128, 128));
413 }
414
basicExtensionTest(Context & context,Type wsiType)415 tcu::TestStatus basicExtensionTest (Context& context, Type wsiType)
416 {
417 const tcu::UVec2 desiredSize (256, 256);
418 const InstanceHelper instHelper (context, wsiType);
419 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
420 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
421 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
422
423 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
424 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
425
426 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
427 devHelper.physicalDevice,
428 *surface);
429
430 bool found = false;
431 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
432 {
433 if (curFmt->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
434 {
435 found = true;
436 break;
437 }
438 }
439 if (!found)
440 {
441 TCU_THROW(NotSupportedError, "VK_EXT_swapchain_colorspace supported, but no non-SRGB_NONLINEAR_KHR surface formats found.");
442 }
443 return tcu::TestStatus::pass("Extension tests succeeded");
444 }
445
446 struct TestParams
447 {
448 Type wsiType;
449 VkFormat format;
450 };
451
452 // Create swapchain with multiple images on different colorspaces and compare pixels on those images.
colorspaceCompareTest(Context & context,TestParams params)453 tcu::TestStatus colorspaceCompareTest (Context& context, TestParams params)
454 {
455 if (!context.isInstanceFunctionalitySupported("VK_EXT_swapchain_colorspace"))
456 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
457
458 const tcu::UVec2 desiredSize (256, 256);
459 const InstanceHelper instHelper (context, params.wsiType);
460 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType, tcu::just(desiredSize));
461 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
462 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
463
464 const vector<VkSurfaceFormatKHR> queriedFormats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
465 devHelper.physicalDevice,
466 *surface);
467
468 vector<vk::VkColorSpaceKHR> supportedColorSpaces;
469 for (const auto& queriedFormat : queriedFormats)
470 {
471 if (queriedFormat.format == params.format)
472 {
473 supportedColorSpaces.push_back(queriedFormat.colorSpace);
474 }
475 }
476
477 // Not supported if there's no color spaces for the format.
478 if(supportedColorSpaces.size() < 2)
479 TCU_THROW(NotSupportedError, "Format not supported");
480
481 // Surface format is used to create the swapchain.
482 VkSurfaceFormatKHR surfaceFormat =
483 {
484 params.format, // format
485 supportedColorSpaces.at(0) // colorSpace
486 };
487
488 tcu::Vec4 referenceColorspacePixel;
489 const tcu::TextureFormat textureFormat = vk::mapVkFormat(surfaceFormat.format);
490 const DeviceInterface& vkd = devHelper.vkd;
491 const VkDevice device = *devHelper.device;
492 SimpleAllocator allocator (vkd,
493 device,
494 getPhysicalDeviceMemoryProperties(instHelper.vki,
495 context.getPhysicalDevice()));
496
497 for (size_t colorspaceNdx = 0; colorspaceNdx < supportedColorSpaces.size(); ++colorspaceNdx)
498 {
499 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(params.wsiType,
500 instHelper.vki,
501 devHelper.physicalDevice,
502 *surface,
503 surfaceFormat,
504 desiredSize,
505 2,
506 supportedColorSpaces[colorspaceNdx]);
507 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
508 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
509 const vector<VkExtensionProperties> deviceExtensions (enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
510
511 const WsiTriangleRenderer renderer(vkd,
512 device,
513 allocator,
514 context.getBinaryCollection(),
515 true,
516 swapchainImages,
517 swapchainImages,
518 swapchainInfo.imageFormat,
519 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
520
521 const Move<VkCommandPool> commandPool (createCommandPool(vkd,
522 device,
523 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
524 devHelper.queueFamilyIndex));
525 const Move<VkSemaphore> imageReadySemaphore = createSemaphore(vkd, device);
526 const Move<VkSemaphore> renderingCompleteSemaphore = createSemaphore(vkd, device);
527 const Move<VkCommandBuffer> commandBuffer = allocateCommandBuffer(vkd,
528 device,
529 *commandPool,
530 VK_COMMAND_BUFFER_LEVEL_PRIMARY);
531
532 try
533 {
534 deUint32 imageNdx = ~0u;
535
536 {
537 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
538 *swapchain,
539 std::numeric_limits<deUint64>::max(),
540 imageReadySemaphore.get(),
541 DE_NULL,
542 &imageNdx);
543
544 if (acquireResult == VK_SUBOPTIMAL_KHR)
545 {
546 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult
547 << TestLog::EndMessage;
548 }
549 else
550 {
551 VK_CHECK(acquireResult);
552 }
553 }
554
555 TCU_CHECK((size_t) imageNdx < swapchainImages.size());
556
557 {
558 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
559 const VkSubmitInfo submitInfo =
560 {
561 VK_STRUCTURE_TYPE_SUBMIT_INFO,
562 DE_NULL,
563 0u,
564 &imageReadySemaphore.get(),
565 &waitDstStage,
566 1u,
567 &commandBuffer.get(),
568 1u,
569 &renderingCompleteSemaphore.get()
570 };
571 const VkPresentInfoKHR presentInfo =
572 {
573 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
574 DE_NULL,
575 1u,
576 &renderingCompleteSemaphore.get(),
577 1u,
578 &swapchain.get(),
579 &imageNdx,
580 (VkResult *) DE_NULL
581 };
582
583 renderer.recordFrame(commandBuffer.get(), imageNdx, 0);
584 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
585 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
586 }
587
588 // Set reference pixelBufferAccess for comparison.
589 if (colorspaceNdx == 0)
590 {
591 referenceColorspacePixel = getPixel(vkd, device, devHelper.queue, commandPool.get(),
592 allocator, desiredSize, textureFormat,
593 &swapchainImages[imageNdx]);
594 continue;
595 }
596
597 // Compare pixels from images to make sure the colorspace makes no difference.
598 if (referenceColorspacePixel == getPixel(vkd, device, devHelper.queue, commandPool.get(),
599 allocator, desiredSize, textureFormat,
600 &swapchainImages[imageNdx]))
601 continue;
602 else
603 {
604 VK_CHECK(vkd.deviceWaitIdle(device));
605 return tcu::TestStatus::fail("Colorspace comparison test failed");
606 }
607 }
608 catch (...)
609 {
610 // Make sure device is idle before destroying resources
611 vkd.deviceWaitIdle(device);
612 throw;
613 }
614 }
615
616 VK_CHECK(vkd.deviceWaitIdle(device));
617 return tcu::TestStatus::pass("Colorspace comparison test succeeded");
618 }
619
surfaceFormatRenderTest(Context & context,Type wsiType,const InstanceHelper & instHelper,const DeviceHelper & devHelper,VkSurfaceKHR surface,VkSurfaceFormatKHR curFmt,deBool checkHdr=false)620 tcu::TestStatus surfaceFormatRenderTest (Context& context,
621 Type wsiType,
622 const InstanceHelper& instHelper,
623 const DeviceHelper& devHelper,
624 VkSurfaceKHR surface,
625 VkSurfaceFormatKHR curFmt,
626 deBool checkHdr = false)
627 {
628 const tcu::UVec2 desiredSize (256, 256);
629 const DeviceInterface& vkd = devHelper.vkd;
630 const VkDevice device = *devHelper.device;
631 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
632
633 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, surface, curFmt, desiredSize, 2);
634 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
635 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
636 const vector<VkExtensionProperties> deviceExtensions (enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
637
638 if (checkHdr && !isExtensionSupported(deviceExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
639 TCU_THROW(NotSupportedError, "Extension VK_EXT_hdr_metadata not supported");
640
641 const WsiTriangleRenderer renderer (vkd,
642 device,
643 allocator,
644 context.getBinaryCollection(),
645 true,
646 swapchainImages,
647 swapchainImages,
648 swapchainInfo.imageFormat,
649 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
650
651 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
652
653 const size_t maxQueuedFrames = swapchainImages.size()*2;
654
655 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
656 // limit number of frames we allow to be queued.
657 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
658
659 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
660 // the semaphore in same time as the fence we use to meter rendering.
661 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
662
663 // For rest we simply need maxQueuedFrames as we will wait for image
664 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
665 // previous uses must have completed.
666 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
667 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
668
669 try
670 {
671 const deUint32 numFramesToRender = 60;
672
673 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
674 {
675 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
676 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
677 deUint32 imageNdx = ~0u;
678
679 if (frameNdx >= maxQueuedFrames)
680 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
681
682 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
683
684 {
685 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
686 *swapchain,
687 std::numeric_limits<deUint64>::max(),
688 imageReadySemaphore,
689 (vk::VkFence)0,
690 &imageNdx);
691
692 if (acquireResult == VK_SUBOPTIMAL_KHR)
693 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
694 else
695 VK_CHECK(acquireResult);
696 }
697
698 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
699
700 {
701 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
702 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
703 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
704 const VkSubmitInfo submitInfo =
705 {
706 VK_STRUCTURE_TYPE_SUBMIT_INFO,
707 DE_NULL,
708 1u,
709 &imageReadySemaphore,
710 &waitDstStage,
711 1u,
712 &commandBuffer,
713 1u,
714 &renderingCompleteSemaphore
715 };
716 const VkPresentInfoKHR presentInfo =
717 {
718 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
719 DE_NULL,
720 1u,
721 &renderingCompleteSemaphore,
722 1u,
723 &*swapchain,
724 &imageNdx,
725 (VkResult*)DE_NULL
726 };
727
728 if (checkHdr) {
729 const VkHdrMetadataEXT hdrData = {
730 VK_STRUCTURE_TYPE_HDR_METADATA_EXT,
731 DE_NULL,
732 makeXYColorEXT(0.680f, 0.320f),
733 makeXYColorEXT(0.265f, 0.690f),
734 makeXYColorEXT(0.150f, 0.060f),
735 makeXYColorEXT(0.3127f, 0.3290f),
736 1000.0,
737 0.0,
738 1000.0,
739 70.0
740 };
741 vector<VkSwapchainKHR> swapchainArray;
742
743 swapchainArray.push_back(*swapchain);
744 vkd.setHdrMetadataEXT(device, (deUint32)swapchainArray.size(), swapchainArray.data(), &hdrData);
745 }
746
747 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
748 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
749 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
750 }
751 }
752
753 VK_CHECK(vkd.deviceWaitIdle(device));
754 }
755 catch (...)
756 {
757 // Make sure device is idle before destroying resources
758 vkd.deviceWaitIdle(device);
759 throw;
760 }
761
762 return tcu::TestStatus::pass("Rendering test succeeded");
763 }
764
surfaceFormatRenderTests(Context & context,Type wsiType)765 tcu::TestStatus surfaceFormatRenderTests (Context& context, Type wsiType)
766 {
767 const tcu::UVec2 desiredSize (256, 256);
768 const InstanceHelper instHelper (context, wsiType);
769 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
770 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
771 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
772
773 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
774 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
775
776 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
777 devHelper.physicalDevice,
778 *surface);
779 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
780 {
781 surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt);
782 }
783 return tcu::TestStatus::pass("Rendering tests succeeded");
784 }
785
surfaceFormatRenderWithHdrTests(Context & context,Type wsiType)786 tcu::TestStatus surfaceFormatRenderWithHdrTests (Context& context, Type wsiType)
787 {
788 const tcu::UVec2 desiredSize (256, 256);
789 const InstanceHelper instHelper (context, wsiType);
790 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
791 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
792 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
793
794 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
795 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
796
797 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
798 devHelper.physicalDevice,
799 *surface);
800 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
801 {
802 surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt, true);
803 }
804 return tcu::TestStatus::pass("Rendering tests succeeded");
805 }
806
807 // We need different versions of this function in order to invoke
808 // different overloaded versions of addFunctionCaseWithPrograms.
getBasicRenderPrograms2(SourceCollections & dst,TestParams)809 void getBasicRenderPrograms2 (SourceCollections& dst, TestParams)
810 {
811 WsiTriangleRenderer::getPrograms(dst);
812 }
813
getBasicRenderPrograms(SourceCollections & dst,Type)814 void getBasicRenderPrograms (SourceCollections& dst, Type)
815 {
816 WsiTriangleRenderer::getPrograms(dst);
817 }
818 } // anonymous
819
createColorSpaceTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)820 void createColorSpaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
821 {
822 addFunctionCase(testGroup, "extensions", "Verify Colorspace Extensions", basicExtensionTest, wsiType);
823 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Tests", getBasicRenderPrograms, surfaceFormatRenderTests, wsiType);
824 addFunctionCaseWithPrograms(testGroup, "hdr", "Basic Rendering Tests with HDR", getBasicRenderPrograms, surfaceFormatRenderWithHdrTests, wsiType);
825 }
826
createColorspaceCompareTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)827 void createColorspaceCompareTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
828 {
829 const VkFormat formatList[] = {
830 VK_FORMAT_B8G8R8A8_UNORM,
831 VK_FORMAT_R8G8B8A8_UNORM,
832 VK_FORMAT_R8G8B8A8_SRGB,
833 VK_FORMAT_R5G6B5_UNORM_PACK16,
834 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
835 VK_FORMAT_R16G16B16A16_SFLOAT
836 };
837
838 // Create test for every format.
839 for (const VkFormat& format : formatList)
840 {
841 const char* const enumName = getFormatName(format);
842 const string caseName = de::toLower(string(enumName).substr(10));
843 const TestParams params =
844 {
845 wsiType,
846 format
847 };
848 addFunctionCaseWithPrograms(testGroup, caseName, "", getBasicRenderPrograms2, colorspaceCompareTest, params);
849 }
850 }
851
852 } // wsi
853 } // vkt
854