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