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