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