1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Advanced Micro Devices, Inc.
6 * Copyright (c) 2019 The Khronos Group Inc.
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 VK_EXT_frame_boundary tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktApiFrameBoundaryTests.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28
29 #include "vkCmdUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkWsiUtil.hpp"
35
36 #include "tcuTestLog.hpp"
37 #include "tcuPlatform.hpp"
38
39 #include <iostream>
40 #include <string>
41 #include <vector>
42
43 #include <string.h>
44
45 namespace vkt
46 {
47 namespace api
48 {
49 namespace
50 {
51
52 using namespace vk;
53
54 enum ExtensionUse
55 {
56 EXTENSION_USE_NONE,
57 EXTENSION_USE_SYNC2,
58 };
59
60 enum TestType
61 {
62 TEST_TYPE_SINGLE_FRAME,
63 TEST_TYPE_SINGLE_FRAME_MULTIPLE_SUBMISSIONS,
64 TEST_TYPE_MULTIPLE_FRAMES,
65 TEST_TYPE_MULTIPLE_FRAMES_MULTIPLE_SUBMISSIONS,
66 TEST_TYPE_MULTIPLE_OVERLAPPING_SUBMISSIONS,
67
68 TEST_TYPE_LAST,
69 };
70
71 struct TestParams
72 {
73 ExtensionUse m_extensionUse;
74 TestType m_testType;
75 };
76
checkSupport(Context & context,TestParams params)77 void checkSupport(Context &context, TestParams params)
78 {
79 context.requireDeviceFunctionality("VK_EXT_frame_boundary");
80
81 if (params.m_extensionUse == EXTENSION_USE_SYNC2)
82 context.requireDeviceFunctionality("VK_KHR_synchronization2");
83 }
84
checkWsiSupport(Context & context,vk::wsi::Type wsiType)85 void checkWsiSupport(Context &context, vk::wsi::Type wsiType)
86 {
87 context.requireDeviceFunctionality("VK_EXT_frame_boundary");
88
89 context.requireInstanceFunctionality("VK_KHR_surface");
90 context.requireInstanceFunctionality(vk::wsi::getExtensionName(wsiType));
91 context.requireDeviceFunctionality("VK_KHR_swapchain");
92 }
93
recordCommands(Context & context,VkCommandBuffer cmdBuffer,VkImage image)94 void recordCommands(Context &context, VkCommandBuffer cmdBuffer, VkImage image)
95 {
96 const DeviceInterface &vk = context.getDeviceInterface();
97
98 beginCommandBuffer(vk, cmdBuffer);
99
100 const VkImageMemoryBarrier imageBarrier = {
101 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
102 DE_NULL, // const void* pNext
103 0, // VkAccessFlags srcAccessMask
104 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask
105 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout
106 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout
107 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
108 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex
109 image, // VkImage image
110 {
111 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask
112 0u, // uint32_t baseMipLevel
113 VK_REMAINING_MIP_LEVELS, // uint32_t levelCount
114 0u, // uint32_t baseArrayLayer
115 VK_REMAINING_ARRAY_LAYERS, // uint32_t layerCount
116 }, // VkImageSubresourceRange subresourceRange
117 };
118
119 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, DE_NULL,
120 0, DE_NULL, 1, &imageBarrier);
121
122 const VkClearColorValue clearColor{{1.0f, 1.0f, 1.0f, 1.0f}};
123 const VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
124
125 vk.cmdClearColorImage(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1u, &range);
126 endCommandBuffer(vk, cmdBuffer);
127 }
128
submitCommands(ExtensionUse extensionUse,Context & context,VkCommandBuffer cmdBuffer,bool lastInFrame,uint32_t frameID,VkImage * pImages)129 void submitCommands(ExtensionUse extensionUse, Context &context, VkCommandBuffer cmdBuffer, bool lastInFrame,
130 uint32_t frameID, VkImage *pImages)
131 {
132 const DeviceInterface &vk = context.getDeviceInterface();
133 const VkDevice vkDevice = context.getDevice();
134
135 const VkFenceCreateInfo fenceParams = {
136 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType
137 DE_NULL, // const void* pNext
138 0u, // VkFenceCreateFlags flags
139 };
140
141 const Move<VkFence> fence = createFence(vk, vkDevice, &fenceParams);
142
143 VkFrameBoundaryEXT frameBoundary = {
144 VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT, // VkStructureType sType
145 DE_NULL, // const void* pNext
146 0u, // VkFrameBoundaryFlagsEXT flags
147 frameID, // uint64_t frameID
148 (lastInFrame ? 1u : 0u), // uint32_t imageCount
149 (lastInFrame ? pImages : DE_NULL), // const VkImage* pImages
150 0u, // uint32_t bufferCount;
151 DE_NULL, // VkBuffer* pBuffers;
152 0u, // uint64_t tagName
153 0u, // size_t tagSize
154 DE_NULL, // const void* pTag
155 };
156
157 if (lastInFrame)
158 frameBoundary.flags = VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT;
159
160 switch (extensionUse)
161 {
162 case EXTENSION_USE_NONE:
163 {
164 const VkSubmitInfo submitInfo = {
165 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType
166 &frameBoundary, // const void* pNext
167 0, // uint32_t waitSemaphoreCount
168 DE_NULL, // const VkSemaphore* pWaitSemaphores
169 DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask
170 1, // uint32_t commandBufferCount
171 &cmdBuffer, // const VkCommandBuffer* pCommandBuffers
172 0u, // uint32_t signalSemaphoreCount
173 DE_NULL, // const VkSemaphore* pSignalSemaphores
174 };
175
176 VK_CHECK(vk.queueSubmit(context.getUniversalQueue(), 1, &submitInfo, *fence));
177 break;
178 }
179 case EXTENSION_USE_SYNC2:
180 {
181 const VkCommandBufferSubmitInfo cmdBufferSubmitInfo = {
182 VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR, // VkStructureType sType
183 DE_NULL, // const void* pNext
184 cmdBuffer, // VkCommandBuffer commandBuffer
185 0u, // uint32_t deviceMask
186 };
187
188 const VkSubmitInfo2 submitInfo2KHR = {
189 VK_STRUCTURE_TYPE_SUBMIT_INFO_2, // VkStructureType sType
190 &frameBoundary, // const void* pNext
191 0u, // VkSubmitFlagsKHR flags
192 0u, // uint32_t waitSemaphoreInfoCount
193 DE_NULL, // const VkSemaphoreSubmitInfo* pWaitSemaphoreInfos
194 1u, // uint32_t commandBufferInfoCount
195 &cmdBufferSubmitInfo, // const VkCommandBufferSubmitInfo* pCommandBufferInfos
196 0u, // uint32_t signalSemaphoreInfoCount
197 DE_NULL, // const VkSemaphoreSubmitInfo* pSignalSemaphoreInfos
198 };
199
200 VK_CHECK(vk.queueSubmit2(context.getUniversalQueue(), 1, &submitInfo2KHR, *fence));
201 break;
202 }
203 default:
204 DE_ASSERT(false);
205 }
206
207 VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~0ull));
208 }
209
testCase(Context & context,TestParams params)210 tcu::TestStatus testCase(Context &context, TestParams params)
211 {
212 const DeviceInterface &vk = context.getDeviceInterface();
213 const VkDevice vkDevice = context.getDevice();
214
215 const VkExtent3D extent{16, 16, 1};
216 const VkImageCreateInfo imageParams = {
217 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
218 DE_NULL, // const void* pNext
219 0u, // VkImageCreateFlags flags
220 VK_IMAGE_TYPE_2D, // VkImageType imageType
221 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
222 extent, // VkExtent3D extent
223 1u, // uint32_t mipLevels
224 1u, // uint32_t arraySize
225 VK_SAMPLE_COUNT_1_BIT, // uint32_t samples
226 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
227 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage
228 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
229 0u, // uint32_t queueFamilyIndexCount
230 (const uint32_t *)DE_NULL, // const uint32_t* pQueueFamilyIndices
231 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
232 };
233
234 Move<VkImage> image = createImage(vk, vkDevice, &imageParams);
235 VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vk, vkDevice, *image);
236 de::MovePtr<Allocation> imageAllocation =
237 context.getDefaultAllocator().allocate(memoryRequirements, MemoryRequirement::Any);
238 VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageAllocation->getMemory(), 0u));
239
240 Move<VkCommandPool> cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
241 context.getUniversalQueueFamilyIndex());
242 Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
243 VkImage frameImages[] = {*image};
244
245 recordCommands(context, *cmdBuffer, *image);
246
247 switch (params.m_testType)
248 {
249 case TEST_TYPE_SINGLE_FRAME:
250 {
251 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, 1, frameImages);
252 break;
253 }
254 case TEST_TYPE_SINGLE_FRAME_MULTIPLE_SUBMISSIONS:
255 {
256 for (uint32_t i = 0; i < 4; i++)
257 {
258 bool lastInFrame = (i == 3);
259 submitCommands(params.m_extensionUse, context, *cmdBuffer, lastInFrame, 1, frameImages);
260 }
261
262 break;
263 }
264 case TEST_TYPE_MULTIPLE_FRAMES:
265 {
266 for (uint32_t i = 1; i <= 4; i++)
267 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, i, frameImages);
268
269 break;
270 }
271 case TEST_TYPE_MULTIPLE_FRAMES_MULTIPLE_SUBMISSIONS:
272 {
273 for (uint32_t i = 1; i <= 4; i++)
274 {
275 submitCommands(params.m_extensionUse, context, *cmdBuffer, false, i, frameImages);
276 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, i, frameImages);
277 }
278
279 break;
280 }
281 case TEST_TYPE_MULTIPLE_OVERLAPPING_SUBMISSIONS:
282 {
283 submitCommands(params.m_extensionUse, context, *cmdBuffer, false, 1, frameImages);
284 submitCommands(params.m_extensionUse, context, *cmdBuffer, false, 2, frameImages);
285 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, 1, frameImages);
286 submitCommands(params.m_extensionUse, context, *cmdBuffer, false, 3, frameImages);
287 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, 2, frameImages);
288 submitCommands(params.m_extensionUse, context, *cmdBuffer, false, 4, frameImages);
289 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, 3, frameImages);
290 submitCommands(params.m_extensionUse, context, *cmdBuffer, true, 4, frameImages);
291 break;
292 }
293 default:
294 DE_ASSERT(false);
295 }
296
297 return tcu::TestStatus::pass("Pass");
298 }
299
300 typedef std::vector<VkExtensionProperties> Extensions;
301
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,wsi::Type wsiType)302 de::MovePtr<wsi::Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions,
303 wsi::Type wsiType)
304 {
305 try
306 {
307 return de::MovePtr<wsi::Display>(platform.createWsiDisplay(wsiType));
308 }
309 catch (const tcu::NotSupportedError &e)
310 {
311 if (isExtensionStructSupported(supportedExtensions, RequiredExtension(wsi::getExtensionName(wsiType))) &&
312 platform.hasDisplay(wsiType))
313 {
314 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
315 // must support creating native display & window for that WSI type.
316 throw tcu::TestError(e.getMessage());
317 }
318 else
319 throw;
320 }
321 }
322
createWindow(const wsi::Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)323 de::MovePtr<wsi::Window> createWindow(const wsi::Display &display, const tcu::Maybe<tcu::UVec2> &initialSize)
324 {
325 try
326 {
327 return de::MovePtr<wsi::Window>(display.createWindow(initialSize));
328 }
329 catch (const tcu::NotSupportedError &e)
330 {
331 // See createDisplay - assuming that wsi::Display was supported platform port
332 // should also support creating a window.
333 throw tcu::TestError(e.getMessage());
334 }
335 }
336
337 struct NativeObjects
338 {
339 const de::UniquePtr<wsi::Display> display;
340 const de::UniquePtr<wsi::Window> window;
341
NativeObjectsvkt::api::__anon13ec37ef0111::NativeObjects342 NativeObjects(Context &context, const Extensions &supportedExtensions, wsi::Type wsiType,
343 const tcu::Maybe<tcu::UVec2> &initialWindowSize = tcu::Nothing)
344 : display(
345 createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
346 , window(createWindow(*display, initialWindowSize))
347 {
348 }
349 };
350
createSwapchain(Context & context,VkSurfaceKHR surface)351 Move<VkSwapchainKHR> createSwapchain(Context &context, VkSurfaceKHR surface)
352 {
353 const InstanceInterface &vki = context.getInstanceInterface();
354 const DeviceInterface &vk = context.getDeviceInterface();
355 const VkDevice vkDevice = context.getDevice();
356 const VkPhysicalDevice vkPhysicalDevice = context.getPhysicalDevice();
357
358 const VkSurfaceCapabilitiesKHR capabilities =
359 wsi::getPhysicalDeviceSurfaceCapabilities(vki, vkPhysicalDevice, surface);
360
361 if (!(capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
362 TCU_THROW(NotSupportedError, "supportedUsageFlags does not contain VK_IMAGE_USAGE_TRANSFER_DST_BIT");
363
364 const std::vector<VkSurfaceFormatKHR> surfaceFormats =
365 wsi::getPhysicalDeviceSurfaceFormats(vki, vkPhysicalDevice, surface);
366
367 const VkSurfaceFormatKHR surfaceFormat = surfaceFormats[0];
368
369 const VkExtent2D swapchainExtent = {
370 de::clamp(16u, capabilities.minImageExtent.width, capabilities.maxImageExtent.width),
371 de::clamp(16u, capabilities.minImageExtent.height, capabilities.maxImageExtent.height)};
372
373 const VkSwapchainCreateInfoKHR swapchainParams = {
374 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // VkStructureType sType
375 DE_NULL, // const void* pNext
376 0u, // VkSwapchainCreateFlagsKHR flags
377 surface, // VkSurfaceKHR surface
378 std::max(1u, capabilities.minImageCount), // uint32_t minImageCount
379 surfaceFormat.format, // VkFormat imageFormat
380 surfaceFormat.colorSpace, // VkColorSpaceKHR imageColorSpace
381 swapchainExtent, // VkExtent2D imageExtent
382 1, // uint32_t imageArrayLayers
383 VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags imageUsage
384 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode imageSharingMode
385 0u, // uint32_t queueFamilyIndexCount
386 (const uint32_t *)DE_NULL, // const uint32_t* pQueueFamilyIndices
387 capabilities.currentTransform, // VkSurfaceTransformFlagBitsKHR preTransform
388 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, // VkCompositeAlphaFlagBitsKHR compositeAlpha
389 VK_PRESENT_MODE_FIFO_KHR, // VkPresentModeKHR presentMode
390 VK_FALSE, // VkBool32 clipped
391 (VkSwapchainKHR)0 // VkSwapchainKHR oldSwapchain
392 };
393
394 return createSwapchainKHR(vk, vkDevice, &swapchainParams);
395 }
396
testCaseWsi(Context & context,vk::wsi::Type wsiType)397 tcu::TestStatus testCaseWsi(Context &context, vk::wsi::Type wsiType)
398 {
399 const InstanceInterface &vki = context.getInstanceInterface();
400 const DeviceInterface &vk = context.getDeviceInterface();
401 const VkInstance vkInstance = context.getInstance();
402 const VkDevice vkDevice = context.getDevice();
403
404 const NativeObjects native(context, enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL),
405 wsiType);
406 const Unique<VkSurfaceKHR> surface(wsi::createSurface(vki, vkInstance, wsiType, *native.display, *native.window,
407 context.getTestContext().getCommandLine()));
408 const Unique<VkSwapchainKHR> swapchain(createSwapchain(context, *surface));
409 const std::vector<VkImage> swapchainImages = wsi::getSwapchainImages(vk, vkDevice, *swapchain);
410
411 const Move<VkCommandPool> cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
412 context.getUniversalQueueFamilyIndex());
413 const Move<VkCommandBuffer> cmdBuffer =
414 allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
415
416 const VkSemaphoreCreateInfo semaphoreCreateInfo = {
417 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // VkStructureType sType;
418 DE_NULL, // const void* pNext;
419 0u, // VkSemaphoreCreateFlags flags;
420 };
421
422 const Move<VkSemaphore> acquireSemaphore = createSemaphore(vk, vkDevice, &semaphoreCreateInfo);
423
424 VkSemaphore acquireSemaphores[] = {*acquireSemaphore};
425 VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
426
427 uint32_t currentBuffer = 0;
428 VK_CHECK(vk.acquireNextImageKHR(vkDevice, *swapchain, ~0ull, *acquireSemaphore, VK_NULL_HANDLE, ¤tBuffer));
429
430 recordCommands(context, *cmdBuffer, swapchainImages[currentBuffer]);
431
432 submitCommandsAndWait(vk, vkDevice, context.getUniversalQueue(), *cmdBuffer, false, 0U, 1U, acquireSemaphores,
433 waitStageMask);
434
435 VkSwapchainKHR swapchains[] = {*swapchain};
436 VkImage frameImages[] = {swapchainImages[currentBuffer]};
437
438 const VkFrameBoundaryEXT frameBoundary = {
439 VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT, // VkStructureType sType
440 DE_NULL, // const void* pNext
441 VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT, // VkFrameBoundaryFlagsEXT flags
442 1, // uint64_t frameID
443 1u, // uint32_t imageCount
444 frameImages, // const VkImage* pImages
445 0u, // uint32_t bufferCount;
446 DE_NULL, // VkBuffer* pBuffers;
447 0u, // uint64_t tagName
448 0u, // size_t tagSize
449 DE_NULL, // const void* pTag
450 };
451
452 const VkPresentInfoKHR presentInfo = {
453 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // VkStructureType sType;
454 &frameBoundary, // const void* pNext;
455 0U, // uint32_t waitSemaphoreCount;
456 DE_NULL, // const VkSemaphore* pWaitSemaphores;
457 1U, // uint32_t swapchainCount;
458 swapchains, // const VkSwapchainKHR* pSwapchains;
459 ¤tBuffer, // const uint32_t* pImageIndices;
460 DE_NULL, // VkResult* pResults;
461 };
462
463 VK_CHECK(vk.queuePresentKHR(context.getUniversalQueue(), &presentInfo));
464
465 return tcu::TestStatus::pass("Pass");
466 }
467
createExecTestCases(tcu::TestCaseGroup * group,ExtensionUse extensionUse)468 void createExecTestCases(tcu::TestCaseGroup *group, ExtensionUse extensionUse)
469 {
470 const std::string testName[TEST_TYPE_LAST] = {
471 "single_frame",
472 "single_frame_multi_submissions",
473 "multi_frame",
474 "multi_frame_multi_submissions",
475 "multi_frame_overlapping_submissions",
476 };
477
478 for (uint32_t testType = 0; testType < TEST_TYPE_LAST; testType++)
479 {
480 TestParams testParams{extensionUse, (TestType)testType};
481 addFunctionCase(group, testName[testType], checkSupport, testCase, testParams);
482 }
483 }
484
createWsiTestCases(tcu::TestCaseGroup * group)485 void createWsiTestCases(tcu::TestCaseGroup *group)
486 {
487 for (uint32_t wsiType = 0; wsiType < wsi::TYPE_LAST; wsiType++)
488 {
489 addFunctionCase(group, wsi::getName((wsi::Type)wsiType), checkWsiSupport, testCaseWsi, (wsi::Type)wsiType);
490 }
491 }
492
createTestCases(tcu::TestCaseGroup * group)493 void createTestCases(tcu::TestCaseGroup *group)
494 {
495 // VK_EXT_frame_boundary tests
496 addTestGroup(group, "core", createExecTestCases, EXTENSION_USE_NONE);
497 addTestGroup(group, "sync2", createExecTestCases, EXTENSION_USE_SYNC2);
498 addTestGroup(group, "wsi", createWsiTestCases);
499 }
500
501 } // namespace
502
createFrameBoundaryTests(tcu::TestContext & testCtx)503 tcu::TestCaseGroup *createFrameBoundaryTests(tcu::TestContext &testCtx)
504 {
505 // VK_EXT_frame_boundary tests
506 return createTestGroup(testCtx, "frame_boundary", createTestCases);
507 }
508
509 } // namespace api
510 } // namespace vkt
511