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