1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSwapchainTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkWsiPlatform.hpp"
41 #include "vkWsiUtil.hpp"
42 #include "vkAllocationCallbackUtil.hpp"
43 #include "vkCmdUtil.hpp"
44 #include "vkObjUtil.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 namespace vkt
59 {
60 namespace wsi
61 {
62
63 namespace
64 {
65
66 using namespace vk;
67 using namespace vk::wsi;
68
69 using tcu::TestLog;
70 using tcu::Maybe;
71 using tcu::UVec2;
72
73 using de::MovePtr;
74 using de::UniquePtr;
75
76 using std::string;
77 using std::vector;
78
79 typedef vector<VkExtensionProperties> Extensions;
80
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)81 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
82 {
83 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
84 requiredExtName != requiredExtensions.end();
85 ++requiredExtName)
86 {
87 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
88 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
89 }
90 }
91
createInstanceWithWsi(const PlatformInterface & vkp,deUint32 version,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)92 Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
93 deUint32 version,
94 const Extensions& supportedExtensions,
95 Type wsiType,
96 const VkAllocationCallbacks* pAllocator = DE_NULL)
97 {
98 vector<string> extensions;
99
100 extensions.push_back("VK_KHR_surface");
101 extensions.push_back(getExtensionName(wsiType));
102
103 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
104 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
105 // but using them without enabling the extension is not allowed. Thus we have
106 // two options:
107 //
108 // 1) Filter out non-core formats to stay within valid usage.
109 //
110 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
111 //
112 // We opt for (2) as it provides basic coverage for the extension as a bonus.
113 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
114 extensions.push_back("VK_EXT_swapchain_colorspace");
115
116 checkAllSupported(supportedExtensions, extensions);
117
118 return createDefaultInstance(vkp, version, vector<string>(), extensions, pAllocator);
119 }
120
getDeviceFeaturesForWsi(void)121 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
122 {
123 VkPhysicalDeviceFeatures features;
124 deMemset(&features, 0, sizeof(features));
125 return features;
126 }
127
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,const VkAllocationCallbacks * pAllocator=DE_NULL)128 Move<VkDevice> createDeviceWithWsi (const vk::PlatformInterface& vkp,
129 vk::VkInstance instance,
130 const InstanceInterface& vki,
131 VkPhysicalDevice physicalDevice,
132 const Extensions& supportedExtensions,
133 const deUint32 queueFamilyIndex,
134 const VkAllocationCallbacks* pAllocator = DE_NULL)
135 {
136 const float queuePriorities[] = { 1.0f };
137 const VkDeviceQueueCreateInfo queueInfos[] =
138 {
139 {
140 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
141 DE_NULL,
142 (VkDeviceQueueCreateFlags)0,
143 queueFamilyIndex,
144 DE_LENGTH_OF_ARRAY(queuePriorities),
145 &queuePriorities[0]
146 }
147 };
148 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
149 vector<const char*> extensions;
150
151 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_swapchain")))
152 TCU_THROW(NotSupportedError, (string(extensions[0]) + " is not supported").c_str());
153 extensions.push_back("VK_KHR_swapchain");
154
155 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
156 extensions.push_back("VK_EXT_hdr_metadata");
157
158 const VkDeviceCreateInfo deviceParams =
159 {
160 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
161 DE_NULL,
162 (VkDeviceCreateFlags)0,
163 DE_LENGTH_OF_ARRAY(queueInfos),
164 &queueInfos[0],
165 0u, // enabledLayerCount
166 DE_NULL, // ppEnabledLayerNames
167 (deUint32)extensions.size(),
168 extensions.empty() ? DE_NULL : &extensions[0],
169 &features
170 };
171
172 return createDevice(vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
173 }
174
getNumQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice)175 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
176 {
177 deUint32 numFamilies = 0;
178
179 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
180
181 return numFamilies;
182 }
183
getSupportedQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)184 vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
185 {
186 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
187 vector<deUint32> supportedFamilyIndices;
188
189 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
190 {
191 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
192 supportedFamilyIndices.push_back(queueFamilyNdx);
193 }
194
195 return supportedFamilyIndices;
196 }
197
chooseQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)198 deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
199 {
200 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
201
202 if (supportedFamilyIndices.empty())
203 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
204
205 return supportedFamilyIndices[0];
206 }
207
208 struct InstanceHelper
209 {
210 const vector<VkExtensionProperties> supportedExtensions;
211 const Unique<VkInstance> instance;
212 const InstanceDriver vki;
213
InstanceHelpervkt::wsi::__anon345ad5070111::InstanceHelper214 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
215 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
216 DE_NULL))
217 , instance (createInstanceWithWsi(context.getPlatformInterface(),
218 context.getUsedApiVersion(),
219 supportedExtensions,
220 wsiType,
221 pAllocator))
222 , vki (context.getPlatformInterface(), *instance)
223 {}
224 };
225
226 struct DeviceHelper
227 {
228 const VkPhysicalDevice physicalDevice;
229 const deUint32 queueFamilyIndex;
230 const Unique<VkDevice> device;
231 const DeviceDriver vkd;
232 const VkQueue queue;
233
DeviceHelpervkt::wsi::__anon345ad5070111::DeviceHelper234 DeviceHelper (Context& context,
235 const InstanceInterface& vki,
236 VkInstance instance,
237 VkSurfaceKHR surface,
238 const VkAllocationCallbacks* pAllocator = DE_NULL)
239 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
240 , queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
241 , device (createDeviceWithWsi(context.getPlatformInterface(),
242 instance,
243 vki,
244 physicalDevice,
245 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
246 queueFamilyIndex,
247 pAllocator))
248 , vkd (context.getPlatformInterface(), instance, *device)
249 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
250 {
251 }
252 };
253
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,Type wsiType)254 MovePtr<Display> createDisplay (const vk::Platform& platform,
255 const Extensions& supportedExtensions,
256 Type wsiType)
257 {
258 try
259 {
260 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
261 }
262 catch (const tcu::NotSupportedError& e)
263 {
264 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
265 platform.hasDisplay(wsiType))
266 {
267 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
268 // must support creating native display & window for that WSI type.
269 throw tcu::TestError(e.getMessage());
270 }
271 else
272 throw;
273 }
274 }
275
createWindow(const Display & display,const Maybe<UVec2> & initialSize)276 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
277 {
278 try
279 {
280 return MovePtr<Window>(display.createWindow(initialSize));
281 }
282 catch (const tcu::NotSupportedError& e)
283 {
284 // See createDisplay - assuming that wsi::Display was supported platform port
285 // should also support creating a window.
286 throw tcu::TestError(e.getMessage());
287 }
288 }
289
290 struct NativeObjects
291 {
292 const UniquePtr<Display> display;
293 const UniquePtr<Window> window;
294
NativeObjectsvkt::wsi::__anon345ad5070111::NativeObjects295 NativeObjects (Context& context,
296 const Extensions& supportedExtensions,
297 Type wsiType,
298 const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
299 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
300 , window (createWindow(*display, initialWindowSize))
301 {}
302 };
303
304 enum TestDimension
305 {
306 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
307 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
308 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
309 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
310 TEST_DIMENSION_IMAGE_USAGE,
311 TEST_DIMENSION_IMAGE_SHARING_MODE,
312 TEST_DIMENSION_PRE_TRANSFORM,
313 TEST_DIMENSION_COMPOSITE_ALPHA,
314 TEST_DIMENSION_PRESENT_MODE,
315 TEST_DIMENSION_CLIPPED,
316
317 TEST_DIMENSION_LAST
318 };
319
320 struct TestParameters
321 {
322 Type wsiType;
323 TestDimension dimension;
324
TestParametersvkt::wsi::__anon345ad5070111::TestParameters325 TestParameters (Type wsiType_, TestDimension dimension_)
326 : wsiType (wsiType_)
327 , dimension (dimension_)
328 {}
329
TestParametersvkt::wsi::__anon345ad5070111::TestParameters330 TestParameters (void)
331 : wsiType (TYPE_LAST)
332 , dimension (TEST_DIMENSION_LAST)
333 {}
334 };
335
336 struct GroupParameters
337 {
338 typedef FunctionInstance1<TestParameters>::Function Function;
339
340 Type wsiType;
341 Function function;
342
GroupParametersvkt::wsi::__anon345ad5070111::GroupParameters343 GroupParameters (Type wsiType_, Function function_)
344 : wsiType (wsiType_)
345 , function (function_)
346 {}
347
GroupParametersvkt::wsi::__anon345ad5070111::GroupParameters348 GroupParameters (void)
349 : wsiType (TYPE_LAST)
350 , function ((Function)DE_NULL)
351 {}
352 };
353
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceFormatKHR surfaceFormat,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)354 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
355 const InstanceInterface& vki,
356 VkPhysicalDevice physicalDevice,
357 VkSurfaceKHR surface,
358 VkSurfaceFormatKHR surfaceFormat,
359 const tcu::UVec2& desiredSize,
360 deUint32 desiredImageCount)
361 {
362 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
363 physicalDevice,
364 surface);
365 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
366 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
367 const VkSwapchainCreateInfoKHR parameters =
368 {
369 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
370 DE_NULL,
371 (VkSwapchainCreateFlagsKHR)0,
372 surface,
373 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
374 surfaceFormat.format,
375 surfaceFormat.colorSpace,
376 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
377 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
378 1u, // imageArrayLayers
379 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
380 VK_SHARING_MODE_EXCLUSIVE,
381 0u,
382 (const deUint32*)DE_NULL,
383 transform,
384 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
385 VK_PRESENT_MODE_FIFO_KHR,
386 VK_FALSE, // clipped
387 (VkSwapchainKHR)0 // oldSwapchain
388 };
389
390 return parameters;
391 }
392
393 typedef de::SharedPtr<Unique<VkImageView> > ImageViewSp;
394 typedef de::SharedPtr<Unique<VkFramebuffer> > FramebufferSp;
395
396 class TriangleRenderer
397 {
398 public:
399 TriangleRenderer (const DeviceInterface& vkd,
400 const VkDevice device,
401 Allocator& allocator,
402 const BinaryCollection& binaryRegistry,
403 const vector<VkImage> swapchainImages,
404 const VkFormat framebufferFormat,
405 const UVec2& renderSize);
406 ~TriangleRenderer (void);
407
408 void recordFrame (VkCommandBuffer cmdBuffer,
409 deUint32 imageNdx,
410 deUint32 frameNdx) const;
411
412 static void getPrograms (SourceCollections& dst);
413
414 private:
415 static Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
416 const VkDevice device,
417 const VkFormat colorAttachmentFormat);
418 static Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vkd,
419 VkDevice device);
420 static Move<VkPipeline> createPipeline (const DeviceInterface& vkd,
421 const VkDevice device,
422 const VkRenderPass renderPass,
423 const VkPipelineLayout pipelineLayout,
424 const BinaryCollection& binaryCollection,
425 const UVec2& renderSize);
426
427 static Move<VkImageView> createAttachmentView(const DeviceInterface& vkd,
428 const VkDevice device,
429 const VkImage image,
430 const VkFormat format);
431 static Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd,
432 const VkDevice device,
433 const VkRenderPass renderPass,
434 const VkImageView colorAttachment,
435 const UVec2& renderSize);
436
437 static Move<VkBuffer> createBuffer (const DeviceInterface& vkd,
438 VkDevice device,
439 VkDeviceSize size,
440 VkBufferUsageFlags usage);
441
442 const DeviceInterface& m_vkd;
443
444 const vector<VkImage> m_swapchainImages;
445 const tcu::UVec2 m_renderSize;
446
447 const Unique<VkRenderPass> m_renderPass;
448 const Unique<VkPipelineLayout> m_pipelineLayout;
449 const Unique<VkPipeline> m_pipeline;
450
451 const Unique<VkBuffer> m_vertexBuffer;
452 const UniquePtr<Allocation> m_vertexBufferMemory;
453
454 vector<ImageViewSp> m_attachmentViews;
455 vector<FramebufferSp> m_framebuffers;
456 };
457
createRenderPass(const DeviceInterface & vkd,const VkDevice device,const VkFormat colorAttachmentFormat)458 Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface& vkd,
459 const VkDevice device,
460 const VkFormat colorAttachmentFormat)
461 {
462 const VkAttachmentDescription colorAttDesc =
463 {
464 (VkAttachmentDescriptionFlags)0,
465 colorAttachmentFormat,
466 VK_SAMPLE_COUNT_1_BIT,
467 VK_ATTACHMENT_LOAD_OP_CLEAR,
468 VK_ATTACHMENT_STORE_OP_STORE,
469 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
470 VK_ATTACHMENT_STORE_OP_DONT_CARE,
471 VK_IMAGE_LAYOUT_UNDEFINED,
472 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
473 };
474 const VkAttachmentReference colorAttRef =
475 {
476 0u,
477 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
478 };
479 const VkSubpassDescription subpassDesc =
480 {
481 (VkSubpassDescriptionFlags)0u,
482 VK_PIPELINE_BIND_POINT_GRAPHICS,
483 0u, // inputAttachmentCount
484 DE_NULL, // pInputAttachments
485 1u, // colorAttachmentCount
486 &colorAttRef, // pColorAttachments
487 DE_NULL, // pResolveAttachments
488 DE_NULL, // depthStencilAttachment
489 0u, // preserveAttachmentCount
490 DE_NULL, // pPreserveAttachments
491 };
492 const VkSubpassDependency dependencies[] =
493 {
494 {
495 VK_SUBPASS_EXTERNAL, // srcSubpass
496 0u, // dstSubpass
497 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
498 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
499 VK_ACCESS_MEMORY_READ_BIT,
500 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
501 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
502 VK_DEPENDENCY_BY_REGION_BIT
503 },
504 {
505 0u, // srcSubpass
506 VK_SUBPASS_EXTERNAL, // dstSubpass
507 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
508 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
509 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
510 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
511 VK_ACCESS_MEMORY_READ_BIT,
512 VK_DEPENDENCY_BY_REGION_BIT
513 },
514 };
515 const VkRenderPassCreateInfo renderPassParams =
516 {
517 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
518 DE_NULL,
519 (VkRenderPassCreateFlags)0,
520 1u,
521 &colorAttDesc,
522 1u,
523 &subpassDesc,
524 DE_LENGTH_OF_ARRAY(dependencies),
525 dependencies,
526 };
527
528 return vk::createRenderPass(vkd, device, &renderPassParams);
529 }
530
createPipelineLayout(const DeviceInterface & vkd,const VkDevice device)531 Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface& vkd,
532 const VkDevice device)
533 {
534 const VkPushConstantRange pushConstantRange =
535 {
536 VK_SHADER_STAGE_VERTEX_BIT,
537 0u, // offset
538 (deUint32)sizeof(deUint32), // size
539 };
540 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
541 {
542 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
543 DE_NULL,
544 (vk::VkPipelineLayoutCreateFlags)0,
545 0u, // setLayoutCount
546 DE_NULL, // pSetLayouts
547 1u,
548 &pushConstantRange,
549 };
550
551 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
552 }
553
createPipeline(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkPipelineLayout pipelineLayout,const BinaryCollection & binaryCollection,const UVec2 & renderSize)554 Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface& vkd,
555 const VkDevice device,
556 const VkRenderPass renderPass,
557 const VkPipelineLayout pipelineLayout,
558 const BinaryCollection& binaryCollection,
559 const UVec2& renderSize)
560 {
561 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
562 // and can be deleted immediately following that call.
563 const Unique<VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
564 const Unique<VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
565 const std::vector<VkViewport> viewports (1, makeViewport(renderSize));
566 const std::vector<VkRect2D> scissors (1, makeRect2D(renderSize));
567
568 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
569 device, // const VkDevice device
570 pipelineLayout, // const VkPipelineLayout pipelineLayout
571 *vertShaderModule, // const VkShaderModule vertexShaderModule
572 DE_NULL, // const VkShaderModule tessellationControlShaderModule
573 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
574 DE_NULL, // const VkShaderModule geometryShaderModule
575 *fragShaderModule, // const VkShaderModule fragmentShaderModule
576 renderPass, // const VkRenderPass renderPass
577 viewports, // const std::vector<VkViewport>& viewports
578 scissors); // const std::vector<VkRect2D>& scissors
579 }
580
createAttachmentView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format)581 Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface& vkd,
582 const VkDevice device,
583 const VkImage image,
584 const VkFormat format)
585 {
586 const VkImageViewCreateInfo viewParams =
587 {
588 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
589 DE_NULL,
590 (VkImageViewCreateFlags)0,
591 image,
592 VK_IMAGE_VIEW_TYPE_2D,
593 format,
594 vk::makeComponentMappingRGBA(),
595 {
596 VK_IMAGE_ASPECT_COLOR_BIT,
597 0u, // baseMipLevel
598 1u, // levelCount
599 0u, // baseArrayLayer
600 1u, // layerCount
601 },
602 };
603
604 return vk::createImageView(vkd, device, &viewParams);
605 }
606
createFramebuffer(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkImageView colorAttachment,const UVec2 & renderSize)607 Move<VkFramebuffer> TriangleRenderer::createFramebuffer (const DeviceInterface& vkd,
608 const VkDevice device,
609 const VkRenderPass renderPass,
610 const VkImageView colorAttachment,
611 const UVec2& renderSize)
612 {
613 const VkFramebufferCreateInfo framebufferParams =
614 {
615 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
616 DE_NULL,
617 (VkFramebufferCreateFlags)0,
618 renderPass,
619 1u,
620 &colorAttachment,
621 renderSize.x(),
622 renderSize.y(),
623 1u, // layers
624 };
625
626 return vk::createFramebuffer(vkd, device, &framebufferParams);
627 }
628
createBuffer(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,VkBufferUsageFlags usage)629 Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface& vkd,
630 VkDevice device,
631 VkDeviceSize size,
632 VkBufferUsageFlags usage)
633 {
634 const VkBufferCreateInfo bufferParams =
635 {
636 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
637 DE_NULL,
638 (VkBufferCreateFlags)0,
639 size,
640 usage,
641 VK_SHARING_MODE_EXCLUSIVE,
642 0,
643 DE_NULL
644 };
645
646 return vk::createBuffer(vkd, device, &bufferParams);
647 }
648
TriangleRenderer(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,const BinaryCollection & binaryRegistry,const vector<VkImage> swapchainImages,const VkFormat framebufferFormat,const UVec2 & renderSize)649 TriangleRenderer::TriangleRenderer (const DeviceInterface& vkd,
650 const VkDevice device,
651 Allocator& allocator,
652 const BinaryCollection& binaryRegistry,
653 const vector<VkImage> swapchainImages,
654 const VkFormat framebufferFormat,
655 const UVec2& renderSize)
656 : m_vkd (vkd)
657 , m_swapchainImages (swapchainImages)
658 , m_renderSize (renderSize)
659 , m_renderPass (createRenderPass(vkd, device, framebufferFormat))
660 , m_pipelineLayout (createPipelineLayout(vkd, device))
661 , m_pipeline (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
662 , m_vertexBuffer (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
663 , m_vertexBufferMemory (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
664 MemoryRequirement::HostVisible))
665 {
666 m_attachmentViews.resize(swapchainImages.size());
667 m_framebuffers.resize(swapchainImages.size());
668
669 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
670 {
671 m_attachmentViews[imageNdx] = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
672 m_framebuffers[imageNdx] = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
673 }
674
675 VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
676
677 {
678 const VkMappedMemoryRange memRange =
679 {
680 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
681 DE_NULL,
682 m_vertexBufferMemory->getMemory(),
683 m_vertexBufferMemory->getOffset(),
684 VK_WHOLE_SIZE
685 };
686 const tcu::Vec4 vertices[] =
687 {
688 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
689 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
690 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
691 };
692 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
693
694 deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
695 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
696 }
697 }
698
~TriangleRenderer(void)699 TriangleRenderer::~TriangleRenderer (void)
700 {
701 }
702
recordFrame(VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const703 void TriangleRenderer::recordFrame (VkCommandBuffer cmdBuffer,
704 deUint32 imageNdx,
705 deUint32 frameNdx) const
706 {
707 const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
708
709 beginCommandBuffer(m_vkd, cmdBuffer, 0u);
710
711 beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
712
713 m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
714
715 {
716 const VkDeviceSize bindingOffset = 0;
717 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
718 }
719
720 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
721 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
722 endRenderPass(m_vkd, cmdBuffer);
723
724 endCommandBuffer(m_vkd, cmdBuffer);
725 }
726
getPrograms(SourceCollections & dst)727 void TriangleRenderer::getPrograms (SourceCollections& dst)
728 {
729 dst.glslSources.add("tri-vert") << glu::VertexSource(
730 "#version 310 es\n"
731 "layout(location = 0) in highp vec4 a_position;\n"
732 "layout(push_constant) uniform FrameData\n"
733 "{\n"
734 " highp uint frameNdx;\n"
735 "} frameData;\n"
736 "void main (void)\n"
737 "{\n"
738 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
739 " highp float c = cos(angle);\n"
740 " highp float s = sin(angle);\n"
741 " highp mat4 t = mat4( c, -s, 0, 0,\n"
742 " s, c, 0, 0,\n"
743 " 0, 0, 1, 0,\n"
744 " 0, 0, 0, 1);\n"
745 " gl_Position = t * a_position;\n"
746 "}\n");
747 dst.glslSources.add("tri-frag") << glu::FragmentSource(
748 "#version 310 es\n"
749 "layout(location = 0) out lowp vec4 o_color;\n"
750 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
751 }
752
753 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
754 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
755 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
756
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)757 vector<FenceSp> createFences (const DeviceInterface& vkd,
758 const VkDevice device,
759 size_t numFences)
760 {
761 vector<FenceSp> fences(numFences);
762
763 for (size_t ndx = 0; ndx < numFences; ++ndx)
764 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
765
766 return fences;
767 }
768
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)769 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
770 const VkDevice device,
771 size_t numSemaphores)
772 {
773 vector<SemaphoreSp> semaphores(numSemaphores);
774
775 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
776 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
777
778 return semaphores;
779 }
780
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)781 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
782 const VkDevice device,
783 const VkCommandPool commandPool,
784 const VkCommandBufferLevel level,
785 const size_t numCommandBuffers)
786 {
787 vector<CommandBufferSp> buffers (numCommandBuffers);
788
789 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
790 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
791
792 return buffers;
793 }
794
basicExtensionTest(Context & context,Type wsiType)795 tcu::TestStatus basicExtensionTest (Context& context, Type wsiType)
796 {
797 const tcu::UVec2 desiredSize (256, 256);
798 const InstanceHelper instHelper (context, wsiType);
799 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
800 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
801 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
802
803 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
804 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
805
806 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
807 devHelper.physicalDevice,
808 *surface);
809
810 bool found = false;
811 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
812 {
813 if (curFmt->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
814 {
815 found = true;
816 break;
817 }
818 }
819 if (!found)
820 {
821 TCU_THROW(NotSupportedError, "VK_EXT_swapchain_colorspace supported, but no non-SRGB_NONLINEAR_KHR surface formats found.");
822 }
823 return tcu::TestStatus::pass("Extension tests succeeded");
824 }
825
surfaceFormatRenderTest(Context & context,Type wsiType,VkSurfaceKHR surface,VkSurfaceFormatKHR curFmt,deBool checkHdr=false)826 tcu::TestStatus surfaceFormatRenderTest (Context& context,
827 Type wsiType,
828 VkSurfaceKHR surface,
829 VkSurfaceFormatKHR curFmt,
830 deBool checkHdr = false)
831 {
832 const tcu::UVec2 desiredSize (256, 256);
833 const InstanceHelper instHelper (context, wsiType);
834 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, surface);
835 const DeviceInterface& vkd = devHelper.vkd;
836 const VkDevice device = *devHelper.device;
837 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
838
839 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, surface, curFmt, desiredSize, 2);
840 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
841 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
842 const vector<VkExtensionProperties> deviceExtensions (enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
843
844 if (checkHdr && !isExtensionSupported(deviceExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
845 TCU_THROW(NotSupportedError, "Extension VK_EXT_hdr_metadata not supported");
846
847 const TriangleRenderer renderer (vkd,
848 device,
849 allocator,
850 context.getBinaryCollection(),
851 swapchainImages,
852 swapchainInfo.imageFormat,
853 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
854
855 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
856
857 const size_t maxQueuedFrames = swapchainImages.size()*2;
858
859 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
860 // limit number of frames we allow to be queued.
861 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
862
863 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
864 // the semaphore in same time as the fence we use to meter rendering.
865 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
866
867 // For rest we simply need maxQueuedFrames as we will wait for image
868 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
869 // previous uses must have completed.
870 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
871 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
872
873 try
874 {
875 const deUint32 numFramesToRender = 60;
876
877 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
878 {
879 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
880 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
881 deUint32 imageNdx = ~0u;
882
883 if (frameNdx >= maxQueuedFrames)
884 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
885
886 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
887
888 {
889 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
890 *swapchain,
891 std::numeric_limits<deUint64>::max(),
892 imageReadySemaphore,
893 (vk::VkFence)0,
894 &imageNdx);
895
896 if (acquireResult == VK_SUBOPTIMAL_KHR)
897 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
898 else
899 VK_CHECK(acquireResult);
900 }
901
902 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
903
904 {
905 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
906 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
907 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
908 const VkSubmitInfo submitInfo =
909 {
910 VK_STRUCTURE_TYPE_SUBMIT_INFO,
911 DE_NULL,
912 1u,
913 &imageReadySemaphore,
914 &waitDstStage,
915 1u,
916 &commandBuffer,
917 1u,
918 &renderingCompleteSemaphore
919 };
920 const VkPresentInfoKHR presentInfo =
921 {
922 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
923 DE_NULL,
924 1u,
925 &renderingCompleteSemaphore,
926 1u,
927 &*swapchain,
928 &imageNdx,
929 (VkResult*)DE_NULL
930 };
931
932 if (checkHdr) {
933 const VkHdrMetadataEXT hdrData = {
934 VK_STRUCTURE_TYPE_HDR_METADATA_EXT,
935 DE_NULL,
936 makeXYColorEXT(0.680f, 0.320f),
937 makeXYColorEXT(0.265f, 0.690f),
938 makeXYColorEXT(0.150f, 0.060f),
939 makeXYColorEXT(0.3127f, 0.3290f),
940 1000.0,
941 0.0,
942 1000.0,
943 70.0
944 };
945 vector<VkSwapchainKHR> swapchainArray;
946
947 swapchainArray.push_back(*swapchain);
948 vkd.setHdrMetadataEXT(device, (deUint32)swapchainArray.size(), swapchainArray.data(), &hdrData);
949 }
950
951 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
952 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
953 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
954 }
955 }
956
957 VK_CHECK(vkd.deviceWaitIdle(device));
958 }
959 catch (...)
960 {
961 // Make sure device is idle before destroying resources
962 vkd.deviceWaitIdle(device);
963 throw;
964 }
965
966 return tcu::TestStatus::pass("Rendering test succeeded");
967 }
968
surfaceFormatRenderTests(Context & context,Type wsiType)969 tcu::TestStatus surfaceFormatRenderTests (Context& context, Type wsiType)
970 {
971 const tcu::UVec2 desiredSize (256, 256);
972 const InstanceHelper instHelper (context, wsiType);
973 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
974 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
975 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
976
977 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
978 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
979
980 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
981 devHelper.physicalDevice,
982 *surface);
983 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
984 {
985 surfaceFormatRenderTest(context, wsiType, *surface, *curFmt);
986 }
987 return tcu::TestStatus::pass("Rendering tests succeeded");
988 }
989
surfaceFormatRenderWithHdrTests(Context & context,Type wsiType)990 tcu::TestStatus surfaceFormatRenderWithHdrTests (Context& context, Type wsiType)
991 {
992 const tcu::UVec2 desiredSize (256, 256);
993 const InstanceHelper instHelper (context, wsiType);
994 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
995 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
996 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
997
998 if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
999 TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
1000
1001 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
1002 devHelper.physicalDevice,
1003 *surface);
1004 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
1005 {
1006 surfaceFormatRenderTest(context, wsiType, *surface, *curFmt, true);
1007 }
1008 return tcu::TestStatus::pass("Rendering tests succeeded");
1009 }
1010
getBasicRenderPrograms(SourceCollections & dst,Type)1011 void getBasicRenderPrograms (SourceCollections& dst, Type)
1012 {
1013 TriangleRenderer::getPrograms(dst);
1014 }
1015
1016 } // anonymous
1017
createColorSpaceTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1018 void createColorSpaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1019 {
1020 addFunctionCase(testGroup, "extensions", "Verify Colorspace Extensions", basicExtensionTest, wsiType);
1021 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Tests", getBasicRenderPrograms, surfaceFormatRenderTests, wsiType);
1022 addFunctionCaseWithPrograms(testGroup, "hdr", "Basic Rendering Tests with HDR", getBasicRenderPrograms, surfaceFormatRenderWithHdrTests, wsiType);
1023 }
1024
1025 } // wsi
1026 } // vkt
1027