1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Protected memory interaction with VkSwapchain Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktProtectedMemWsiSwapchainTests.hpp"
26
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkPlatform.hpp"
32 #include "vkStrUtil.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkDeviceUtil.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45
46 #include "tcuTestLog.hpp"
47 #include "tcuFormatUtil.hpp"
48 #include "tcuPlatform.hpp"
49 #include "tcuResultCollector.hpp"
50
51 #include "deUniquePtr.hpp"
52 #include "deStringUtil.hpp"
53 #include "deArrayUtil.hpp"
54 #include "deSharedPtr.hpp"
55
56 #include <limits>
57
58 #include "vktProtectedMemContext.hpp"
59 #include "vktProtectedMemUtils.hpp"
60
61 namespace vkt
62 {
63 namespace ProtectedMem
64 {
65
66 namespace
67 {
68
69 typedef std::vector<vk::VkExtensionProperties> Extensions;
70
checkAllSupported(const Extensions & supportedExtensions,const std::vector<std::string> & requiredExtensions)71 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
72 {
73 for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
74 requiredExtName != requiredExtensions.end();
75 ++requiredExtName)
76 {
77 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79 }
80 }
81
getRequiredWsiExtensions(const Extensions & supportedExtensions,vk::wsi::Type wsiType)82 std::vector<std::string> getRequiredWsiExtensions (const Extensions& supportedExtensions,
83 vk::wsi::Type wsiType)
84 {
85 std::vector<std::string> extensions;
86
87 extensions.push_back("VK_KHR_surface");
88 extensions.push_back(getExtensionName(wsiType));
89
90 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
91 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
92 // but using them without enabling the extension is not allowed. Thus we have
93 // two options:
94 //
95 // 1) Filter out non-core formats to stay within valid usage.
96 //
97 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
98 //
99 // We opt for (2) as it provides basic coverage for the extension as a bonus.
100 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
101 extensions.push_back("VK_EXT_swapchain_colorspace");
102
103 // VK_KHR_surface_protected_capabilities adds a way to check if swapchain can be
104 // created for protected VkSurface, so if this extension is enabled then we can
105 // check for that capability.
106 // To check this capability, vkGetPhysicalDeviceSurfaceCapabilities2KHR needs
107 // to be called so add VK_KHR_get_surface_capabilities2 for this.
108 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
109 {
110 extensions.push_back("VK_KHR_get_surface_capabilities2");
111 extensions.push_back("VK_KHR_surface_protected_capabilities");
112 }
113
114 checkAllSupported(supportedExtensions, extensions);
115
116 return extensions;
117 }
118
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)119 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
120 const Extensions& supportedExtensions,
121 vk::wsi::Type wsiType)
122 {
123 try
124 {
125 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
126 }
127 catch (const tcu::NotSupportedError& e)
128 {
129 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
130 platform.hasDisplay(wsiType))
131 {
132 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
133 // must support creating native display & window for that WSI type.
134 throw tcu::TestError(e.getMessage());
135 }
136 else
137 throw;
138 }
139 }
140
createWindow(const vk::wsi::Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)141 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
142 {
143 try
144 {
145 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
146 }
147 catch (const tcu::NotSupportedError& e)
148 {
149 // See createDisplay - assuming that wsi::Display was supported platform port
150 // should also support creating a window.
151 throw tcu::TestError(e.getMessage());
152 }
153 }
154
155 struct NativeObjects
156 {
157 const de::UniquePtr<vk::wsi::Display> display;
158 const de::UniquePtr<vk::wsi::Window> window;
159
NativeObjectsvkt::ProtectedMem::__anonf67e0b520111::NativeObjects160 NativeObjects (Context& context,
161 const Extensions& supportedExtensions,
162 vk::wsi::Type wsiType,
163 const tcu::Maybe<tcu::UVec2>& initialWindowSize = tcu::Nothing)
164 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
165 , window (createWindow(*display, initialWindowSize))
166 {}
167 };
168
169 enum TestDimension
170 {
171 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
172 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
173 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
174 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
175 TEST_DIMENSION_IMAGE_USAGE,
176 TEST_DIMENSION_IMAGE_SHARING_MODE,
177 TEST_DIMENSION_PRE_TRANSFORM,
178 TEST_DIMENSION_COMPOSITE_ALPHA,
179 TEST_DIMENSION_PRESENT_MODE,
180 TEST_DIMENSION_CLIPPED,
181
182 TEST_DIMENSION_LAST
183 };
184
getTestDimensionName(TestDimension dimension)185 const char* getTestDimensionName (TestDimension dimension)
186 {
187 static const char* const s_names[] =
188 {
189 "min_image_count",
190 "image_format",
191 "image_extent",
192 "image_array_layers",
193 "image_usage",
194 "image_sharing_mode",
195 "pre_transform",
196 "composite_alpha",
197 "present_mode",
198 "clipped"
199 };
200 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
201 }
202
203 struct TestParameters
204 {
205 vk::wsi::Type wsiType;
206 TestDimension dimension;
207
TestParametersvkt::ProtectedMem::__anonf67e0b520111::TestParameters208 TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
209 : wsiType (wsiType_)
210 , dimension (dimension_)
211 {}
212
TestParametersvkt::ProtectedMem::__anonf67e0b520111::TestParameters213 TestParameters (void)
214 : wsiType (vk::wsi::TYPE_LAST)
215 , dimension (TEST_DIMENSION_LAST)
216 {}
217 };
218
firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR & capabilities)219 static vk::VkCompositeAlphaFlagBitsKHR firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR& capabilities)
220 {
221 deUint32 alphaMode = 1u;
222
223 for (;alphaMode < capabilities.supportedCompositeAlpha; alphaMode = alphaMode<<1u)
224 {
225 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
226 {
227 break;
228 }
229 }
230
231 return (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
232 }
233
generateSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,const vk::VkSurfaceCapabilitiesKHR & capabilities,const std::vector<vk::VkSurfaceFormatKHR> & formats,const std::vector<vk::VkPresentModeKHR> & presentModes)234 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType,
235 TestDimension dimension,
236 const ProtectedContext& context,
237 const vk::VkSurfaceCapabilitiesKHR& capabilities,
238 const std::vector<vk::VkSurfaceFormatKHR>& formats,
239 const std::vector<vk::VkPresentModeKHR>& presentModes)
240 {
241 std::vector<vk::VkSwapchainCreateInfoKHR> cases;
242 const vk::wsi::PlatformProperties& platformProperties = getPlatformProperties(wsiType);
243 const vk::VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
244 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
245 const vk::VkSwapchainCreateInfoKHR baseParameters =
246 {
247 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
248 DE_NULL,
249 #ifndef NOT_PROTECTED
250 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
251 #else
252 (vk::VkSwapchainCreateFlagsKHR)0,
253 #endif
254 (vk::VkSurfaceKHR)0,
255 capabilities.minImageCount,
256 formats[0].format,
257 formats[0].colorSpace,
258 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
259 ? capabilities.minImageExtent : capabilities.currentExtent),
260 1u, // imageArrayLayers
261 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
262 vk::VK_SHARING_MODE_EXCLUSIVE,
263 0u,
264 (const deUint32*)DE_NULL,
265 defaultTransform,
266 firstSupportedCompositeAlpha(capabilities),
267 vk::VK_PRESENT_MODE_FIFO_KHR,
268 VK_FALSE, // clipped
269 (vk::VkSwapchainKHR)0 // oldSwapchain
270 };
271
272 vk::VkImageCreateFlags imageCreateFlag =
273 #ifndef NOT_PROTECTED
274 vk::VK_IMAGE_CREATE_PROTECTED_BIT;
275 #else
276 (vk::VkImageCreateFlags)0u;
277 #endif
278
279 switch (dimension)
280 {
281 case TEST_DIMENSION_MIN_IMAGE_COUNT:
282 {
283 // Estimate how much memory each swapchain image consumes. This isn't perfect, since
284 // swapchain images may have additional constraints that equivalent non-swapchain
285 // images don't have. But it's the best we can do.
286 const vk::DeviceInterface& vkd = context.getDeviceInterface();
287 vk::VkDevice device = context.getDevice();
288 vk::VkMemoryRequirements memoryRequirements;
289 {
290 const vk::VkImageCreateInfo imageInfo =
291 {
292 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
293 DE_NULL,
294 imageCreateFlag,
295 vk::VK_IMAGE_TYPE_2D,
296 baseParameters.imageFormat,
297 {
298 baseParameters.imageExtent.width,
299 baseParameters.imageExtent.height,
300 1,
301 },
302 1, // mipLevels
303 baseParameters.imageArrayLayers,
304 vk::VK_SAMPLE_COUNT_1_BIT,
305 vk::VK_IMAGE_TILING_OPTIMAL,
306 baseParameters.imageUsage,
307 baseParameters.imageSharingMode,
308 baseParameters.queueFamilyIndexCount,
309 baseParameters.pQueueFamilyIndices,
310 vk::VK_IMAGE_LAYOUT_UNDEFINED
311 };
312 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
313
314 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
315 }
316
317 // Determine the maximum memory heap space available for protected images
318 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
319 vk::VkDeviceSize protectedHeapSize = 0;
320 vk::VkDeviceSize maxMemoryUsage = 0;
321 deUint32 protectedHeapMask = 0;
322
323 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
324 {
325 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
326 if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
327 #ifndef NOT_PROTECTED
328 (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
329 #endif
330 (protectedHeapMask & (1u << heapIndex)) == 0)
331 {
332 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
333 maxMemoryUsage = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
334 protectedHeapMask |= 1u << heapIndex;
335 }
336 }
337
338 // If the implementation doesn't have a max image count, min+16 means we won't clamp.
339 // Limit it to how many protected images we estimate can be allocated - 25% of heap size
340 const deUint32 maxImageCount = de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
341 deUint32(maxMemoryUsage / memoryRequirements.size));
342 if (maxImageCount < capabilities.minImageCount)
343 TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!.");
344
345 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, maxImageCount);
346 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
347 {
348 cases.push_back(baseParameters);
349 cases.back().minImageCount = imageCount;
350 }
351
352 break;
353 }
354
355 case TEST_DIMENSION_IMAGE_FORMAT:
356 {
357 const vk::DeviceInterface& vkd = context.getDeviceInterface();
358 vk::VkDevice device = context.getDevice();
359 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
360 vk::VkDeviceSize protectedHeapSize = 0;
361 vk::VkDeviceSize maxMemoryUsage = 0;
362
363 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
364 {
365 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
366 #ifndef NOT_PROTECTED
367 if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
368 #endif
369 {
370 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
371 maxMemoryUsage = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
372 }
373 }
374
375 for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
376 {
377 vk::VkMemoryRequirements memoryRequirements;
378 {
379 const vk::VkImageCreateInfo imageInfo =
380 {
381 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
382 DE_NULL,
383 imageCreateFlag,
384 vk::VK_IMAGE_TYPE_2D,
385 curFmt->format,
386 {
387 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
388 ? capabilities.minImageExtent.width : capabilities.currentExtent.width,
389 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
390 ? capabilities.minImageExtent.height : capabilities.currentExtent.height,
391 1,
392 },
393 1, // mipLevels
394 baseParameters.imageArrayLayers,
395 vk::VK_SAMPLE_COUNT_1_BIT,
396 vk::VK_IMAGE_TILING_OPTIMAL,
397 baseParameters.imageUsage,
398 baseParameters.imageSharingMode,
399 baseParameters.queueFamilyIndexCount,
400 baseParameters.pQueueFamilyIndices,
401 vk::VK_IMAGE_LAYOUT_UNDEFINED
402 };
403
404 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
405
406 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
407 }
408
409 // Check for the image size requirement based on double/triple buffering
410 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
411 {
412 cases.push_back(baseParameters);
413 cases.back().imageFormat = curFmt->format;
414 cases.back().imageColorSpace = curFmt->colorSpace;
415 }
416 }
417
418 break;
419 }
420
421 case TEST_DIMENSION_IMAGE_EXTENT:
422 {
423 static const vk::VkExtent2D s_testSizes[] =
424 {
425 { 1, 1 },
426 { 16, 32 },
427 { 32, 16 },
428 { 632, 231 },
429 { 117, 998 },
430 };
431
432 const vk::DeviceInterface& vkd = context.getDeviceInterface();
433 vk::VkDevice device = context.getDevice();
434 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
435 vk::VkDeviceSize protectedHeapSize = 0;
436 vk::VkDeviceSize maxMemoryUsage = 0;
437
438 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
439 {
440 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
441 #ifndef NOT_PROTECTED
442 if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
443 #endif
444 {
445 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
446 maxMemoryUsage = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
447 }
448 }
449
450 if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
451 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
452 {
453 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
454 {
455 vk::VkMemoryRequirements memoryRequirements;
456 {
457 const vk::VkImageCreateInfo imageInfo =
458 {
459 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
460 DE_NULL,
461 imageCreateFlag,
462 vk::VK_IMAGE_TYPE_2D,
463 baseParameters.imageFormat,
464 {
465 s_testSizes[ndx].width,
466 s_testSizes[ndx].height,
467 1,
468 },
469 1, // mipLevels
470 baseParameters.imageArrayLayers,
471 vk::VK_SAMPLE_COUNT_1_BIT,
472 vk::VK_IMAGE_TILING_OPTIMAL,
473 baseParameters.imageUsage,
474 baseParameters.imageSharingMode,
475 baseParameters.queueFamilyIndexCount,
476 baseParameters.pQueueFamilyIndices,
477 vk::VK_IMAGE_LAYOUT_UNDEFINED
478 };
479
480 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
481
482 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
483 }
484
485 // Check for the image size requirement based on double/triple buffering
486 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
487 {
488 cases.push_back(baseParameters);
489 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
490 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
491 }
492 }
493 }
494
495 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
496 {
497 vk::VkMemoryRequirements memoryRequirements;
498 {
499 const vk::VkImageCreateInfo imageInfo =
500 {
501 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
502 DE_NULL,
503 imageCreateFlag,
504 vk::VK_IMAGE_TYPE_2D,
505 baseParameters.imageFormat,
506 {
507 capabilities.currentExtent.width,
508 capabilities.currentExtent.height,
509 1,
510 },
511 1, // mipLevels
512 baseParameters.imageArrayLayers,
513 vk::VK_SAMPLE_COUNT_1_BIT,
514 vk::VK_IMAGE_TILING_OPTIMAL,
515 baseParameters.imageUsage,
516 baseParameters.imageSharingMode,
517 baseParameters.queueFamilyIndexCount,
518 baseParameters.pQueueFamilyIndices,
519 vk::VK_IMAGE_LAYOUT_UNDEFINED
520 };
521
522 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
523
524 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
525 }
526
527 // Check for the image size requirement based on double/triple buffering
528 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
529 {
530 cases.push_back(baseParameters);
531 cases.back().imageExtent = capabilities.currentExtent;
532 }
533 }
534
535 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
536 {
537 static const vk::VkExtent2D s_testExtentSizes[] =
538 {
539 { capabilities.minImageExtent.width, capabilities.minImageExtent.height },
540 { capabilities.maxImageExtent.width, capabilities.maxImageExtent.height },
541 };
542
543 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testExtentSizes); ++ndx)
544 {
545 vk::VkMemoryRequirements memoryRequirements;
546 {
547 const vk::VkImageCreateInfo imageInfo =
548 {
549 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
550 DE_NULL,
551 imageCreateFlag,
552 vk::VK_IMAGE_TYPE_2D,
553 baseParameters.imageFormat,
554 {
555 s_testExtentSizes[ndx].width,
556 s_testExtentSizes[ndx].height,
557 1,
558 },
559 1, // mipLevels
560 baseParameters.imageArrayLayers,
561 vk::VK_SAMPLE_COUNT_1_BIT,
562 vk::VK_IMAGE_TILING_OPTIMAL,
563 baseParameters.imageUsage,
564 baseParameters.imageSharingMode,
565 baseParameters.queueFamilyIndexCount,
566 baseParameters.pQueueFamilyIndices,
567 vk::VK_IMAGE_LAYOUT_UNDEFINED
568 };
569
570 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
571
572 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
573 }
574
575 // Check for the image size requirement based on double/triple buffering
576 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
577 {
578 cases.push_back(baseParameters);
579 cases.back().imageExtent =s_testExtentSizes[ndx];
580 }
581 }
582 }
583
584 break;
585 }
586
587 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
588 {
589 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
590
591 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
592 {
593 cases.push_back(baseParameters);
594 cases.back().imageArrayLayers = numLayers;
595 }
596
597 break;
598 }
599
600 case TEST_DIMENSION_IMAGE_USAGE:
601 {
602 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
603 {
604 if ((flags & ~capabilities.supportedUsageFlags) == 0)
605 {
606 cases.push_back(baseParameters);
607 cases.back().imageUsage = flags;
608 }
609 }
610
611 break;
612 }
613
614 case TEST_DIMENSION_IMAGE_SHARING_MODE:
615 {
616 cases.push_back(baseParameters);
617 cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
618
619 cases.push_back(baseParameters);
620 cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
621
622 break;
623 }
624
625 case TEST_DIMENSION_PRE_TRANSFORM:
626 {
627 for (deUint32 transform = 1u;
628 transform <= capabilities.supportedTransforms;
629 transform = transform<<1u)
630 {
631 if ((transform & capabilities.supportedTransforms) != 0)
632 {
633 cases.push_back(baseParameters);
634 cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
635 }
636 }
637
638 break;
639 }
640
641 case TEST_DIMENSION_COMPOSITE_ALPHA:
642 {
643 for (deUint32 alphaMode = 1u;
644 alphaMode <= capabilities.supportedCompositeAlpha;
645 alphaMode = alphaMode<<1u)
646 {
647 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
648 {
649 cases.push_back(baseParameters);
650 cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
651 }
652 }
653
654 break;
655 }
656
657 case TEST_DIMENSION_PRESENT_MODE:
658 {
659 for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
660 {
661 cases.push_back(baseParameters);
662 cases.back().presentMode = *curMode;
663 }
664
665 break;
666 }
667
668 case TEST_DIMENSION_CLIPPED:
669 {
670 cases.push_back(baseParameters);
671 cases.back().clipped = VK_FALSE;
672
673 cases.push_back(baseParameters);
674 cases.back().clipped = VK_TRUE;
675
676 break;
677 }
678
679 default:
680 DE_FATAL("Impossible");
681 }
682
683 DE_ASSERT(!cases.empty());
684 return cases;
685 }
686
generateSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,vk::VkSurfaceKHR surface)687 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType,
688 TestDimension dimension,
689 const ProtectedContext& context,
690 vk::VkSurfaceKHR surface)
691 {
692 const vk::InstanceInterface& vki = context.getInstanceDriver();
693 vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
694 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
695 physicalDevice,
696 surface);
697 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
698 physicalDevice,
699 surface);
700 const std::vector<vk::VkPresentModeKHR> presentModes = vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
701 physicalDevice,
702 surface);
703
704 return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
705 }
706
createSwapchainTest(Context & baseCtx,TestParameters params)707 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
708 {
709 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
710 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, params.wsiType);
711 std::vector<std::string> devExts;
712 devExts.push_back("VK_KHR_swapchain");
713
714 const NativeObjects native (baseCtx, supportedExtensions, params.wsiType);
715 ProtectedContext context (baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
716 vk::VkSurfaceKHR surface = context.getSurface();
717 const std::vector<vk::VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType,
718 params.dimension,
719 context,
720 surface));
721 deUint32 queueIdx = context.getQueueFamilyIndex();
722 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
723 {
724 vk::VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
725
726 curParams.surface = surface;
727 curParams.queueFamilyIndexCount = 1u;
728 curParams.pQueueFamilyIndices = &queueIdx;
729
730 context.getTestContext().getLog()
731 << tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
732
733 {
734 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
735 }
736 }
737
738 return tcu::TestStatus::pass("Creating swapchain succeeded");
739 }
740
741 struct GroupParameters
742 {
743 typedef FunctionInstance1<TestParameters>::Function Function;
744
745 vk::wsi::Type wsiType;
746 Function function;
747
GroupParametersvkt::ProtectedMem::__anonf67e0b520111::GroupParameters748 GroupParameters (vk::wsi::Type wsiType_, Function function_)
749 : wsiType (wsiType_)
750 , function (function_)
751 {}
752
GroupParametersvkt::ProtectedMem::__anonf67e0b520111::GroupParameters753 GroupParameters (void)
754 : wsiType (vk::wsi::TYPE_LAST)
755 , function ((Function)DE_NULL)
756 {}
757 };
758
checkSupport(Context & context,TestParameters)759 void checkSupport (Context& context, TestParameters)
760 {
761 checkProtectedQueueSupport(context);
762 }
763
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)764 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
765 {
766 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
767 {
768 const TestDimension testDimension = (TestDimension)dimensionNdx;
769
770 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", checkSupport, params.function, TestParameters(params.wsiType, testDimension));
771 }
772 }
773
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)774 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type wsiType,
775 const vk::InstanceInterface& vki,
776 vk::VkPhysicalDevice physicalDevice,
777 vk::VkSurfaceKHR surface,
778 const tcu::UVec2& desiredSize,
779 deUint32 desiredImageCount)
780 {
781 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
782 physicalDevice,
783 surface);
784 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
785 physicalDevice,
786 surface);
787 const vk::wsi::PlatformProperties& platformProperties = vk::wsi::getPlatformProperties(wsiType);
788 const vk::VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
789 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
790 const vk::VkSwapchainCreateInfoKHR parameters =
791 {
792 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
793 DE_NULL,
794 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
795 surface,
796 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
797 formats[0].format,
798 formats[0].colorSpace,
799 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
800 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
801 1u, // imageArrayLayers
802 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
803 vk::VK_SHARING_MODE_EXCLUSIVE,
804 0u,
805 (const deUint32*)DE_NULL,
806 transform,
807 firstSupportedCompositeAlpha(capabilities),
808 vk::VK_PRESENT_MODE_FIFO_KHR,
809 VK_FALSE, // clipped
810 (vk::VkSwapchainKHR)0 // oldSwapchain
811 };
812
813 return parameters;
814 }
815
816 typedef de::SharedPtr<vk::Unique<vk::VkImageView> > ImageViewSp;
817 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> > FramebufferSp;
818
819 class TriangleRenderer
820 {
821 public:
822 TriangleRenderer (ProtectedContext& context,
823 const vk::BinaryCollection& binaryRegistry,
824 const std::vector<vk::VkImage> swapchainImages,
825 const vk::VkFormat framebufferFormat,
826 const tcu::UVec2& renderSize);
827 ~TriangleRenderer (void);
828
829 void recordFrame (vk::VkCommandBuffer cmdBuffer,
830 deUint32 imageNdx,
831 deUint32 frameNdx) const;
832
833 static void getPrograms (vk::SourceCollections& dst);
834
835 private:
836 static vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
837 const vk::VkDevice device,
838 const vk::VkFormat colorAttachmentFormat);
839 static vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface& vkd,
840 vk::VkDevice device);
841 static vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd,
842 const vk::VkDevice device,
843 const vk::VkRenderPass renderPass,
844 const vk::VkPipelineLayout pipelineLayout,
845 const vk::BinaryCollection& binaryCollection,
846 const tcu::UVec2& renderSize);
847
848 const vk::DeviceInterface& m_vkd;
849
850 const std::vector<vk::VkImage> m_swapchainImages;
851 const tcu::UVec2 m_renderSize;
852
853 const vk::Unique<vk::VkRenderPass> m_renderPass;
854 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
855 const vk::Unique<vk::VkPipeline> m_pipeline;
856
857 const de::UniquePtr<vk::BufferWithMemory> m_vertexBuffer;
858
859 std::vector<ImageViewSp> m_attachmentViews;
860 std::vector<FramebufferSp> m_framebuffers;
861 };
862
createRenderPass(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat colorAttachmentFormat)863 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface& vkd,
864 const vk::VkDevice device,
865 const vk::VkFormat colorAttachmentFormat)
866 {
867 const vk::VkAttachmentDescription colorAttDesc =
868 {
869 (vk::VkAttachmentDescriptionFlags)0,
870 colorAttachmentFormat,
871 vk::VK_SAMPLE_COUNT_1_BIT,
872 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
873 vk::VK_ATTACHMENT_STORE_OP_STORE,
874 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
875 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
876 vk::VK_IMAGE_LAYOUT_UNDEFINED,
877 vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
878 };
879 const vk::VkAttachmentReference colorAttRef =
880 {
881 0u,
882 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
883 };
884 const vk::VkSubpassDescription subpassDesc =
885 {
886 (vk::VkSubpassDescriptionFlags)0u,
887 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
888 0u, // inputAttachmentCount
889 DE_NULL, // pInputAttachments
890 1u, // colorAttachmentCount
891 &colorAttRef, // pColorAttachments
892 DE_NULL, // pResolveAttachments
893 DE_NULL, // depthStencilAttachment
894 0u, // preserveAttachmentCount
895 DE_NULL, // pPreserveAttachments
896 };
897 const vk::VkSubpassDependency dependencies[] =
898 {
899 {
900 VK_SUBPASS_EXTERNAL, // srcSubpass
901 0u, // dstSubpass
902 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
903 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
904 vk::VK_ACCESS_MEMORY_READ_BIT,
905 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
906 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
907 vk::VK_DEPENDENCY_BY_REGION_BIT
908 },
909 {
910 0u, // srcSubpass
911 VK_SUBPASS_EXTERNAL, // dstSubpass
912 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
913 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
914 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
915 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
916 vk::VK_ACCESS_MEMORY_READ_BIT,
917 vk::VK_DEPENDENCY_BY_REGION_BIT
918 },
919 };
920 const vk::VkRenderPassCreateInfo renderPassParams =
921 {
922 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
923 DE_NULL,
924 (vk::VkRenderPassCreateFlags)0,
925 1u,
926 &colorAttDesc,
927 1u,
928 &subpassDesc,
929 DE_LENGTH_OF_ARRAY(dependencies),
930 dependencies,
931 };
932
933 return vk::createRenderPass(vkd, device, &renderPassParams);
934 }
935
createPipelineLayout(const vk::DeviceInterface & vkd,const vk::VkDevice device)936 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface& vkd,
937 const vk::VkDevice device)
938 {
939 const vk::VkPushConstantRange pushConstantRange =
940 {
941 vk::VK_SHADER_STAGE_VERTEX_BIT,
942 0u, // offset
943 (deUint32)sizeof(deUint32), // size
944 };
945 const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams =
946 {
947 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
948 DE_NULL,
949 (vk::VkPipelineLayoutCreateFlags)0,
950 0u, // setLayoutCount
951 DE_NULL, // pSetLayouts
952 1u,
953 &pushConstantRange,
954 };
955
956 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
957 }
958
createPipeline(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkRenderPass renderPass,const vk::VkPipelineLayout pipelineLayout,const vk::BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)959 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface& vkd,
960 const vk::VkDevice device,
961 const vk::VkRenderPass renderPass,
962 const vk::VkPipelineLayout pipelineLayout,
963 const vk::BinaryCollection& binaryCollection,
964 const tcu::UVec2& renderSize)
965 {
966 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
967 // and can be deleted immediately following that call.
968 const vk::Unique<vk::VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
969 const vk::Unique<vk::VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
970 const std::vector<vk::VkViewport> viewports (1, vk::makeViewport(renderSize));
971 const std::vector<vk::VkRect2D> scissors (1, vk::makeRect2D(renderSize));
972
973 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
974 device, // const VkDevice device
975 pipelineLayout, // const VkPipelineLayout pipelineLayout
976 *vertShaderModule, // const VkShaderModule vertexShaderModule
977 DE_NULL, // const VkShaderModule tessellationControlShaderModule
978 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
979 DE_NULL, // const VkShaderModule geometryShaderModule
980 *fragShaderModule, // const VkShaderModule fragmentShaderModule
981 renderPass, // const VkRenderPass renderPass
982 viewports, // const std::vector<VkViewport>& viewports
983 scissors); // const std::vector<VkRect2D>& scissors
984 }
985
TriangleRenderer(ProtectedContext & context,const vk::BinaryCollection & binaryRegistry,const std::vector<vk::VkImage> swapchainImages,const vk::VkFormat framebufferFormat,const tcu::UVec2 & renderSize)986 TriangleRenderer::TriangleRenderer (ProtectedContext& context,
987 const vk::BinaryCollection& binaryRegistry,
988 const std::vector<vk::VkImage> swapchainImages,
989 const vk::VkFormat framebufferFormat,
990 const tcu::UVec2& renderSize)
991 : m_vkd (context.getDeviceInterface())
992 , m_swapchainImages (swapchainImages)
993 , m_renderSize (renderSize)
994 , m_renderPass (createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
995 , m_pipelineLayout (createPipelineLayout(m_vkd, context.getDevice()))
996 , m_pipeline (createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
997 , m_vertexBuffer (makeBuffer(context,
998 PROTECTION_DISABLED,
999 context.getQueueFamilyIndex(),
1000 (deUint32)(sizeof(float)*4*3),
1001 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1002 vk::MemoryRequirement::HostVisible))
1003 {
1004 m_attachmentViews.resize(swapchainImages.size());
1005 m_framebuffers.resize(swapchainImages.size());
1006
1007 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1008 {
1009 m_attachmentViews[imageNdx] = ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
1010 m_framebuffers[imageNdx] = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
1011 renderSize.x(),
1012 renderSize.y(),
1013 *m_renderPass,
1014 **m_attachmentViews[imageNdx])));
1015 }
1016
1017 // Upload vertex data
1018 {
1019 const tcu::Vec4 vertices[] =
1020 {
1021 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1022 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1023 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1024 };
1025 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1026
1027 deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
1028 flushAlloc(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation());
1029 }
1030 }
1031
~TriangleRenderer(void)1032 TriangleRenderer::~TriangleRenderer (void)
1033 {
1034 }
1035
recordFrame(vk::VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const1036 void TriangleRenderer::recordFrame (vk::VkCommandBuffer cmdBuffer,
1037 deUint32 imageNdx,
1038 deUint32 frameNdx) const
1039 {
1040 const vk::VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
1041
1042 beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1043
1044 beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, vk::makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
1045 m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1046
1047 {
1048 const vk::VkDeviceSize bindingOffset = 0;
1049 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
1050 }
1051
1052 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1053 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1054 endRenderPass(m_vkd, cmdBuffer);
1055
1056 endCommandBuffer(m_vkd, cmdBuffer);
1057 }
1058
getPrograms(vk::SourceCollections & dst)1059 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
1060 {
1061 dst.glslSources.add("tri-vert") << glu::VertexSource(
1062 "#version 310 es\n"
1063 "layout(location = 0) in highp vec4 a_position;\n"
1064 "layout(push_constant) uniform FrameData\n"
1065 "{\n"
1066 " highp uint frameNdx;\n"
1067 "} frameData;\n"
1068 "void main (void)\n"
1069 "{\n"
1070 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
1071 " highp float c = cos(angle);\n"
1072 " highp float s = sin(angle);\n"
1073 " highp mat4 t = mat4( c, -s, 0, 0,\n"
1074 " s, c, 0, 0,\n"
1075 " 0, 0, 1, 0,\n"
1076 " 0, 0, 0, 1);\n"
1077 " gl_Position = t * a_position;\n"
1078 "}\n");
1079 dst.glslSources.add("tri-frag") << glu::FragmentSource(
1080 "#version 310 es\n"
1081 "layout(location = 0) out lowp vec4 o_color;\n"
1082 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1083 }
1084
1085 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> > CommandBufferSp;
1086 typedef de::SharedPtr<vk::Unique<vk::VkFence> > FenceSp;
1087 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> > SemaphoreSp;
1088
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)1089 std::vector<FenceSp> createFences (const vk::DeviceInterface& vkd,
1090 const vk::VkDevice device,
1091 size_t numFences)
1092 {
1093 std::vector<FenceSp> fences(numFences);
1094
1095 for (size_t ndx = 0; ndx < numFences; ++ndx)
1096 fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1097
1098 return fences;
1099 }
1100
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)1101 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface& vkd,
1102 const vk::VkDevice device,
1103 size_t numSemaphores)
1104 {
1105 std::vector<SemaphoreSp> semaphores(numSemaphores);
1106
1107 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1108 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1109
1110 return semaphores;
1111 }
1112
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)1113 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface& vkd,
1114 const vk::VkDevice device,
1115 const vk::VkCommandPool commandPool,
1116 const vk::VkCommandBufferLevel level,
1117 const size_t numCommandBuffers)
1118 {
1119 std::vector<CommandBufferSp> buffers (numCommandBuffers);
1120
1121 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1122 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1123
1124 return buffers;
1125 }
1126
basicRenderTest(Context & baseCtx,vk::wsi::Type wsiType)1127 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1128 {
1129 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1130 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, wsiType);
1131 std::vector<std::string> devExts;
1132 devExts.push_back("VK_KHR_swapchain");
1133
1134 const tcu::UVec2 desiredSize (256, 256);
1135 const NativeObjects native (baseCtx, supportedExtensions, wsiType, tcu::just(desiredSize));
1136 ProtectedContext context (baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1137 vk::VkSurfaceKHR surface = context.getSurface();
1138 const vk::DeviceInterface& vkd = context.getDeviceInterface();
1139 const vk::VkDevice device = context.getDevice();
1140 const vk::VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType,
1141 context.getInstanceDriver(),
1142 context.getPhysicalDevice(),
1143 surface,
1144 desiredSize,
1145 2);
1146 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1147 const std::vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1148
1149 const TriangleRenderer renderer (context,
1150 context.getBinaryCollection(),
1151 swapchainImages,
1152 swapchainInfo.imageFormat,
1153 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1154
1155 const vk::Unique<vk::VkCommandPool> commandPool (makeCommandPool(vkd, device, PROTECTION_ENABLED,
1156 context.getQueueFamilyIndex()));
1157
1158 const size_t maxQueuedFrames = swapchainImages.size()*2;
1159
1160 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1161 // limit number of frames we allow to be queued.
1162 const std::vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1163
1164 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1165 // the semaphore in same time as the fence we use to meter rendering.
1166 const std::vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1167
1168 // For rest we simply need maxQueuedFrames as we will wait for image
1169 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1170 // previous uses must have completed.
1171 const std::vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1172 const std::vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd,
1173 device,
1174 *commandPool,
1175 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1176 maxQueuedFrames));
1177
1178 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
1179 {
1180 // Check if swapchain can be created for protected surface
1181 const vk::InstanceInterface& vki = context.getInstanceDriver();
1182 vk::VkSurfaceCapabilities2KHR extCapabilities;
1183 vk::VkSurfaceProtectedCapabilitiesKHR extProtectedCapabilities;
1184 const vk::VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
1185 {
1186 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
1187 DE_NULL,
1188 surface
1189 };
1190
1191 extProtectedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
1192 extProtectedCapabilities.pNext = DE_NULL;
1193 extProtectedCapabilities.supportsProtected = DE_FALSE;
1194
1195 extCapabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1196 extCapabilities.pNext = &extProtectedCapabilities;
1197
1198 VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(context.getPhysicalDevice(), &surfaceInfo, &extCapabilities));
1199
1200 if (extProtectedCapabilities.supportsProtected == DE_FALSE)
1201 TCU_THROW(NotSupportedError, "Swapchain creation for Protected VkSurface is not Supported.");
1202 }
1203
1204 try
1205 {
1206 const deUint32 numFramesToRender = 60*10;
1207
1208 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1209 {
1210 const vk::VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1211 const vk::VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1212 deUint32 imageNdx = ~0u;
1213
1214 if (frameNdx >= maxQueuedFrames)
1215 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1216
1217 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1218
1219 {
1220 const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device,
1221 *swapchain,
1222 std::numeric_limits<deUint64>::max(),
1223 imageReadySemaphore,
1224 0,
1225 &imageNdx);
1226
1227 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1228 context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1229 else
1230 VK_CHECK(acquireResult);
1231 }
1232
1233 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1234
1235 {
1236 const vk::VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1237 const vk::VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1238 const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1239 vk::VkSubmitInfo submitInfo =
1240 {
1241 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1242 DE_NULL,
1243 1u,
1244 &imageReadySemaphore,
1245 &waitDstStage,
1246 1u,
1247 &commandBuffer,
1248 1u,
1249 &renderingCompleteSemaphore
1250 };
1251
1252 const vk::VkProtectedSubmitInfo protectedInfo =
1253 {
1254 vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, // sType
1255 DE_NULL, // pNext
1256 VK_TRUE, // protectedSubmit
1257 };
1258 submitInfo.pNext = &protectedInfo;
1259
1260 const vk::VkPresentInfoKHR presentInfo =
1261 {
1262 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1263 DE_NULL,
1264 1u,
1265 &renderingCompleteSemaphore,
1266 1u,
1267 &*swapchain,
1268 &imageNdx,
1269 (vk::VkResult*)DE_NULL
1270 };
1271
1272 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1273 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, imageReadyFence));
1274 VK_CHECK_WSI(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1275 }
1276 }
1277
1278 VK_CHECK(vkd.deviceWaitIdle(device));
1279 }
1280 catch (...)
1281 {
1282 // Make sure device is idle before destroying resources
1283 vkd.deviceWaitIdle(device);
1284 throw;
1285 }
1286
1287 return tcu::TestStatus::pass("Rendering tests succeeded");
1288 }
1289
getBasicRenderPrograms(vk::SourceCollections & dst,vk::wsi::Type)1290 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1291 {
1292 TriangleRenderer::getPrograms(dst);
1293 }
1294
checkSupport(Context & context,vk::wsi::Type)1295 void checkSupport (Context& context, vk::wsi::Type)
1296 {
1297 checkProtectedQueueSupport(context);
1298 }
1299
populateRenderGroup(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1300 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1301 {
1302 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", checkSupport, getBasicRenderPrograms, basicRenderTest, wsiType);
1303 }
1304
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1305 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1306 {
1307 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1308 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
1309 }
1310
createTypeSpecificTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1311 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1312 {
1313 addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
1314 }
1315
1316 } // anonymous
1317
createSwapchainTests(tcu::TestContext & testCtx)1318 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1319 {
1320 de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
1321
1322 for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1323 {
1324 const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
1325
1326 addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
1327 }
1328
1329 return wsiTestGroup.release();
1330 }
1331
1332 } // wsi
1333 } // vkt
1334