| /* |
| * Copyright (c) 2015-2019 The Khronos Group Inc. |
| * Copyright (c) 2015-2019 Valve Corporation |
| * Copyright (c) 2015-2019 LunarG, Inc. |
| * Copyright (c) 2015-2019 Google, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Author: Chia-I Wu <[email protected]> |
| * Author: Chris Forbes <[email protected]> |
| * Author: Courtney Goeltzenleuchter <[email protected]> |
| * Author: Mark Lobodzinski <[email protected]> |
| * Author: Mike Stroyan <[email protected]> |
| * Author: Tobin Ehlis <[email protected]> |
| * Author: Tony Barbour <[email protected]> |
| * Author: Cody Northrop <[email protected]> |
| * Author: Dave Houlton <[email protected]> |
| * Author: Jeremy Kniager <[email protected]> |
| * Author: Shannon McPherson <[email protected]> |
| * Author: John Zulauf <[email protected]> |
| */ |
| |
| #include "cast_utils.h" |
| #include "layer_validation_tests.h" |
| |
| TEST_F(VkLayerTest, RequiredParameter) { |
| TEST_DESCRIPTION("Specify VK_NULL_HANDLE, NULL, and 0 for required handle, pointer, array, and array count parameters"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pFeatures specified as NULL"); |
| // Specify NULL for a pointer to a handle |
| // Expected to trigger an error with |
| // parameter_validation::validate_required_pointer |
| vkGetPhysicalDeviceFeatures(gpu(), NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "required parameter pQueueFamilyPropertyCount specified as NULL"); |
| // Specify NULL for pointer to array count |
| // Expected to trigger an error with parameter_validation::validate_array |
| vkGetPhysicalDeviceQueueFamilyProperties(gpu(), NULL, NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewport-viewportCount-arraylength"); |
| // Specify 0 for a required array count |
| // Expected to trigger an error with parameter_validation::validate_array |
| VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f}; |
| m_commandBuffer->SetViewport(0, 0, &viewport); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCreateImage-pCreateInfo-parameter"); |
| // Specify a null pImageCreateInfo struct pointer |
| VkImage test_image; |
| vkCreateImage(device(), NULL, NULL, &test_image); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewport-pViewports-parameter"); |
| // Specify NULL for a required array |
| // Expected to trigger an error with parameter_validation::validate_array |
| m_commandBuffer->SetViewport(0, 1, NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter memory specified as VK_NULL_HANDLE"); |
| // Specify VK_NULL_HANDLE for a required handle |
| // Expected to trigger an error with |
| // parameter_validation::validate_required_handle |
| vkUnmapMemory(device(), VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "required parameter pFences[0] specified as VK_NULL_HANDLE"); |
| // Specify VK_NULL_HANDLE for a required handle array entry |
| // Expected to trigger an error with |
| // parameter_validation::validate_required_handle_array |
| VkFence fence = VK_NULL_HANDLE; |
| vkResetFences(device(), 1, &fence); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pAllocateInfo specified as NULL"); |
| // Specify NULL for a required struct pointer |
| // Expected to trigger an error with |
| // parameter_validation::validate_struct_type |
| VkDeviceMemory memory = VK_NULL_HANDLE; |
| vkAllocateMemory(device(), NULL, NULL, &memory); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "value of faceMask must not be 0"); |
| // Specify 0 for a required VkFlags parameter |
| // Expected to trigger an error with parameter_validation::validate_flags |
| m_commandBuffer->SetStencilReference(0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "value of pSubmits[0].pWaitDstStageMask[0] must not be 0"); |
| // Specify 0 for a required VkFlags array entry |
| // Expected to trigger an error with |
| // parameter_validation::validate_flags_array |
| VkSemaphore semaphore = VK_NULL_HANDLE; |
| VkPipelineStageFlags stageFlags = 0; |
| VkSubmitInfo submitInfo = {}; |
| submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submitInfo.waitSemaphoreCount = 1; |
| submitInfo.pWaitSemaphores = &semaphore; |
| submitInfo.pWaitDstStageMask = &stageFlags; |
| vkQueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubmitInfo-sType-sType"); |
| stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; |
| // Set a bogus sType and see what happens |
| submitInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
| submitInfo.waitSemaphoreCount = 1; |
| submitInfo.pWaitSemaphores = &semaphore; |
| submitInfo.pWaitDstStageMask = &stageFlags; |
| vkQueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubmitInfo-pWaitSemaphores-parameter"); |
| stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; |
| submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submitInfo.waitSemaphoreCount = 1; |
| // Set a null pointer for pWaitSemaphores |
| submitInfo.pWaitSemaphores = NULL; |
| submitInfo.pWaitDstStageMask = &stageFlags; |
| vkQueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCreateRenderPass-pCreateInfo-parameter"); |
| VkRenderPass render_pass; |
| vkCreateRenderPass(device(), nullptr, nullptr, &render_pass); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, PnextOnlyStructValidation) { |
| TEST_DESCRIPTION("See if checks occur on structs ONLY used in pnext chains."); |
| |
| if (!(CheckDescriptorIndexingSupportAndInitFramework(this, m_instance_extension_names, m_device_extension_names, NULL, |
| m_errorMonitor))) { |
| printf("Descriptor indexing or one of its dependencies not supported, skipping tests\n"); |
| return; |
| } |
| |
| PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = |
| (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR"); |
| ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr); |
| |
| // Create a device passing in a bad PdevFeatures2 value |
| auto indexing_features = lvl_init_struct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(); |
| auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&indexing_features); |
| vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2); |
| // Set one of the features values to an invalid boolean value |
| indexing_features.descriptorBindingUniformBufferUpdateAfterBind = 800; |
| |
| uint32_t queue_node_count; |
| vkGetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_node_count, NULL); |
| VkQueueFamilyProperties *queue_props = new VkQueueFamilyProperties[queue_node_count]; |
| vkGetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_node_count, queue_props); |
| float priorities[] = {1.0f}; |
| VkDeviceQueueCreateInfo queue_info{}; |
| queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
| queue_info.pNext = NULL; |
| queue_info.flags = 0; |
| queue_info.queueFamilyIndex = 0; |
| queue_info.queueCount = 1; |
| queue_info.pQueuePriorities = &priorities[0]; |
| VkDeviceCreateInfo dev_info = {}; |
| dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| dev_info.pNext = NULL; |
| dev_info.queueCreateInfoCount = 1; |
| dev_info.pQueueCreateInfos = &queue_info; |
| dev_info.enabledLayerCount = 0; |
| dev_info.ppEnabledLayerNames = NULL; |
| dev_info.enabledExtensionCount = m_device_extension_names.size(); |
| dev_info.ppEnabledExtensionNames = m_device_extension_names.data(); |
| dev_info.pNext = &features2; |
| VkDevice dev; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "is neither VK_TRUE nor VK_FALSE"); |
| m_errorMonitor->SetUnexpectedError("Failed to create"); |
| vkCreateDevice(gpu(), &dev_info, NULL, &dev); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, ReservedParameter) { |
| TEST_DESCRIPTION("Specify a non-zero value for a reserved parameter"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, " must be 0"); |
| // Specify 0 for a reserved VkFlags parameter |
| // Expected to trigger an error with |
| // parameter_validation::validate_reserved_flags |
| VkEvent event_handle = VK_NULL_HANDLE; |
| VkEventCreateInfo event_info = {}; |
| event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| event_info.flags = 1; |
| vkCreateEvent(device(), &event_info, NULL, &event_handle); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, DebugMarkerNameTest) { |
| TEST_DESCRIPTION("Ensure debug marker object names are printed in debug report output"); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| if (DeviceExtensionSupported(gpu(), "VK_LAYER_LUNARG_core_validation", VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { |
| m_device_extension_names.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); |
| } else { |
| printf("%s Debug Marker Extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| PFN_vkDebugMarkerSetObjectNameEXT fpvkDebugMarkerSetObjectNameEXT = |
| (PFN_vkDebugMarkerSetObjectNameEXT)vkGetInstanceProcAddr(instance(), "vkDebugMarkerSetObjectNameEXT"); |
| if (!(fpvkDebugMarkerSetObjectNameEXT)) { |
| printf("%s Can't find fpvkDebugMarkerSetObjectNameEXT; skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| if (DeviceSimulation()) { |
| printf("%sSkipping object naming test.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkBuffer buffer; |
| VkDeviceMemory memory_1, memory_2; |
| std::string memory_name = "memory_name"; |
| |
| VkBufferCreateInfo buffer_create_info = {}; |
| buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; |
| buffer_create_info.size = 1; |
| |
| vkCreateBuffer(device(), &buffer_create_info, nullptr, &buffer); |
| |
| VkMemoryRequirements memRequirements; |
| vkGetBufferMemoryRequirements(device(), buffer, &memRequirements); |
| |
| VkMemoryAllocateInfo memory_allocate_info = {}; |
| memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| memory_allocate_info.allocationSize = memRequirements.size; |
| memory_allocate_info.memoryTypeIndex = 0; |
| |
| vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_1); |
| vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_2); |
| |
| VkDebugMarkerObjectNameInfoEXT name_info = {}; |
| name_info.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT; |
| name_info.pNext = nullptr; |
| name_info.object = (uint64_t)memory_2; |
| name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT; |
| name_info.pObjectName = memory_name.c_str(); |
| fpvkDebugMarkerSetObjectNameEXT(device(), &name_info); |
| |
| vkBindBufferMemory(device(), buffer, memory_1, 0); |
| |
| // Test core_validation layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, memory_name); |
| vkBindBufferMemory(device(), buffer, memory_2, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), memory_1, nullptr); |
| memory_1 = VK_NULL_HANDLE; |
| vkFreeMemory(device(), memory_2, nullptr); |
| memory_2 = VK_NULL_HANDLE; |
| vkDestroyBuffer(device(), buffer, nullptr); |
| buffer = VK_NULL_HANDLE; |
| |
| VkCommandBuffer commandBuffer; |
| std::string commandBuffer_name = "command_buffer_name"; |
| VkCommandPool commandpool_1; |
| VkCommandPool commandpool_2; |
| VkCommandPoolCreateInfo pool_create_info{}; |
| pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
| pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; |
| pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
| vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_1); |
| vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_2); |
| |
| VkCommandBufferAllocateInfo command_buffer_allocate_info{}; |
| command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| command_buffer_allocate_info.commandPool = commandpool_1; |
| command_buffer_allocate_info.commandBufferCount = 1; |
| command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| vkAllocateCommandBuffers(device(), &command_buffer_allocate_info, &commandBuffer); |
| |
| name_info.object = (uint64_t)commandBuffer; |
| name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT; |
| name_info.pObjectName = commandBuffer_name.c_str(); |
| fpvkDebugMarkerSetObjectNameEXT(device(), &name_info); |
| |
| VkCommandBufferBeginInfo cb_begin_Info = {}; |
| cb_begin_Info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| cb_begin_Info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| vkBeginCommandBuffer(commandBuffer, &cb_begin_Info); |
| |
| const VkRect2D scissor = {{-1, 0}, {16, 16}}; |
| const VkRect2D scissors[] = {scissor, scissor}; |
| |
| // Test parameter_validation layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name); |
| vkCmdSetScissor(commandBuffer, 1, 1, scissors); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test object_tracker layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name); |
| vkFreeCommandBuffers(device(), commandpool_2, 1, &commandBuffer); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyCommandPool(device(), commandpool_1, NULL); |
| vkDestroyCommandPool(device(), commandpool_2, NULL); |
| } |
| |
| TEST_F(VkLayerTest, DebugUtilsNameTest) { |
| TEST_DESCRIPTION("Ensure debug utils object names are printed in debug messenger output"); |
| |
| // Skip test if extension not supported |
| if (InstanceExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { |
| m_instance_extension_names.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| } else { |
| printf("%s Debug Utils Extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| PFN_vkSetDebugUtilsObjectNameEXT fpvkSetDebugUtilsObjectNameEXT = |
| (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance(), "vkSetDebugUtilsObjectNameEXT"); |
| ASSERT_TRUE(fpvkSetDebugUtilsObjectNameEXT); // Must be extant if extension is enabled |
| PFN_vkCreateDebugUtilsMessengerEXT fpvkCreateDebugUtilsMessengerEXT = |
| (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance(), "vkCreateDebugUtilsMessengerEXT"); |
| ASSERT_TRUE(fpvkCreateDebugUtilsMessengerEXT); // Must be extant if extension is enabled |
| PFN_vkDestroyDebugUtilsMessengerEXT fpvkDestroyDebugUtilsMessengerEXT = |
| (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance(), "vkDestroyDebugUtilsMessengerEXT"); |
| ASSERT_TRUE(fpvkDestroyDebugUtilsMessengerEXT); // Must be extant if extension is enabled |
| PFN_vkCmdInsertDebugUtilsLabelEXT fpvkCmdInsertDebugUtilsLabelEXT = |
| (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance(), "vkCmdInsertDebugUtilsLabelEXT"); |
| ASSERT_TRUE(fpvkCmdInsertDebugUtilsLabelEXT); // Must be extant if extension is enabled |
| |
| if (DeviceSimulation()) { |
| printf("%sSkipping object naming test.\n", kSkipPrefix); |
| return; |
| } |
| |
| DebugUtilsLabelCheckData callback_data; |
| auto empty_callback = [](const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, DebugUtilsLabelCheckData *data) { |
| data->count++; |
| }; |
| callback_data.count = 0; |
| callback_data.callback = empty_callback; |
| |
| auto callback_create_info = lvl_init_struct<VkDebugUtilsMessengerCreateInfoEXT>(); |
| callback_create_info.messageSeverity = |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; |
| callback_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; |
| callback_create_info.pfnUserCallback = DebugUtilsCallback; |
| callback_create_info.pUserData = &callback_data; |
| VkDebugUtilsMessengerEXT my_messenger = VK_NULL_HANDLE; |
| fpvkCreateDebugUtilsMessengerEXT(instance(), &callback_create_info, nullptr, &my_messenger); |
| |
| VkBuffer buffer; |
| VkDeviceMemory memory_1, memory_2; |
| std::string memory_name = "memory_name"; |
| |
| VkBufferCreateInfo buffer_create_info = {}; |
| buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; |
| buffer_create_info.size = 1; |
| |
| vkCreateBuffer(device(), &buffer_create_info, nullptr, &buffer); |
| |
| VkMemoryRequirements memRequirements; |
| vkGetBufferMemoryRequirements(device(), buffer, &memRequirements); |
| |
| VkMemoryAllocateInfo memory_allocate_info = {}; |
| memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| memory_allocate_info.allocationSize = memRequirements.size; |
| memory_allocate_info.memoryTypeIndex = 0; |
| |
| vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_1); |
| vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_2); |
| |
| VkDebugUtilsObjectNameInfoEXT name_info = {}; |
| name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; |
| name_info.pNext = nullptr; |
| name_info.objectHandle = (uint64_t)memory_2; |
| name_info.objectType = VK_OBJECT_TYPE_DEVICE_MEMORY; |
| name_info.pObjectName = memory_name.c_str(); |
| fpvkSetDebugUtilsObjectNameEXT(device(), &name_info); |
| |
| vkBindBufferMemory(device(), buffer, memory_1, 0); |
| |
| // Test core_validation layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, memory_name); |
| vkBindBufferMemory(device(), buffer, memory_2, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), memory_1, nullptr); |
| memory_1 = VK_NULL_HANDLE; |
| vkFreeMemory(device(), memory_2, nullptr); |
| memory_2 = VK_NULL_HANDLE; |
| vkDestroyBuffer(device(), buffer, nullptr); |
| buffer = VK_NULL_HANDLE; |
| |
| VkCommandBuffer commandBuffer; |
| std::string commandBuffer_name = "command_buffer_name"; |
| VkCommandPool commandpool_1; |
| VkCommandPool commandpool_2; |
| VkCommandPoolCreateInfo pool_create_info{}; |
| pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
| pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; |
| pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
| vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_1); |
| vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_2); |
| |
| VkCommandBufferAllocateInfo command_buffer_allocate_info{}; |
| command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| command_buffer_allocate_info.commandPool = commandpool_1; |
| command_buffer_allocate_info.commandBufferCount = 1; |
| command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| vkAllocateCommandBuffers(device(), &command_buffer_allocate_info, &commandBuffer); |
| |
| name_info.objectHandle = (uint64_t)commandBuffer; |
| name_info.objectType = VK_OBJECT_TYPE_COMMAND_BUFFER; |
| name_info.pObjectName = commandBuffer_name.c_str(); |
| fpvkSetDebugUtilsObjectNameEXT(device(), &name_info); |
| |
| VkCommandBufferBeginInfo cb_begin_Info = {}; |
| cb_begin_Info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| cb_begin_Info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| vkBeginCommandBuffer(commandBuffer, &cb_begin_Info); |
| |
| const VkRect2D scissor = {{-1, 0}, {16, 16}}; |
| const VkRect2D scissors[] = {scissor, scissor}; |
| |
| auto command_label = lvl_init_struct<VkDebugUtilsLabelEXT>(); |
| command_label.pLabelName = "Command Label 0123"; |
| command_label.color[0] = 0.; |
| command_label.color[1] = 1.; |
| command_label.color[2] = 2.; |
| command_label.color[3] = 3.0; |
| bool command_label_test = false; |
| auto command_label_callback = [command_label, &command_label_test](const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, |
| DebugUtilsLabelCheckData *data) { |
| data->count++; |
| command_label_test = false; |
| if (pCallbackData->cmdBufLabelCount == 1) { |
| command_label_test = pCallbackData->pCmdBufLabels[0] == command_label; |
| } |
| }; |
| callback_data.callback = command_label_callback; |
| |
| fpvkCmdInsertDebugUtilsLabelEXT(commandBuffer, &command_label); |
| // Test parameter_validation layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name); |
| vkCmdSetScissor(commandBuffer, 1, 1, scissors); |
| m_errorMonitor->VerifyFound(); |
| |
| // Check the label test |
| if (!command_label_test) { |
| ADD_FAILURE() << "Command label '" << command_label.pLabelName << "' not passed to callback."; |
| } |
| |
| // Test object_tracker layer |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name); |
| vkFreeCommandBuffers(device(), commandpool_2, 1, &commandBuffer); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyCommandPool(device(), commandpool_1, NULL); |
| vkDestroyCommandPool(device(), commandpool_2, NULL); |
| fpvkDestroyDebugUtilsMessengerEXT(instance(), my_messenger, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, InvalidStructSType) { |
| TEST_DESCRIPTION("Specify an invalid VkStructureType for a Vulkan structure's sType field"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pAllocateInfo->sType must be"); |
| // Zero struct memory, effectively setting sType to |
| // VK_STRUCTURE_TYPE_APPLICATION_INFO |
| // Expected to trigger an error with |
| // parameter_validation::validate_struct_type |
| VkMemoryAllocateInfo alloc_info = {}; |
| VkDeviceMemory memory = VK_NULL_HANDLE; |
| vkAllocateMemory(device(), &alloc_info, NULL, &memory); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pSubmits[0].sType must be"); |
| // Zero struct memory, effectively setting sType to |
| // VK_STRUCTURE_TYPE_APPLICATION_INFO |
| // Expected to trigger an error with |
| // parameter_validation::validate_struct_type_array |
| VkSubmitInfo submit_info = {}; |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidStructPNext) { |
| TEST_DESCRIPTION("Specify an invalid value for a Vulkan structure's pNext field"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "value of pCreateInfo->pNext must be NULL"); |
| // Set VkMemoryAllocateInfo::pNext to a non-NULL value, when pNext must be NULL. |
| // Need to pick a function that has no allowed pNext structure types. |
| // Expected to trigger an error with parameter_validation::validate_struct_pnext |
| VkEvent event = VK_NULL_HANDLE; |
| VkEventCreateInfo event_alloc_info = {}; |
| // Zero-initialization will provide the correct sType |
| VkApplicationInfo app_info = {}; |
| event_alloc_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| event_alloc_info.pNext = &app_info; |
| vkCreateEvent(device(), &event_alloc_info, NULL, &event); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, |
| " chain includes a structure with unexpected VkStructureType "); |
| // Set VkMemoryAllocateInfo::pNext to a non-NULL value, but use |
| // a function that has allowed pNext structure types and specify |
| // a structure type that is not allowed. |
| // Expected to trigger an error with parameter_validation::validate_struct_pnext |
| VkDeviceMemory memory = VK_NULL_HANDLE; |
| VkMemoryAllocateInfo memory_alloc_info = {}; |
| memory_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| memory_alloc_info.pNext = &app_info; |
| vkAllocateMemory(device(), &memory_alloc_info, NULL, &memory); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, UnrecognizedValueOutOfRange) { |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "does not fall within the begin..end range of the core VkFormat enumeration tokens"); |
| // Specify an invalid VkFormat value |
| // Expected to trigger an error with |
| // parameter_validation::validate_ranged_enum |
| VkFormatProperties format_properties; |
| vkGetPhysicalDeviceFormatProperties(gpu(), static_cast<VkFormat>(8000), &format_properties); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, UnrecognizedValueBadMask) { |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "contains flag bits that are not recognized members of"); |
| // Specify an invalid VkFlags bitmask value |
| // Expected to trigger an error with parameter_validation::validate_flags |
| VkImageFormatProperties image_format_properties; |
| vkGetPhysicalDeviceImageFormatProperties(gpu(), VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, |
| static_cast<VkImageUsageFlags>(1 << 25), 0, &image_format_properties); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, UnrecognizedValueBadFlag) { |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "contains flag bits that are not recognized members of"); |
| // Specify an invalid VkFlags array entry |
| // Expected to trigger an error with parameter_validation::validate_flags_array |
| VkSemaphore semaphore; |
| VkSemaphoreCreateInfo semaphore_create_info{}; |
| semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
| vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); |
| // `stage_flags` is set to a value which, currently, is not a defined stage flag |
| // `VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM` works well for this |
| VkPipelineStageFlags stage_flags = VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM; |
| // `waitSemaphoreCount` *must* be greater than 0 to perform this check |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.waitSemaphoreCount = 1; |
| submit_info.pWaitSemaphores = &semaphore; |
| submit_info.pWaitDstStageMask = &stage_flags; |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| vkDestroySemaphore(m_device->device(), semaphore, nullptr); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, UnrecognizedValueBadBool) { |
| // Make sure using VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE doesn't trigger a false positive. |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME)) { |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME); |
| } else { |
| printf("%s VK_KHR_sampler_mirror_clamp_to_edge extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Specify an invalid VkBool32 value, expecting a warning with parameter_validation::validate_bool32 |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| |
| // Not VK_TRUE or VK_FALSE |
| sampler_info.anisotropyEnable = 3; |
| CreateSamplerTest(*this, &sampler_info, "is neither VK_TRUE nor VK_FALSE"); |
| } |
| |
| TEST_F(VkLayerTest, UnrecognizedValueMaxEnum) { |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // Specify MAX_ENUM |
| VkFormatProperties format_properties; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "does not fall within the begin..end range"); |
| vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_MAX_ENUM, &format_properties); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, SubmitSignaledFence) { |
| vk_testing::Fence testFence; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "submitted in SIGNALED state. Fences must be reset before being submitted"); |
| |
| VkFenceCreateInfo fenceInfo = {}; |
| fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
| fenceInfo.pNext = NULL; |
| fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitViewport()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->ClearAllBuffers(m_renderTargets, m_clear_color, nullptr, m_depth_clear_color, m_stencil_clear_color); |
| m_commandBuffer->end(); |
| |
| testFence.init(*m_device, fenceInfo); |
| |
| VkSubmitInfo submit_info; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.pNext = NULL; |
| submit_info.waitSemaphoreCount = 0; |
| submit_info.pWaitSemaphores = NULL; |
| submit_info.pWaitDstStageMask = NULL; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| submit_info.signalSemaphoreCount = 0; |
| submit_info.pSignalSemaphores = NULL; |
| |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, testFence.handle()); |
| vkQueueWaitIdle(m_device->m_queue); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, LeakAnObject) { |
| TEST_DESCRIPTION("Create a fence and destroy its device without first destroying the fence."); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| // Workaround for overzealous layers checking even the guaranteed 0th queue family |
| const auto q_props = vk_testing::PhysicalDevice(gpu()).queue_properties(); |
| ASSERT_TRUE(q_props.size() > 0); |
| ASSERT_TRUE(q_props[0].queueCount > 0); |
| |
| const float q_priority[] = {1.0f}; |
| VkDeviceQueueCreateInfo queue_ci = {}; |
| queue_ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
| queue_ci.queueFamilyIndex = 0; |
| queue_ci.queueCount = 1; |
| queue_ci.pQueuePriorities = q_priority; |
| |
| VkDeviceCreateInfo device_ci = {}; |
| device_ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_ci.queueCreateInfoCount = 1; |
| device_ci.pQueueCreateInfos = &queue_ci; |
| |
| VkDevice leaky_device; |
| ASSERT_VK_SUCCESS(vkCreateDevice(gpu(), &device_ci, nullptr, &leaky_device)); |
| |
| const VkFenceCreateInfo fence_ci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; |
| VkFence leaked_fence; |
| ASSERT_VK_SUCCESS(vkCreateFence(leaky_device, &fence_ci, nullptr, &leaked_fence)); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyDevice-device-00378"); |
| vkDestroyDevice(leaky_device, nullptr); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, UseObjectWithWrongDevice) { |
| TEST_DESCRIPTION( |
| "Try to destroy a render pass object using a device other than the one it was created on. This should generate a distinct " |
| "error from the invalid handle error."); |
| // Create first device and renderpass |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| // Create second device |
| float priorities[] = {1.0f}; |
| VkDeviceQueueCreateInfo queue_info{}; |
| queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
| queue_info.pNext = NULL; |
| queue_info.flags = 0; |
| queue_info.queueFamilyIndex = 0; |
| queue_info.queueCount = 1; |
| queue_info.pQueuePriorities = &priorities[0]; |
| |
| VkDeviceCreateInfo device_create_info = {}; |
| auto features = m_device->phy().features(); |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.pNext = NULL; |
| device_create_info.queueCreateInfoCount = 1; |
| device_create_info.pQueueCreateInfos = &queue_info; |
| device_create_info.enabledLayerCount = 0; |
| device_create_info.ppEnabledLayerNames = NULL; |
| device_create_info.pEnabledFeatures = &features; |
| |
| VkDevice second_device; |
| ASSERT_VK_SUCCESS(vkCreateDevice(gpu(), &device_create_info, NULL, &second_device)); |
| |
| // Try to destroy the renderpass from the first device using the second device |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyRenderPass-renderPass-parent"); |
| vkDestroyRenderPass(second_device, m_renderPass, NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyDevice(second_device, NULL); |
| } |
| |
| TEST_F(VkLayerTest, InvalidAllocationCallbacks) { |
| TEST_DESCRIPTION("Test with invalid VkAllocationCallbacks"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // vkCreateInstance, and vkCreateDevice tend to crash in the Loader Trampoline ATM, so choosing vkCreateCommandPool |
| const VkCommandPoolCreateInfo cpci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, |
| DeviceObj()->QueueFamilyMatching(0, 0, true)}; |
| VkCommandPool cmdPool; |
| |
| struct Alloc { |
| static VKAPI_ATTR void *VKAPI_CALL alloc(void *, size_t, size_t, VkSystemAllocationScope) { return nullptr; }; |
| static VKAPI_ATTR void *VKAPI_CALL realloc(void *, void *, size_t, size_t, VkSystemAllocationScope) { return nullptr; }; |
| static VKAPI_ATTR void VKAPI_CALL free(void *, void *){}; |
| static VKAPI_ATTR void VKAPI_CALL internalAlloc(void *, size_t, VkInternalAllocationType, VkSystemAllocationScope){}; |
| static VKAPI_ATTR void VKAPI_CALL internalFree(void *, size_t, VkInternalAllocationType, VkSystemAllocationScope){}; |
| }; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAllocationCallbacks-pfnAllocation-00632"); |
| const VkAllocationCallbacks allocator = {nullptr, nullptr, Alloc::realloc, Alloc::free, nullptr, nullptr}; |
| vkCreateCommandPool(device(), &cpci, &allocator, &cmdPool); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAllocationCallbacks-pfnReallocation-00633"); |
| const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, nullptr, Alloc::free, nullptr, nullptr}; |
| vkCreateCommandPool(device(), &cpci, &allocator, &cmdPool); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAllocationCallbacks-pfnFree-00634"); |
| const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, nullptr, nullptr, nullptr}; |
| vkCreateCommandPool(device(), &cpci, &allocator, &cmdPool); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkAllocationCallbacks-pfnInternalAllocation-00635"); |
| const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, Alloc::free, nullptr, Alloc::internalFree}; |
| vkCreateCommandPool(device(), &cpci, &allocator, &cmdPool); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkAllocationCallbacks-pfnInternalAllocation-00635"); |
| const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, Alloc::free, Alloc::internalAlloc, nullptr}; |
| vkCreateCommandPool(device(), &cpci, &allocator, &cmdPool); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, MismatchedQueueFamiliesOnSubmit) { |
| TEST_DESCRIPTION( |
| "Submit command buffer created using one queue family and attempt to submit them on a queue created in a different queue " |
| "family."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); // assumes it initializes all queue families on vkCreateDevice |
| |
| // This test is meaningless unless we have multiple queue families |
| auto queue_family_properties = m_device->phy().queue_properties(); |
| std::vector<uint32_t> queue_families; |
| for (uint32_t i = 0; i < queue_family_properties.size(); ++i) |
| if (queue_family_properties[i].queueCount > 0) queue_families.push_back(i); |
| |
| if (queue_families.size() < 2) { |
| printf("%s Device only has one queue family; skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| const uint32_t queue_family = queue_families[0]; |
| |
| const uint32_t other_queue_family = queue_families[1]; |
| VkQueue other_queue; |
| vkGetDeviceQueue(m_device->device(), other_queue_family, 0, &other_queue); |
| |
| VkCommandPoolObj cmd_pool(m_device, queue_family); |
| VkCommandBufferObj cmd_buff(m_device, &cmd_pool); |
| |
| cmd_buff.begin(); |
| cmd_buff.end(); |
| |
| // Submit on the wrong queue |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &cmd_buff.handle(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkQueueSubmit-pCommandBuffers-00074"); |
| vkQueueSubmit(other_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, TemporaryExternalSemaphore) { |
| #ifdef _WIN32 |
| const auto extension_name = VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; |
| #else |
| const auto extension_name = VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; |
| #endif |
| // Check for external semaphore instance extensions |
| if (InstanceExtensionSupported(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME)) { |
| m_instance_extension_names.push_back(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME); |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| } else { |
| printf("%s External semaphore extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| // Check for external semaphore device extensions |
| if (DeviceExtensionSupported(gpu(), nullptr, extension_name)) { |
| m_device_extension_names.push_back(extension_name); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME); |
| } else { |
| printf("%s External semaphore extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Check for external semaphore import and export capability |
| VkPhysicalDeviceExternalSemaphoreInfoKHR esi = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR, nullptr, |
| handle_type}; |
| VkExternalSemaphorePropertiesKHR esp = {VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR, nullptr}; |
| auto vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = |
| (PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)vkGetInstanceProcAddr( |
| instance(), "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"); |
| vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(gpu(), &esi, &esp); |
| |
| if (!(esp.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR) || |
| !(esp.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR)) { |
| printf("%s External semaphore does not support importing and exporting, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| VkResult err; |
| |
| // Create a semaphore to export payload from |
| VkExportSemaphoreCreateInfoKHR esci = {VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR, nullptr, handle_type}; |
| VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &esci, 0}; |
| |
| VkSemaphore export_semaphore; |
| err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &export_semaphore); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Create a semaphore to import payload into |
| sci.pNext = nullptr; |
| VkSemaphore import_semaphore; |
| err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &import_semaphore); |
| ASSERT_VK_SUCCESS(err); |
| |
| #ifdef _WIN32 |
| // Export semaphore payload to an opaque handle |
| HANDLE handle = nullptr; |
| VkSemaphoreGetWin32HandleInfoKHR ghi = {VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR, nullptr, export_semaphore, |
| handle_type}; |
| auto vkGetSemaphoreWin32HandleKHR = |
| (PFN_vkGetSemaphoreWin32HandleKHR)vkGetDeviceProcAddr(m_device->device(), "vkGetSemaphoreWin32HandleKHR"); |
| err = vkGetSemaphoreWin32HandleKHR(m_device->device(), &ghi, &handle); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Import opaque handle exported above *temporarily* |
| VkImportSemaphoreWin32HandleInfoKHR ihi = {VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR, |
| nullptr, |
| import_semaphore, |
| VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR, |
| handle_type, |
| handle, |
| nullptr}; |
| auto vkImportSemaphoreWin32HandleKHR = |
| (PFN_vkImportSemaphoreWin32HandleKHR)vkGetDeviceProcAddr(m_device->device(), "vkImportSemaphoreWin32HandleKHR"); |
| err = vkImportSemaphoreWin32HandleKHR(m_device->device(), &ihi); |
| ASSERT_VK_SUCCESS(err); |
| #else |
| // Export semaphore payload to an opaque handle |
| int fd = 0; |
| VkSemaphoreGetFdInfoKHR ghi = {VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, nullptr, export_semaphore, handle_type}; |
| auto vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)vkGetDeviceProcAddr(m_device->device(), "vkGetSemaphoreFdKHR"); |
| err = vkGetSemaphoreFdKHR(m_device->device(), &ghi, &fd); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Import opaque handle exported above *temporarily* |
| VkImportSemaphoreFdInfoKHR ihi = {VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, nullptr, import_semaphore, |
| VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR, handle_type, fd}; |
| auto vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)vkGetDeviceProcAddr(m_device->device(), "vkImportSemaphoreFdKHR"); |
| err = vkImportSemaphoreFdKHR(m_device->device(), &ihi); |
| ASSERT_VK_SUCCESS(err); |
| #endif |
| |
| // Wait on the imported semaphore twice in vkQueueSubmit, the second wait should be an error |
| VkPipelineStageFlags flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
| VkSubmitInfo si[] = { |
| {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, &flags, 0, nullptr, 1, &export_semaphore}, |
| {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 1, &import_semaphore, &flags, 0, nullptr, 0, nullptr}, |
| {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, &flags, 0, nullptr, 1, &export_semaphore}, |
| {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 1, &import_semaphore, &flags, 0, nullptr, 0, nullptr}, |
| }; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "has no way to be signaled"); |
| vkQueueSubmit(m_device->m_queue, 4, si, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| auto index = m_device->graphics_queue_node_index_; |
| if (m_device->queue_props[index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) { |
| // Wait on the imported semaphore twice in vkQueueBindSparse, the second wait should be an error |
| VkBindSparseInfo bi[] = { |
| {VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 1, &export_semaphore}, |
| {VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, nullptr, 1, &import_semaphore, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr}, |
| {VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 1, &export_semaphore}, |
| {VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, nullptr, 1, &import_semaphore, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr}, |
| }; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "has no way to be signaled"); |
| vkQueueBindSparse(m_device->m_queue, 4, bi, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Cleanup |
| err = vkQueueWaitIdle(m_device->m_queue); |
| ASSERT_VK_SUCCESS(err); |
| vkDestroySemaphore(m_device->device(), export_semaphore, nullptr); |
| vkDestroySemaphore(m_device->device(), import_semaphore, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, TemporaryExternalFence) { |
| #ifdef _WIN32 |
| const auto extension_name = VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; |
| #else |
| const auto extension_name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; |
| #endif |
| // Check for external fence instance extensions |
| if (InstanceExtensionSupported(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME)) { |
| m_instance_extension_names.push_back(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME); |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| } else { |
| printf("%s External fence extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| // Check for external fence device extensions |
| if (DeviceExtensionSupported(gpu(), nullptr, extension_name)) { |
| m_device_extension_names.push_back(extension_name); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME); |
| } else { |
| printf("%s External fence extension not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Check for external fence import and export capability |
| VkPhysicalDeviceExternalFenceInfoKHR efi = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR, nullptr, handle_type}; |
| VkExternalFencePropertiesKHR efp = {VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR, nullptr}; |
| auto vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)vkGetInstanceProcAddr( |
| instance(), "vkGetPhysicalDeviceExternalFencePropertiesKHR"); |
| vkGetPhysicalDeviceExternalFencePropertiesKHR(gpu(), &efi, &efp); |
| |
| if (!(efp.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR) || |
| !(efp.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR)) { |
| printf("%s External fence does not support importing and exporting, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| VkResult err; |
| |
| // Create a fence to export payload from |
| VkFence export_fence; |
| { |
| VkExportFenceCreateInfoKHR efci = {VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR, nullptr, handle_type}; |
| VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, &efci, 0}; |
| err = vkCreateFence(m_device->device(), &fci, nullptr, &export_fence); |
| ASSERT_VK_SUCCESS(err); |
| } |
| |
| // Create a fence to import payload into |
| VkFence import_fence; |
| { |
| VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0}; |
| err = vkCreateFence(m_device->device(), &fci, nullptr, &import_fence); |
| ASSERT_VK_SUCCESS(err); |
| } |
| |
| #ifdef _WIN32 |
| // Export fence payload to an opaque handle |
| HANDLE handle = nullptr; |
| { |
| VkFenceGetWin32HandleInfoKHR ghi = {VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR, nullptr, export_fence, handle_type}; |
| auto vkGetFenceWin32HandleKHR = |
| (PFN_vkGetFenceWin32HandleKHR)vkGetDeviceProcAddr(m_device->device(), "vkGetFenceWin32HandleKHR"); |
| err = vkGetFenceWin32HandleKHR(m_device->device(), &ghi, &handle); |
| ASSERT_VK_SUCCESS(err); |
| } |
| |
| // Import opaque handle exported above |
| { |
| VkImportFenceWin32HandleInfoKHR ifi = {VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR, |
| nullptr, |
| import_fence, |
| VK_FENCE_IMPORT_TEMPORARY_BIT_KHR, |
| handle_type, |
| handle, |
| nullptr}; |
| auto vkImportFenceWin32HandleKHR = |
| (PFN_vkImportFenceWin32HandleKHR)vkGetDeviceProcAddr(m_device->device(), "vkImportFenceWin32HandleKHR"); |
| err = vkImportFenceWin32HandleKHR(m_device->device(), &ifi); |
| ASSERT_VK_SUCCESS(err); |
| } |
| #else |
| // Export fence payload to an opaque handle |
| int fd = 0; |
| { |
| VkFenceGetFdInfoKHR gfi = {VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR, nullptr, export_fence, handle_type}; |
| auto vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)vkGetDeviceProcAddr(m_device->device(), "vkGetFenceFdKHR"); |
| err = vkGetFenceFdKHR(m_device->device(), &gfi, &fd); |
| ASSERT_VK_SUCCESS(err); |
| } |
| |
| // Import opaque handle exported above |
| { |
| VkImportFenceFdInfoKHR ifi = {VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, nullptr, import_fence, |
| VK_FENCE_IMPORT_TEMPORARY_BIT_KHR, handle_type, fd}; |
| auto vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)vkGetDeviceProcAddr(m_device->device(), "vkImportFenceFdKHR"); |
| err = vkImportFenceFdKHR(m_device->device(), &ifi); |
| ASSERT_VK_SUCCESS(err); |
| } |
| #endif |
| |
| // Undo the temporary import |
| vkResetFences(m_device->device(), 1, &import_fence); |
| |
| // Signal the previously imported fence twice, the second signal should produce a validation error |
| vkQueueSubmit(m_device->m_queue, 0, nullptr, import_fence); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "is already in use by another submission."); |
| vkQueueSubmit(m_device->m_queue, 0, nullptr, import_fence); |
| m_errorMonitor->VerifyFound(); |
| |
| // Cleanup |
| err = vkQueueWaitIdle(m_device->m_queue); |
| ASSERT_VK_SUCCESS(err); |
| vkDestroyFence(m_device->device(), export_fence, nullptr); |
| vkDestroyFence(m_device->device(), import_fence, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, InvalidCmdBufferEventDestroyed) { |
| TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid due to an event dependency being destroyed."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkEvent event; |
| VkEventCreateInfo evci = {}; |
| evci.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| VkResult result = vkCreateEvent(m_device->device(), &evci, NULL, &event); |
| ASSERT_VK_SUCCESS(result); |
| |
| m_commandBuffer->begin(); |
| vkCmdSetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); |
| m_commandBuffer->end(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkEvent"); |
| // Destroy event dependency prior to submit to cause ERROR |
| vkDestroyEvent(m_device->device(), event, NULL); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidCmdBufferQueryPoolDestroyed) { |
| TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid due to a query pool dependency being destroyed."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo qpci{}; |
| qpci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| qpci.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| qpci.queryCount = 1; |
| VkResult result = vkCreateQueryPool(m_device->device(), &qpci, nullptr, &query_pool); |
| ASSERT_VK_SUCCESS(result); |
| |
| m_commandBuffer->begin(); |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1); |
| m_commandBuffer->end(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkQueryPool"); |
| // Destroy query pool dependency prior to submit to cause ERROR |
| vkDestroyQueryPool(m_device->device(), query_pool, NULL); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, DeviceFeature2AndVertexAttributeDivisorExtensionUnenabled) { |
| TEST_DESCRIPTION( |
| "Test unenabled VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME & " |
| "VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME."); |
| |
| VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vadf = {}; |
| vadf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; |
| VkPhysicalDeviceFeatures2 pd_features2 = {}; |
| pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
| pd_features2.pNext = &vadf; |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props); |
| VkDeviceCreateInfo device_create_info = {}; |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.pNext = &pd_features2; |
| device_create_info.queueCreateInfoCount = queue_info.size(); |
| device_create_info.pQueueCreateInfos = queue_info.data(); |
| VkDevice testDevice; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VK_KHR_get_physical_device_properties2 must be enabled when it creates an instance"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VK_EXT_vertex_attribute_divisor must be enabled when it creates a device"); |
| m_errorMonitor->SetUnexpectedError("Failed to create device chain"); |
| vkCreateDevice(gpu(), &device_create_info, NULL, &testDevice); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidDeviceMask) { |
| TEST_DESCRIPTION("Invalid deviceMask."); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| |
| bool support_surface = true; |
| if (!AddSurfaceInstanceExtension()) { |
| printf("%s surface extensions not supported, skipping VkAcquireNextImageInfoKHR test\n", kSkipPrefix); |
| support_surface = false; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (support_surface) { |
| if (!AddSwapchainDeviceExtension()) { |
| printf("%s swapchain extensions not supported, skipping BindSwapchainImageMemory test\n", kSkipPrefix); |
| support_surface = false; |
| } |
| } |
| |
| if (DeviceValidationVersion() < VK_API_VERSION_1_1) { |
| printf("%s Device Groups requires Vulkan 1.1+, skipping test\n", kSkipPrefix); |
| return; |
| } |
| uint32_t physical_device_group_count = 0; |
| vkEnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, nullptr); |
| |
| if (physical_device_group_count == 0) { |
| printf("%s physical_device_group_count is 0, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| std::vector<VkPhysicalDeviceGroupProperties> physical_device_group(physical_device_group_count, |
| {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES}); |
| vkEnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, physical_device_group.data()); |
| VkDeviceGroupDeviceCreateInfo create_device_pnext = {}; |
| create_device_pnext.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO; |
| create_device_pnext.physicalDeviceCount = physical_device_group[0].physicalDeviceCount; |
| create_device_pnext.pPhysicalDevices = physical_device_group[0].physicalDevices; |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &create_device_pnext, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| if (!InitSwapchain()) { |
| printf("%s Cannot create surface or swapchain, skipping VkAcquireNextImageInfoKHR test\n", kSkipPrefix); |
| support_surface = false; |
| } |
| |
| // Test VkMemoryAllocateFlagsInfo |
| VkMemoryAllocateFlagsInfo alloc_flags_info = {}; |
| alloc_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; |
| alloc_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT; |
| alloc_flags_info.deviceMask = 0xFFFFFFFF; |
| VkMemoryAllocateInfo alloc_info = {}; |
| alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| alloc_info.pNext = &alloc_flags_info; |
| alloc_info.memoryTypeIndex = 0; |
| alloc_info.allocationSize = 32; |
| |
| VkDeviceMemory mem; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateFlagsInfo-deviceMask-00675"); |
| vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); |
| m_errorMonitor->VerifyFound(); |
| |
| alloc_flags_info.deviceMask = 0; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateFlagsInfo-deviceMask-00676"); |
| vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test VkDeviceGroupCommandBufferBeginInfo |
| VkDeviceGroupCommandBufferBeginInfo dev_grp_cmd_buf_info = {}; |
| dev_grp_cmd_buf_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO; |
| dev_grp_cmd_buf_info.deviceMask = 0xFFFFFFFF; |
| VkCommandBufferBeginInfo cmd_buf_info = {}; |
| cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| cmd_buf_info.pNext = &dev_grp_cmd_buf_info; |
| |
| m_commandBuffer->reset(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkDeviceGroupCommandBufferBeginInfo-deviceMask-00106"); |
| vkBeginCommandBuffer(m_commandBuffer->handle(), &cmd_buf_info); |
| m_errorMonitor->VerifyFound(); |
| |
| dev_grp_cmd_buf_info.deviceMask = 0; |
| m_commandBuffer->reset(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkDeviceGroupCommandBufferBeginInfo-deviceMask-00107"); |
| vkBeginCommandBuffer(m_commandBuffer->handle(), &cmd_buf_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test VkDeviceGroupRenderPassBeginInfo |
| dev_grp_cmd_buf_info.deviceMask = 0x00000001; |
| m_commandBuffer->reset(); |
| vkBeginCommandBuffer(m_commandBuffer->handle(), &cmd_buf_info); |
| |
| VkDeviceGroupRenderPassBeginInfo dev_grp_rp_info = {}; |
| dev_grp_rp_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO; |
| dev_grp_rp_info.deviceMask = 0xFFFFFFFF; |
| m_renderPassBeginInfo.pNext = &dev_grp_rp_info; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00905"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00907"); |
| vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| m_errorMonitor->VerifyFound(); |
| |
| dev_grp_rp_info.deviceMask = 0; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00906"); |
| vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| m_errorMonitor->VerifyFound(); |
| |
| dev_grp_rp_info.deviceMask = 0x00000001; |
| dev_grp_rp_info.deviceRenderAreaCount = physical_device_group[0].physicalDeviceCount + 1; |
| std::vector<VkRect2D> device_render_areas(dev_grp_rp_info.deviceRenderAreaCount, m_renderPassBeginInfo.renderArea); |
| dev_grp_rp_info.pDeviceRenderAreas = device_render_areas.data(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkDeviceGroupRenderPassBeginInfo-deviceRenderAreaCount-00908"); |
| vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test vkCmdSetDeviceMask() |
| vkCmdSetDeviceMask(m_commandBuffer->handle(), 0x00000001); |
| |
| dev_grp_rp_info.deviceRenderAreaCount = physical_device_group[0].physicalDeviceCount; |
| vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetDeviceMask-deviceMask-00108"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetDeviceMask-deviceMask-00110"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetDeviceMask-deviceMask-00111"); |
| vkCmdSetDeviceMask(m_commandBuffer->handle(), 0xFFFFFFFF); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetDeviceMask-deviceMask-00109"); |
| vkCmdSetDeviceMask(m_commandBuffer->handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| VkSemaphoreCreateInfo semaphore_create_info = {}; |
| semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
| VkSemaphore semaphore; |
| ASSERT_VK_SUCCESS(vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore)); |
| VkSemaphore semaphore2; |
| ASSERT_VK_SUCCESS(vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore2)); |
| VkFenceCreateInfo fence_create_info = {}; |
| fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
| VkFence fence; |
| ASSERT_VK_SUCCESS(vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence)); |
| |
| if (support_surface) { |
| // Test VkAcquireNextImageInfoKHR |
| uint32_t imageIndex = 0; |
| VkAcquireNextImageInfoKHR acquire_next_image_info = {}; |
| acquire_next_image_info.sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR; |
| acquire_next_image_info.semaphore = semaphore; |
| acquire_next_image_info.swapchain = m_swapchain; |
| acquire_next_image_info.fence = fence; |
| acquire_next_image_info.deviceMask = 0xFFFFFFFF; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAcquireNextImageInfoKHR-deviceMask-01290"); |
| vkAcquireNextImage2KHR(m_device->device(), &acquire_next_image_info, &imageIndex); |
| m_errorMonitor->VerifyFound(); |
| |
| vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, std::numeric_limits<int>::max()); |
| vkResetFences(m_device->device(), 1, &fence); |
| |
| acquire_next_image_info.semaphore = semaphore2; |
| acquire_next_image_info.deviceMask = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAcquireNextImageInfoKHR-deviceMask-01291"); |
| vkAcquireNextImage2KHR(m_device->device(), &acquire_next_image_info, &imageIndex); |
| m_errorMonitor->VerifyFound(); |
| DestroySwapchain(); |
| } |
| |
| // Test VkDeviceGroupSubmitInfo |
| VkDeviceGroupSubmitInfo device_group_submit_info = {}; |
| device_group_submit_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO; |
| device_group_submit_info.commandBufferCount = 1; |
| std::array<uint32_t, 1> command_buffer_device_masks = {0xFFFFFFFF}; |
| device_group_submit_info.pCommandBufferDeviceMasks = command_buffer_device_masks.data(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.pNext = &device_group_submit_info; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| |
| m_commandBuffer->reset(); |
| vkBeginCommandBuffer(m_commandBuffer->handle(), &cmd_buf_info); |
| vkEndCommandBuffer(m_commandBuffer->handle()); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkDeviceGroupSubmitInfo-pCommandBufferDeviceMasks-00086"); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| vkQueueWaitIdle(m_device->m_queue); |
| |
| vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, std::numeric_limits<int>::max()); |
| vkDestroyFence(m_device->device(), fence, nullptr); |
| vkDestroySemaphore(m_device->device(), semaphore, nullptr); |
| vkDestroySemaphore(m_device->device(), semaphore2, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, ValidationCacheTestBadMerge) { |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| if (DeviceExtensionSupported(gpu(), "VK_LAYER_LUNARG_core_validation", VK_EXT_VALIDATION_CACHE_EXTENSION_NAME)) { |
| m_device_extension_names.push_back(VK_EXT_VALIDATION_CACHE_EXTENSION_NAME); |
| } else { |
| printf("%s %s not supported, skipping test\n", kSkipPrefix, VK_EXT_VALIDATION_CACHE_EXTENSION_NAME); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Load extension functions |
| auto fpCreateValidationCache = |
| (PFN_vkCreateValidationCacheEXT)vkGetDeviceProcAddr(m_device->device(), "vkCreateValidationCacheEXT"); |
| auto fpDestroyValidationCache = |
| (PFN_vkDestroyValidationCacheEXT)vkGetDeviceProcAddr(m_device->device(), "vkDestroyValidationCacheEXT"); |
| auto fpMergeValidationCaches = |
| (PFN_vkMergeValidationCachesEXT)vkGetDeviceProcAddr(m_device->device(), "vkMergeValidationCachesEXT"); |
| if (!fpCreateValidationCache || !fpDestroyValidationCache || !fpMergeValidationCaches) { |
| printf("%s Failed to load function pointers for %s\n", kSkipPrefix, VK_EXT_VALIDATION_CACHE_EXTENSION_NAME); |
| return; |
| } |
| |
| VkValidationCacheCreateInfoEXT validationCacheCreateInfo; |
| validationCacheCreateInfo.sType = VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT; |
| validationCacheCreateInfo.pNext = NULL; |
| validationCacheCreateInfo.initialDataSize = 0; |
| validationCacheCreateInfo.pInitialData = NULL; |
| validationCacheCreateInfo.flags = 0; |
| VkValidationCacheEXT validationCache = VK_NULL_HANDLE; |
| VkResult res = fpCreateValidationCache(m_device->device(), &validationCacheCreateInfo, nullptr, &validationCache); |
| ASSERT_VK_SUCCESS(res); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkMergeValidationCachesEXT-dstCache-01536"); |
| res = fpMergeValidationCaches(m_device->device(), validationCache, 1, &validationCache); |
| m_errorMonitor->VerifyFound(); |
| |
| fpDestroyValidationCache(m_device->device(), validationCache, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, InvalidQueueFamilyIndex) { |
| // Miscellaneous queueFamilyIndex validation tests |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| VkBufferCreateInfo buffCI = {}; |
| buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffCI.size = 1024; |
| buffCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| buffCI.queueFamilyIndexCount = 2; |
| // Introduce failure by specifying invalid queue_family_index |
| uint32_t qfi[2]; |
| qfi[0] = 777; |
| qfi[1] = 0; |
| |
| buffCI.pQueueFamilyIndices = qfi; |
| buffCI.sharingMode = VK_SHARING_MODE_CONCURRENT; // qfi only matters in CONCURRENT mode |
| |
| // Test for queue family index out of range |
| CreateBufferTest(*this, &buffCI, "VUID-VkBufferCreateInfo-sharingMode-01419"); |
| |
| // Test for non-unique QFI in array |
| qfi[0] = 0; |
| CreateBufferTest(*this, &buffCI, "VUID-VkBufferCreateInfo-sharingMode-01419"); |
| |
| if (m_device->queue_props.size() > 2) { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "which was not created allowing concurrent"); |
| |
| // Create buffer shared to queue families 1 and 2, but submitted on queue family 0 |
| buffCI.queueFamilyIndexCount = 2; |
| qfi[0] = 1; |
| qfi[1] = 2; |
| VkBufferObj ib; |
| ib.init(*m_device, buffCI); |
| |
| m_commandBuffer->begin(); |
| vkCmdFillBuffer(m_commandBuffer->handle(), ib.handle(), 0, 16, 5); |
| m_commandBuffer->end(); |
| m_commandBuffer->QueueCommandBuffer(false); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, InvalidQueryPoolCreate) { |
| TEST_DESCRIPTION("Attempt to create a query pool for PIPELINE_STATISTICS without enabling pipeline stats for the device."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props); |
| |
| VkDevice local_device; |
| VkDeviceCreateInfo device_create_info = {}; |
| auto features = m_device->phy().features(); |
| // Intentionally disable pipeline stats |
| features.pipelineStatisticsQuery = VK_FALSE; |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.pNext = NULL; |
| device_create_info.queueCreateInfoCount = queue_info.size(); |
| device_create_info.pQueueCreateInfos = queue_info.data(); |
| device_create_info.enabledLayerCount = 0; |
| device_create_info.ppEnabledLayerNames = NULL; |
| device_create_info.pEnabledFeatures = &features; |
| VkResult err = vkCreateDevice(gpu(), &device_create_info, nullptr, &local_device); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkQueryPoolCreateInfo qpci{}; |
| qpci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| qpci.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; |
| qpci.queryCount = 1; |
| VkQueryPool query_pool; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkQueryPoolCreateInfo-queryType-00791"); |
| vkCreateQueryPool(local_device, &qpci, nullptr, &query_pool); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyDevice(local_device, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, UnclosedQuery) { |
| TEST_DESCRIPTION("End a command buffer with a query still in progress."); |
| |
| const char *invalid_query = "VUID-vkEndCommandBuffer-commandBuffer-00061"; |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkEvent event; |
| VkEventCreateInfo event_create_info{}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); |
| |
| VkQueue queue = VK_NULL_HANDLE; |
| vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); |
| |
| m_commandBuffer->begin(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, invalid_query); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info = {}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0 /*startQuery*/, 1 /*queryCount*/); |
| vkCmdBeginQuery(m_commandBuffer->handle(), query_pool, 0, 0); |
| |
| vkEndCommandBuffer(m_commandBuffer->handle()); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| vkDestroyEvent(m_device->device(), event, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, QueryPreciseBit) { |
| TEST_DESCRIPTION("Check for correct Query Precise Bit circumstances."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // These tests require that the device support pipeline statistics query |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| if (VK_TRUE != device_features.pipelineStatisticsQuery) { |
| printf("%s Test requires unsupported pipelineStatisticsQuery feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| std::vector<const char *> device_extension_names; |
| auto features = m_device->phy().features(); |
| |
| // Test for precise bit when query type is not OCCLUSION |
| if (features.occlusionQueryPrecise) { |
| VkEvent event; |
| VkEventCreateInfo event_create_info{}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(m_device->handle(), &event_create_info, nullptr, &event); |
| |
| m_commandBuffer->begin(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginQuery-queryType-00800"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info = {}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->handle(), &query_pool_create_info, nullptr, &query_pool); |
| |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1); |
| vkCmdBeginQuery(m_commandBuffer->handle(), query_pool, 0, VK_QUERY_CONTROL_PRECISE_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->end(); |
| vkDestroyQueryPool(m_device->handle(), query_pool, nullptr); |
| vkDestroyEvent(m_device->handle(), event, nullptr); |
| } |
| |
| // Test for precise bit when precise feature is not available |
| features.occlusionQueryPrecise = false; |
| VkDeviceObj test_device(0, gpu(), device_extension_names, &features); |
| |
| VkCommandPoolCreateInfo pool_create_info{}; |
| pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
| pool_create_info.queueFamilyIndex = test_device.graphics_queue_node_index_; |
| |
| VkCommandPool command_pool; |
| vkCreateCommandPool(test_device.handle(), &pool_create_info, nullptr, &command_pool); |
| |
| VkCommandBufferAllocateInfo cmd = {}; |
| cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| cmd.pNext = NULL; |
| cmd.commandPool = command_pool; |
| cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| cmd.commandBufferCount = 1; |
| |
| VkCommandBuffer cmd_buffer; |
| VkResult err = vkAllocateCommandBuffers(test_device.handle(), &cmd, &cmd_buffer); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkEvent event; |
| VkEventCreateInfo event_create_info{}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(test_device.handle(), &event_create_info, nullptr, &event); |
| |
| VkCommandBufferBeginInfo begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr}; |
| |
| vkBeginCommandBuffer(cmd_buffer, &begin_info); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginQuery-queryType-00800"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info = {}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(test_device.handle(), &query_pool_create_info, nullptr, &query_pool); |
| |
| vkCmdResetQueryPool(cmd_buffer, query_pool, 0, 1); |
| vkCmdBeginQuery(cmd_buffer, query_pool, 0, VK_QUERY_CONTROL_PRECISE_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| vkEndCommandBuffer(cmd_buffer); |
| vkDestroyQueryPool(test_device.handle(), query_pool, nullptr); |
| vkDestroyEvent(test_device.handle(), event, nullptr); |
| vkDestroyCommandPool(test_device.handle(), command_pool, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, StageMaskGsTsEnabled) { |
| TEST_DESCRIPTION( |
| "Attempt to use a stageMask w/ geometry shader and tesselation shader bits enabled when those features are disabled on the " |
| "device."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| std::vector<const char *> device_extension_names; |
| auto features = m_device->phy().features(); |
| // Make sure gs & ts are disabled |
| features.geometryShader = false; |
| features.tessellationShader = false; |
| // The sacrificial device object |
| VkDeviceObj test_device(0, gpu(), device_extension_names, &features); |
| |
| VkCommandPoolCreateInfo pool_create_info{}; |
| pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
| pool_create_info.queueFamilyIndex = test_device.graphics_queue_node_index_; |
| |
| VkCommandPool command_pool; |
| vkCreateCommandPool(test_device.handle(), &pool_create_info, nullptr, &command_pool); |
| |
| VkCommandBufferAllocateInfo cmd = {}; |
| cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| cmd.pNext = NULL; |
| cmd.commandPool = command_pool; |
| cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| cmd.commandBufferCount = 1; |
| |
| VkCommandBuffer cmd_buffer; |
| VkResult err = vkAllocateCommandBuffers(test_device.handle(), &cmd, &cmd_buffer); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkEvent event; |
| VkEventCreateInfo evci = {}; |
| evci.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| VkResult result = vkCreateEvent(test_device.handle(), &evci, NULL, &event); |
| ASSERT_VK_SUCCESS(result); |
| |
| VkCommandBufferBeginInfo cbbi = {}; |
| cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| vkBeginCommandBuffer(cmd_buffer, &cbbi); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetEvent-stageMask-01150"); |
| vkCmdSetEvent(cmd_buffer, event, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetEvent-stageMask-01151"); |
| vkCmdSetEvent(cmd_buffer, event, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyEvent(test_device.handle(), event, NULL); |
| vkDestroyCommandPool(test_device.handle(), command_pool, NULL); |
| } |
| |
| TEST_F(VkLayerTest, DescriptorPoolInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete a DescriptorPool with a DescriptorSet that is in use."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitViewport()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| // Create image to update the descriptor with |
| VkImageObj image(m_device); |
| image.Init(32, 32, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageView view = image.targetView(VK_FORMAT_B8G8R8A8_UNORM); |
| // Create Sampler |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| VkSampler sampler; |
| VkResult err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Create PSO to be used for draw-time errors below |
| VkShaderObj fs(m_device, bindStateFragSamplerShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| const VkDynamicState dyn_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; |
| dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
| dyn_state_ci.dynamicStateCount = size(dyn_states); |
| dyn_state_ci.pDynamicStates = dyn_states; |
| pipe.dyn_state_ci_ = dyn_state_ci; |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| // Update descriptor with image and sampler |
| pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, NULL); |
| |
| VkViewport viewport = {0, 0, 16, 16, 0, 1}; |
| VkRect2D scissor = {{0, 0}, {16, 16}}; |
| vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport); |
| vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor); |
| |
| m_commandBuffer->Draw(1, 0, 0, 0); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| // Submit cmd buffer to put pool in-flight |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| // Destroy pool while in-flight, causing error |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyDescriptorPool-descriptorPool-00303"); |
| vkDestroyDescriptorPool(m_device->device(), pipe.descriptor_set_->pool_, NULL); |
| m_errorMonitor->VerifyFound(); |
| vkQueueWaitIdle(m_device->m_queue); |
| // Cleanup |
| vkDestroySampler(m_device->device(), sampler, NULL); |
| m_errorMonitor->SetUnexpectedError( |
| "If descriptorPool is not VK_NULL_HANDLE, descriptorPool must be a valid VkDescriptorPool handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove DescriptorPool obj"); |
| // TODO : It seems Validation layers think ds_pool was already destroyed, even though it wasn't? |
| } |
| |
| TEST_F(VkLayerTest, FramebufferInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use framebuffer."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| VkFormatProperties format_properties; |
| VkResult err = VK_SUCCESS; |
| vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_B8G8R8A8_UNORM, &format_properties); |
| |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkImageObj image(m_device); |
| image.Init(256, 256, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| VkImageView view = image.targetView(VK_FORMAT_B8G8R8A8_UNORM); |
| |
| VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, m_renderPass, 1, &view, 256, 256, 1}; |
| VkFramebuffer fb; |
| err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Just use default renderpass with our framebuffer |
| m_renderPassBeginInfo.framebuffer = fb; |
| // Create Null cmd buffer for submit |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| // Submit cmd buffer to put it in-flight |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| // Destroy framebuffer while in-flight |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyFramebuffer-framebuffer-00892"); |
| vkDestroyFramebuffer(m_device->device(), fb, NULL); |
| m_errorMonitor->VerifyFound(); |
| // Wait for queue to complete so we can safely destroy everything |
| vkQueueWaitIdle(m_device->m_queue); |
| m_errorMonitor->SetUnexpectedError("If framebuffer is not VK_NULL_HANDLE, framebuffer must be a valid VkFramebuffer handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Framebuffer obj"); |
| vkDestroyFramebuffer(m_device->device(), fb, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, FramebufferImageInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use image that's child of framebuffer."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| VkFormatProperties format_properties; |
| VkResult err = VK_SUCCESS; |
| vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_B8G8R8A8_UNORM, &format_properties); |
| |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkImageCreateInfo image_ci = {}; |
| image_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_ci.pNext = NULL; |
| image_ci.imageType = VK_IMAGE_TYPE_2D; |
| image_ci.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_ci.extent.width = 256; |
| image_ci.extent.height = 256; |
| image_ci.extent.depth = 1; |
| image_ci.mipLevels = 1; |
| image_ci.arrayLayers = 1; |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_ci.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| image_ci.flags = 0; |
| VkImageObj image(m_device); |
| image.init(&image_ci); |
| |
| VkImageView view = image.targetView(VK_FORMAT_B8G8R8A8_UNORM); |
| |
| VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, m_renderPass, 1, &view, 256, 256, 1}; |
| VkFramebuffer fb; |
| err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Just use default renderpass with our framebuffer |
| m_renderPassBeginInfo.framebuffer = fb; |
| // Create Null cmd buffer for submit |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| // Submit cmd buffer to put it (and attached imageView) in-flight |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| // Submit cmd buffer to put framebuffer and children in-flight |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| // Destroy image attached to framebuffer while in-flight |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyImage-image-01000"); |
| vkDestroyImage(m_device->device(), image.handle(), NULL); |
| m_errorMonitor->VerifyFound(); |
| // Wait for queue to complete so we can safely destroy image and other objects |
| vkQueueWaitIdle(m_device->m_queue); |
| m_errorMonitor->SetUnexpectedError("If image is not VK_NULL_HANDLE, image must be a valid VkImage handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Image obj"); |
| vkDestroyFramebuffer(m_device->device(), fb, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, EventInUseDestroyedSignaled) { |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| m_commandBuffer->begin(); |
| |
| VkEvent event; |
| VkEventCreateInfo event_create_info = {}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); |
| vkCmdSetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); |
| |
| m_commandBuffer->end(); |
| vkDestroyEvent(m_device->device(), event, nullptr); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is invalid because bound"); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InUseDestroyedSignaled) { |
| TEST_DESCRIPTION( |
| "Use vkCmdExecuteCommands with invalid state in primary and secondary command buffers. Delete objects that are in use. " |
| "Call VkQueueSubmit with an event that has been deleted."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| m_errorMonitor->ExpectSuccess(); |
| |
| VkSemaphoreCreateInfo semaphore_create_info = {}; |
| semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
| VkSemaphore semaphore; |
| ASSERT_VK_SUCCESS(vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore)); |
| VkFenceCreateInfo fence_create_info = {}; |
| fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
| VkFence fence; |
| ASSERT_VK_SUCCESS(vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence)); |
| |
| VkBufferTest buffer_test(m_device, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| pipe.descriptor_set_->WriteDescriptorBufferInfo(0, buffer_test.GetBuffer(), 1024, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| VkEvent event; |
| VkEventCreateInfo event_create_info = {}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); |
| |
| m_commandBuffer->begin(); |
| |
| vkCmdSetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); |
| |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, NULL); |
| |
| m_commandBuffer->end(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| submit_info.signalSemaphoreCount = 1; |
| submit_info.pSignalSemaphores = &semaphore; |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); |
| m_errorMonitor->Reset(); // resume logmsg processing |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyEvent-event-01145"); |
| vkDestroyEvent(m_device->device(), event, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroySemaphore-semaphore-01137"); |
| vkDestroySemaphore(m_device->device(), semaphore, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyFence-fence-01120"); |
| vkDestroyFence(m_device->device(), fence, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| vkQueueWaitIdle(m_device->m_queue); |
| m_errorMonitor->SetUnexpectedError("If semaphore is not VK_NULL_HANDLE, semaphore must be a valid VkSemaphore handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Semaphore obj"); |
| vkDestroySemaphore(m_device->device(), semaphore, nullptr); |
| m_errorMonitor->SetUnexpectedError("If fence is not VK_NULL_HANDLE, fence must be a valid VkFence handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Fence obj"); |
| vkDestroyFence(m_device->device(), fence, nullptr); |
| m_errorMonitor->SetUnexpectedError("If event is not VK_NULL_HANDLE, event must be a valid VkEvent handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Event obj"); |
| vkDestroyEvent(m_device->device(), event, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, QueryPoolPartialTimestamp) { |
| TEST_DESCRIPTION("Request partial result on timestamp query."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_ci{}; |
| query_pool_ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_ci.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_ci.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_ci, nullptr, &query_pool); |
| |
| m_commandBuffer->begin(); |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1); |
| vkCmdWriteTimestamp(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); |
| m_commandBuffer->end(); |
| |
| // Submit cmd buffer and wait for it. |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| vkQueueWaitIdle(m_device->m_queue); |
| |
| // Attempt to obtain partial results. |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetQueryPoolResults-queryType-00818"); |
| uint32_t data_space[16]; |
| m_errorMonitor->SetUnexpectedError("Cannot get query results on queryPool"); |
| vkGetQueryPoolResults(m_device->handle(), query_pool, 0, 1, sizeof(data_space), &data_space, sizeof(uint32_t), |
| VK_QUERY_RESULT_PARTIAL_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| // Destroy query pool. |
| vkDestroyQueryPool(m_device->handle(), query_pool, NULL); |
| } |
| |
| TEST_F(VkLayerTest, QueryPoolInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use query pool."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_ci{}; |
| query_pool_ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_ci.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_ci.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_ci, nullptr, &query_pool); |
| |
| m_commandBuffer->begin(); |
| // Use query pool to create binding with cmd buffer |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1); |
| vkCmdWriteTimestamp(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); |
| m_commandBuffer->end(); |
| |
| // Submit cmd buffer and then destroy query pool while in-flight |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyQueryPool-queryPool-00793"); |
| vkDestroyQueryPool(m_device->handle(), query_pool, NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| vkQueueWaitIdle(m_device->m_queue); |
| // Now that cmd buffer done we can safely destroy query_pool |
| m_errorMonitor->SetUnexpectedError("If queryPool is not VK_NULL_HANDLE, queryPool must be a valid VkQueryPool handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove QueryPool obj"); |
| vkDestroyQueryPool(m_device->handle(), query_pool, NULL); |
| } |
| |
| TEST_F(VkLayerTest, PipelineInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use pipeline."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| const VkPipelineLayoutObj pipeline_layout(m_device); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyPipeline-pipeline-00765"); |
| // Create PSO to be used for draw-time errors below |
| |
| // Store pipeline handle so we can actually delete it before test finishes |
| VkPipeline delete_this_pipeline; |
| { // Scope pipeline so it will be auto-deleted |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| delete_this_pipeline = pipe.pipeline_; |
| |
| m_commandBuffer->begin(); |
| // Bind pipeline to cmd buffer |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| |
| m_commandBuffer->end(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| // Submit cmd buffer and then pipeline destroyed while in-flight |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| } // Pipeline deletion triggered here |
| m_errorMonitor->VerifyFound(); |
| // Make sure queue finished and then actually delete pipeline |
| vkQueueWaitIdle(m_device->m_queue); |
| m_errorMonitor->SetUnexpectedError("If pipeline is not VK_NULL_HANDLE, pipeline must be a valid VkPipeline handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Pipeline obj"); |
| vkDestroyPipeline(m_device->handle(), delete_this_pipeline, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, ImageViewInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use imageView."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| VkSampler sampler; |
| |
| VkResult err; |
| err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkImageObj image(m_device); |
| image.Init(128, 128, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageView view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM); |
| |
| // Create PSO to use the sampler |
| VkShaderObj fs(m_device, bindStateFragSamplerShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| const VkDynamicState dyn_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; |
| dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
| dyn_state_ci.dynamicStateCount = size(dyn_states); |
| dyn_state_ci.pDynamicStates = dyn_states; |
| pipe.dyn_state_ci_ = dyn_state_ci; |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyImageView-imageView-01026"); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| // Bind pipeline to cmd buffer |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, nullptr); |
| |
| VkViewport viewport = {0, 0, 16, 16, 0, 1}; |
| VkRect2D scissor = {{0, 0}, {16, 16}}; |
| vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport); |
| vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor); |
| |
| m_commandBuffer->Draw(1, 0, 0, 0); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| // Submit cmd buffer then destroy sampler |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| // Submit cmd buffer and then destroy imageView while in-flight |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| vkDestroyImageView(m_device->device(), view, nullptr); |
| m_errorMonitor->VerifyFound(); |
| vkQueueWaitIdle(m_device->m_queue); |
| // Now we can actually destroy imageView |
| m_errorMonitor->SetUnexpectedError("If imageView is not VK_NULL_HANDLE, imageView must be a valid VkImageView handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove ImageView obj"); |
| vkDestroySampler(m_device->device(), sampler, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, BufferViewInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use bufferView."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| uint32_t queue_family_index = 0; |
| VkBufferCreateInfo buffer_create_info = {}; |
| buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffer_create_info.size = 1024; |
| buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| buffer_create_info.queueFamilyIndexCount = 1; |
| buffer_create_info.pQueueFamilyIndices = &queue_family_index; |
| VkBufferObj buffer; |
| buffer.init(*m_device, buffer_create_info); |
| |
| VkBufferView view; |
| VkBufferViewCreateInfo bvci = {}; |
| bvci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; |
| bvci.buffer = buffer.handle(); |
| bvci.format = VK_FORMAT_R32_SFLOAT; |
| bvci.range = VK_WHOLE_SIZE; |
| |
| VkResult err = vkCreateBufferView(m_device->device(), &bvci, NULL, &view); |
| ASSERT_VK_SUCCESS(err); |
| |
| char const *fsSource = |
| "#version 450\n" |
| "\n" |
| "layout(set=0, binding=0, r32f) uniform readonly imageBuffer s;\n" |
| "layout(location=0) out vec4 x;\n" |
| "void main(){\n" |
| " x = imageLoad(s, 0);\n" |
| "}\n"; |
| VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| const VkDynamicState dyn_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; |
| dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
| dyn_state_ci.dynamicStateCount = size(dyn_states); |
| dyn_state_ci.pDynamicStates = dyn_states; |
| pipe.dyn_state_ci_ = dyn_state_ci; |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| pipe.descriptor_set_->WriteDescriptorBufferView(0, view, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER); |
| pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyBufferView-bufferView-00936"); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| VkViewport viewport = {0, 0, 16, 16, 0, 1}; |
| vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport); |
| VkRect2D scissor = {{0, 0}, {16, 16}}; |
| vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor); |
| // Bind pipeline to cmd buffer |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, nullptr); |
| m_commandBuffer->Draw(1, 0, 0, 0); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| // Submit cmd buffer and then destroy bufferView while in-flight |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| vkDestroyBufferView(m_device->device(), view, nullptr); |
| m_errorMonitor->VerifyFound(); |
| vkQueueWaitIdle(m_device->m_queue); |
| // Now we can actually destroy bufferView |
| m_errorMonitor->SetUnexpectedError("If bufferView is not VK_NULL_HANDLE, bufferView must be a valid VkBufferView handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove BufferView obj"); |
| vkDestroyBufferView(m_device->device(), view, NULL); |
| } |
| |
| TEST_F(VkLayerTest, SamplerInUseDestroyedSignaled) { |
| TEST_DESCRIPTION("Delete in-use sampler."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| VkSampler sampler; |
| |
| VkResult err; |
| err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkImageObj image(m_device); |
| image.Init(128, 128, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageView view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM); |
| |
| // Create PSO to use the sampler |
| VkShaderObj fs(m_device, bindStateFragSamplerShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| const VkDynamicState dyn_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; |
| dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
| dyn_state_ci.dynamicStateCount = size(dyn_states); |
| dyn_state_ci.pDynamicStates = dyn_states; |
| pipe.dyn_state_ci_ = dyn_state_ci; |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroySampler-sampler-01082"); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| // Bind pipeline to cmd buffer |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, nullptr); |
| |
| VkViewport viewport = {0, 0, 16, 16, 0, 1}; |
| VkRect2D scissor = {{0, 0}, {16, 16}}; |
| vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport); |
| vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor); |
| |
| m_commandBuffer->Draw(1, 0, 0, 0); |
| m_commandBuffer->EndRenderPass(); |
| m_commandBuffer->end(); |
| // Submit cmd buffer then destroy sampler |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| // Submit cmd buffer and then destroy sampler while in-flight |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| vkDestroySampler(m_device->device(), sampler, nullptr); // Destroyed too soon |
| m_errorMonitor->VerifyFound(); |
| vkQueueWaitIdle(m_device->m_queue); |
| |
| // Now we can actually destroy sampler |
| m_errorMonitor->SetUnexpectedError("If sampler is not VK_NULL_HANDLE, sampler must be a valid VkSampler handle"); |
| m_errorMonitor->SetUnexpectedError("Unable to remove Sampler obj"); |
| vkDestroySampler(m_device->device(), sampler, NULL); // Destroyed for real |
| } |
| |
| TEST_F(VkLayerTest, QueueForwardProgressFenceWait) { |
| TEST_DESCRIPTION("Call VkQueueSubmit with a semaphore that is already signaled but not waited on by the queue."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| const char *queue_forward_progress_message = "UNASSIGNED-CoreValidation-DrawState-QueueForwardProgress"; |
| |
| VkCommandBufferObj cb1(m_device, m_commandPool); |
| cb1.begin(); |
| cb1.end(); |
| |
| VkSemaphoreCreateInfo semaphore_create_info = {}; |
| semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
| VkSemaphore semaphore; |
| ASSERT_VK_SUCCESS(vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore)); |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &cb1.handle(); |
| submit_info.signalSemaphoreCount = 1; |
| submit_info.pSignalSemaphores = &semaphore; |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->end(); |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, queue_forward_progress_message); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDeviceWaitIdle(m_device->device()); |
| vkDestroySemaphore(m_device->device(), semaphore, nullptr); |
| } |
| |
| #if GTEST_IS_THREADSAFE |
| TEST_F(VkLayerTest, ThreadCommandBufferCollision) { |
| test_platform_thread thread; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "THREADING ERROR"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| ASSERT_NO_FATAL_FAILURE(InitViewport()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| // Calls AllocateCommandBuffers |
| VkCommandBufferObj commandBuffer(m_device, m_commandPool); |
| |
| commandBuffer.begin(); |
| |
| VkEventCreateInfo event_info; |
| VkEvent event; |
| VkResult err; |
| |
| memset(&event_info, 0, sizeof(event_info)); |
| event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| |
| err = vkCreateEvent(device(), &event_info, NULL, &event); |
| ASSERT_VK_SUCCESS(err); |
| |
| err = vkResetEvent(device(), event); |
| ASSERT_VK_SUCCESS(err); |
| |
| struct thread_data_struct data; |
| data.commandBuffer = commandBuffer.handle(); |
| data.event = event; |
| data.bailout = false; |
| m_errorMonitor->SetBailout(&data.bailout); |
| |
| // First do some correct operations using multiple threads. |
| // Add many entries to command buffer from another thread. |
| test_platform_thread_create(&thread, AddToCommandBuffer, (void *)&data); |
| // Make non-conflicting calls from this thread at the same time. |
| for (int i = 0; i < 80000; i++) { |
| uint32_t count; |
| vkEnumeratePhysicalDevices(instance(), &count, NULL); |
| } |
| test_platform_thread_join(thread, NULL); |
| |
| // Then do some incorrect operations using multiple threads. |
| // Add many entries to command buffer from another thread. |
| test_platform_thread_create(&thread, AddToCommandBuffer, (void *)&data); |
| // Add many entries to command buffer from this thread at the same time. |
| AddToCommandBuffer(&data); |
| |
| test_platform_thread_join(thread, NULL); |
| commandBuffer.end(); |
| |
| m_errorMonitor->SetBailout(NULL); |
| |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyEvent(device(), event, NULL); |
| } |
| #endif // GTEST_IS_THREADSAFE |
| |
| TEST_F(VkLayerTest, ExecuteUnrecordedPrimaryCB) { |
| TEST_DESCRIPTION("Attempt vkQueueSubmit with a CB in the initial state"); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| // never record m_commandBuffer |
| |
| VkSubmitInfo si = {}; |
| si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| si.commandBufferCount = 1; |
| si.pCommandBuffers = &m_commandBuffer->handle(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkQueueSubmit-pCommandBuffers-00072"); |
| vkQueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, Maintenance1AndNegativeViewport) { |
| TEST_DESCRIPTION("Attempt to enable AMD_negative_viewport_height and Maintenance1_KHR extension simultaneously"); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| if (!((DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE1_EXTENSION_NAME)) && |
| (DeviceExtensionSupported(gpu(), nullptr, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME)))) { |
| printf("%s Maintenance1 and AMD_negative viewport height extensions not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props); |
| const char *extension_names[2] = {"VK_KHR_maintenance1", "VK_AMD_negative_viewport_height"}; |
| VkDevice testDevice; |
| VkDeviceCreateInfo device_create_info = {}; |
| auto features = m_device->phy().features(); |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.pNext = NULL; |
| device_create_info.queueCreateInfoCount = queue_info.size(); |
| device_create_info.pQueueCreateInfos = queue_info.data(); |
| device_create_info.enabledLayerCount = 0; |
| device_create_info.ppEnabledLayerNames = NULL; |
| device_create_info.enabledExtensionCount = 2; |
| device_create_info.ppEnabledExtensionNames = (const char *const *)extension_names; |
| device_create_info.pEnabledFeatures = &features; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374"); |
| // The following unexpected error is coming from the LunarG loader. Do not make it a desired message because platforms that do |
| // not use the LunarG loader (e.g. Android) will not see the message and the test will fail. |
| m_errorMonitor->SetUnexpectedError("Failed to create device chain."); |
| vkCreateDevice(gpu(), &device_create_info, NULL, &testDevice); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, HostQueryResetNotEnabled) { |
| TEST_DESCRIPTION("Use vkResetQueryPoolEXT without enabling the feature"); |
| |
| if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) { |
| printf("%s Extension %s not supported by device; skipped.\n", kSkipPrefix, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| return; |
| } |
| |
| m_device_extension_names.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| auto fpvkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)vkGetDeviceProcAddr(m_device->device(), "vkResetQueryPoolEXT"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info{}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkResetQueryPoolEXT-None-02665"); |
| fpvkResetQueryPoolEXT(m_device->device(), query_pool, 0, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, HostQueryResetBadFirstQuery) { |
| TEST_DESCRIPTION("Bad firstQuery in vkResetQueryPoolEXT"); |
| |
| if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) { |
| printf("%s Extension %s not supported by device; skipped.\n", kSkipPrefix, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| return; |
| } |
| |
| m_device_extension_names.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| |
| VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset_features{}; |
| host_query_reset_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; |
| host_query_reset_features.hostQueryReset = VK_TRUE; |
| |
| VkPhysicalDeviceFeatures2 pd_features2{}; |
| pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
| pd_features2.pNext = &host_query_reset_features; |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2)); |
| |
| auto fpvkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)vkGetDeviceProcAddr(m_device->device(), "vkResetQueryPoolEXT"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info{}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkResetQueryPoolEXT-firstQuery-02666"); |
| fpvkResetQueryPoolEXT(m_device->device(), query_pool, 1, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, HostQueryResetBadRange) { |
| TEST_DESCRIPTION("Bad range in vkResetQueryPoolEXT"); |
| |
| if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) { |
| printf("%s Extension %s not supported by device; skipped.\n", kSkipPrefix, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| return; |
| } |
| |
| m_device_extension_names.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| |
| VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset_features{}; |
| host_query_reset_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; |
| host_query_reset_features.hostQueryReset = VK_TRUE; |
| |
| VkPhysicalDeviceFeatures2 pd_features2{}; |
| pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
| pd_features2.pNext = &host_query_reset_features; |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2)); |
| |
| auto fpvkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)vkGetDeviceProcAddr(m_device->device(), "vkResetQueryPoolEXT"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info{}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkResetQueryPoolEXT-firstQuery-02667"); |
| fpvkResetQueryPoolEXT(m_device->device(), query_pool, 0, 2); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, HostQueryResetInvalidQueryPool) { |
| TEST_DESCRIPTION("Invalid queryPool in vkResetQueryPoolEXT"); |
| |
| if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) { |
| printf("%s Extension %s not supported by device; skipped.\n", kSkipPrefix, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| return; |
| } |
| |
| m_device_extension_names.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| |
| VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset_features{}; |
| host_query_reset_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; |
| host_query_reset_features.hostQueryReset = VK_TRUE; |
| |
| VkPhysicalDeviceFeatures2 pd_features2{}; |
| pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
| pd_features2.pNext = &host_query_reset_features; |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2)); |
| |
| auto fpvkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)vkGetDeviceProcAddr(m_device->device(), "vkResetQueryPoolEXT"); |
| |
| // Create and destroy a query pool. |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info{}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| |
| // Attempt to reuse the query pool handle. |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkResetQueryPoolEXT-queryPool-parameter"); |
| fpvkResetQueryPoolEXT(m_device->device(), query_pool, 0, 1); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, HostQueryResetWrongDevice) { |
| TEST_DESCRIPTION("Device not matching queryPool in vkResetQueryPoolEXT"); |
| |
| if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) { |
| printf("%s Extension %s not supported by device; skipped.\n", kSkipPrefix, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| return; |
| } |
| |
| m_device_extension_names.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
| |
| VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset_features{}; |
| host_query_reset_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; |
| host_query_reset_features.hostQueryReset = VK_TRUE; |
| |
| VkPhysicalDeviceFeatures2 pd_features2{}; |
| pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
| pd_features2.pNext = &host_query_reset_features; |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2)); |
| |
| auto fpvkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)vkGetDeviceProcAddr(m_device->device(), "vkResetQueryPoolEXT"); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_create_info{}; |
| query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_create_info.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); |
| |
| // Create a second device with the feature enabled. |
| vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props); |
| auto features = m_device->phy().features(); |
| |
| VkDeviceCreateInfo device_create_info = {}; |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.pNext = &host_query_reset_features; |
| device_create_info.queueCreateInfoCount = queue_info.size(); |
| device_create_info.pQueueCreateInfos = queue_info.data(); |
| device_create_info.pEnabledFeatures = &features; |
| device_create_info.enabledExtensionCount = m_device_extension_names.size(); |
| device_create_info.ppEnabledExtensionNames = m_device_extension_names.data(); |
| |
| VkDevice second_device; |
| ASSERT_VK_SUCCESS(vkCreateDevice(gpu(), &device_create_info, nullptr, &second_device)); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkResetQueryPoolEXT-queryPool-parent"); |
| // Run vkResetQueryPoolExt on the wrong device. |
| fpvkResetQueryPoolEXT(second_device, query_pool, 0, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| vkDestroyQueryPool(m_device->device(), query_pool, nullptr); |
| vkDestroyDevice(second_device, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, ResetEventThenSet) { |
| TEST_DESCRIPTION("Reset an event then set it after the reset has been submitted."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| VkEvent event; |
| VkEventCreateInfo event_create_info{}; |
| event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; |
| vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); |
| |
| VkCommandPool command_pool; |
| VkCommandPoolCreateInfo pool_create_info{}; |
| pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
| pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; |
| pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
| vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); |
| |
| VkCommandBuffer command_buffer; |
| VkCommandBufferAllocateInfo command_buffer_allocate_info{}; |
| command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
| command_buffer_allocate_info.commandPool = command_pool; |
| command_buffer_allocate_info.commandBufferCount = 1; |
| command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); |
| |
| VkQueue queue = VK_NULL_HANDLE; |
| vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); |
| |
| { |
| VkCommandBufferBeginInfo begin_info{}; |
| begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| vkBeginCommandBuffer(command_buffer, &begin_info); |
| |
| vkCmdResetEvent(command_buffer, event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); |
| vkEndCommandBuffer(command_buffer); |
| } |
| { |
| VkSubmitInfo submit_info{}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &command_buffer; |
| submit_info.signalSemaphoreCount = 0; |
| submit_info.pSignalSemaphores = nullptr; |
| vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); |
| } |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is already in use by a command buffer."); |
| vkSetEvent(m_device->device(), event); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| vkQueueWaitIdle(queue); |
| |
| vkDestroyEvent(m_device->device(), event, nullptr); |
| vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); |
| vkDestroyCommandPool(m_device->device(), command_pool, NULL); |
| } |
| |
| TEST_F(VkLayerTest, ShadingRateImageNV) { |
| TEST_DESCRIPTION("Test VK_NV_shading_rate_image."); |
| |
| if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| } else { |
| printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| std::array<const char *, 1> required_device_extensions = {{VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME}}; |
| for (auto device_extension : required_device_extensions) { |
| if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) { |
| m_device_extension_names.push_back(device_extension); |
| } else { |
| printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension); |
| return; |
| } |
| } |
| |
| if (DeviceIsMockICD() || DeviceSimulation()) { |
| printf("%s Test not supported by MockICD, skipping tests\n", kSkipPrefix); |
| return; |
| } |
| |
| PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = |
| (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR"); |
| ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr); |
| |
| // Create a device that enables shading_rate_image but disables multiViewport |
| auto shading_rate_image_features = lvl_init_struct<VkPhysicalDeviceShadingRateImageFeaturesNV>(); |
| auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&shading_rate_image_features); |
| vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2); |
| |
| features2.features.multiViewport = VK_FALSE; |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2)); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| // Test shading rate image creation |
| VkResult result = VK_RESULT_MAX_ENUM; |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8_UINT; |
| image_create_info.extent.width = 4; |
| image_create_info.extent.height = 4; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| image_create_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| |
| // image type must be 2D |
| image_create_info.imageType = VK_IMAGE_TYPE_3D; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-02082"); |
| |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| |
| // must be single sample |
| image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-samples-02083"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| |
| // tiling must be optimal |
| image_create_info.tiling = VK_IMAGE_TILING_LINEAR; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-tiling-02084"); |
| |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| |
| // Should succeed. |
| VkImageObj image(m_device); |
| image.init(&image_create_info); |
| |
| // Test image view creation |
| VkImageView view; |
| VkImageViewCreateInfo ivci = {}; |
| ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
| ivci.image = image.handle(); |
| ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| ivci.format = VK_FORMAT_R8_UINT; |
| ivci.subresourceRange.layerCount = 1; |
| ivci.subresourceRange.baseMipLevel = 0; |
| ivci.subresourceRange.levelCount = 1; |
| ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| // view type must be 2D or 2D_ARRAY |
| ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02086"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-01003"); |
| result = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); |
| m_errorMonitor->VerifyFound(); |
| if (VK_SUCCESS == result) { |
| vkDestroyImageView(m_device->device(), view, NULL); |
| view = VK_NULL_HANDLE; |
| } |
| ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| |
| // format must be R8_UINT |
| ivci.format = VK_FORMAT_R8_UNORM; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02087"); |
| result = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); |
| m_errorMonitor->VerifyFound(); |
| if (VK_SUCCESS == result) { |
| vkDestroyImageView(m_device->device(), view, NULL); |
| view = VK_NULL_HANDLE; |
| } |
| ivci.format = VK_FORMAT_R8_UINT; |
| |
| vkCreateImageView(m_device->device(), &ivci, nullptr, &view); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Test pipeline creation |
| VkPipelineViewportShadingRateImageStateCreateInfoNV vsrisci = { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV}; |
| |
| VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f}; |
| VkViewport viewports[20] = {viewport, viewport}; |
| VkRect2D scissor = {{0, 0}, {64, 64}}; |
| VkRect2D scissors[20] = {scissor, scissor}; |
| VkDynamicState dynPalette = VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV; |
| VkPipelineDynamicStateCreateInfo dyn = {VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, 1, &dynPalette}; |
| |
| // viewportCount must be 0 or 1 when multiViewport is disabled |
| { |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.vp_state_ci_.viewportCount = 2; |
| helper.vp_state_ci_.pViewports = viewports; |
| helper.vp_state_ci_.scissorCount = 2; |
| helper.vp_state_ci_.pScissors = scissors; |
| helper.vp_state_ci_.pNext = &vsrisci; |
| helper.dyn_state_ci_ = dyn; |
| |
| vsrisci.shadingRateImageEnable = VK_TRUE; |
| vsrisci.viewportCount = 2; |
| }; |
| CreatePipelineHelper::OneshotTest( |
| *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-viewportCount-02054", |
| "VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216", |
| "VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217"})); |
| } |
| |
| // viewportCounts must match |
| { |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.vp_state_ci_.viewportCount = 1; |
| helper.vp_state_ci_.pViewports = viewports; |
| helper.vp_state_ci_.scissorCount = 1; |
| helper.vp_state_ci_.pScissors = scissors; |
| helper.vp_state_ci_.pNext = &vsrisci; |
| helper.dyn_state_ci_ = dyn; |
| |
| vsrisci.shadingRateImageEnable = VK_TRUE; |
| vsrisci.viewportCount = 0; |
| }; |
| CreatePipelineHelper::OneshotTest( |
| *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-shadingRateImageEnable-02056"})); |
| } |
| |
| // pShadingRatePalettes must not be NULL. |
| { |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.vp_state_ci_.viewportCount = 1; |
| helper.vp_state_ci_.pViewports = viewports; |
| helper.vp_state_ci_.scissorCount = 1; |
| helper.vp_state_ci_.pScissors = scissors; |
| helper.vp_state_ci_.pNext = &vsrisci; |
| |
| vsrisci.shadingRateImageEnable = VK_TRUE; |
| vsrisci.viewportCount = 1; |
| }; |
| CreatePipelineHelper::OneshotTest( |
| *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-pDynamicStates-02057"})); |
| } |
| |
| // Create an image without the SRI bit |
| VkImageObj nonSRIimage(m_device); |
| nonSRIimage.Init(256, 256, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(nonSRIimage.initialized()); |
| VkImageView nonSRIview = nonSRIimage.targetView(VK_FORMAT_B8G8R8A8_UNORM); |
| |
| // Test SRI layout on non-SRI image |
| VkImageMemoryBarrier img_barrier = {}; |
| img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
| img_barrier.pNext = nullptr; |
| img_barrier.srcAccessMask = 0; |
| img_barrier.dstAccessMask = 0; |
| img_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; |
| img_barrier.newLayout = VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV; |
| img_barrier.image = nonSRIimage.handle(); |
| img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| img_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| img_barrier.subresourceRange.baseArrayLayer = 0; |
| img_barrier.subresourceRange.baseMipLevel = 0; |
| img_barrier.subresourceRange.layerCount = 1; |
| img_barrier.subresourceRange.levelCount = 1; |
| |
| m_commandBuffer->begin(); |
| |
| // Error trying to convert it to SRI layout |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageMemoryBarrier-oldLayout-02088"); |
| vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, |
| nullptr, 0, nullptr, 1, &img_barrier); |
| m_errorMonitor->VerifyFound(); |
| |
| // succeed converting it to GENERAL |
| img_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
| vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, |
| nullptr, 0, nullptr, 1, &img_barrier); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Test vkCmdBindShadingRateImageNV errors |
| auto vkCmdBindShadingRateImageNV = |
| (PFN_vkCmdBindShadingRateImageNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdBindShadingRateImageNV"); |
| |
| // if the view is non-NULL, it must be R8_UINT, USAGE_SRI, image layout must match, layout must be valid |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBindShadingRateImageNV-imageView-02060"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBindShadingRateImageNV-imageView-02061"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBindShadingRateImageNV-imageView-02062"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBindShadingRateImageNV-imageLayout-02063"); |
| vkCmdBindShadingRateImageNV(m_commandBuffer->handle(), nonSRIview, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test vkCmdSetViewportShadingRatePaletteNV errors |
| auto vkCmdSetViewportShadingRatePaletteNV = |
| (PFN_vkCmdSetViewportShadingRatePaletteNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdSetViewportShadingRatePaletteNV"); |
| |
| VkShadingRatePaletteEntryNV paletteEntries[100] = {}; |
| VkShadingRatePaletteNV palette = {100, paletteEntries}; |
| VkShadingRatePaletteNV palettes[] = {palette, palette}; |
| |
| // errors on firstViewport/viewportCount |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02066"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02067"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02068"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdSetViewportShadingRatePaletteNV-viewportCount-02069"); |
| vkCmdSetViewportShadingRatePaletteNV(m_commandBuffer->handle(), 20, 2, palettes); |
| m_errorMonitor->VerifyFound(); |
| |
| // shadingRatePaletteEntryCount must be in range |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkShadingRatePaletteNV-shadingRatePaletteEntryCount-02071"); |
| vkCmdSetViewportShadingRatePaletteNV(m_commandBuffer->handle(), 0, 1, palettes); |
| m_errorMonitor->VerifyFound(); |
| |
| VkCoarseSampleLocationNV locations[100] = { |
| {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 1, 1}, // duplicate |
| {1000, 0, 0}, // pixelX too large |
| {0, 1000, 0}, // pixelY too large |
| {0, 0, 1000}, // sample too large |
| }; |
| |
| // Test custom sample orders, both via pipeline state and via dynamic state |
| { |
| VkCoarseSampleOrderCustomNV sampOrdBadShadingRate = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV, 1, 1, |
| locations}; |
| VkCoarseSampleOrderCustomNV sampOrdBadSampleCount = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 3, 1, |
| locations}; |
| VkCoarseSampleOrderCustomNV sampOrdBadSampleLocationCount = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, |
| 2, 2, locations}; |
| VkCoarseSampleOrderCustomNV sampOrdDuplicateLocations = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, |
| 1 * 2 * 2, &locations[1]}; |
| VkCoarseSampleOrderCustomNV sampOrdOutOfRangeLocations = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, |
| 1 * 2 * 2, &locations[4]}; |
| VkCoarseSampleOrderCustomNV sampOrdTooLargeSampleLocationCount = { |
| VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, 4, 64, &locations[8]}; |
| VkCoarseSampleOrderCustomNV sampOrdGood = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 1 * 2 * 2, |
| &locations[0]}; |
| |
| VkPipelineViewportCoarseSampleOrderStateCreateInfoNV csosci = { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV}; |
| csosci.sampleOrderType = VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV; |
| csosci.customSampleOrderCount = 1; |
| |
| using std::vector; |
| struct TestCase { |
| const VkCoarseSampleOrderCustomNV *order; |
| vector<std::string> vuids; |
| }; |
| |
| vector<TestCase> test_cases = { |
| {&sampOrdBadShadingRate, {"VUID-VkCoarseSampleOrderCustomNV-shadingRate-02073"}}, |
| {&sampOrdBadSampleCount, |
| {"VUID-VkCoarseSampleOrderCustomNV-sampleCount-02074", "VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}}, |
| {&sampOrdBadSampleLocationCount, {"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}}, |
| {&sampOrdDuplicateLocations, {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}}, |
| {&sampOrdOutOfRangeLocations, |
| {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077", "VUID-VkCoarseSampleLocationNV-pixelX-02078", |
| "VUID-VkCoarseSampleLocationNV-pixelY-02079", "VUID-VkCoarseSampleLocationNV-sample-02080"}}, |
| {&sampOrdTooLargeSampleLocationCount, |
| {"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02076", |
| "VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}}, |
| {&sampOrdGood, {}}, |
| }; |
| |
| for (const auto &test_case : test_cases) { |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.vp_state_ci_.pNext = &csosci; |
| csosci.pCustomSampleOrders = test_case.order; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuids); |
| } |
| |
| // Test vkCmdSetCoarseSampleOrderNV errors |
| auto vkCmdSetCoarseSampleOrderNV = |
| (PFN_vkCmdSetCoarseSampleOrderNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdSetCoarseSampleOrderNV"); |
| |
| for (const auto &test_case : test_cases) { |
| for (uint32_t i = 0; i < test_case.vuids.size(); ++i) { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuids[i]); |
| } |
| vkCmdSetCoarseSampleOrderNV(m_commandBuffer->handle(), VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV, 1, test_case.order); |
| if (test_case.vuids.size()) { |
| m_errorMonitor->VerifyFound(); |
| } else { |
| m_errorMonitor->VerifyNotFound(); |
| } |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdSetCoarseSampleOrderNV-sampleOrderType-02081"); |
| vkCmdSetCoarseSampleOrderNV(m_commandBuffer->handle(), VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV, 1, &sampOrdGood); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_commandBuffer->end(); |
| |
| vkDestroyImageView(m_device->device(), view, NULL); |
| } |
| |
| #ifdef VK_USE_PLATFORM_ANDROID_KHR |
| #include "android_ndk_types.h" |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferImageCreate) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer image create info."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkImage img = VK_NULL_HANDLE; |
| auto reset_img = [&img, dev]() { |
| if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL); |
| img = VK_NULL_HANDLE; |
| }; |
| |
| VkImageCreateInfo ici = {}; |
| ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| ici.pNext = nullptr; |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.arrayLayers = 1; |
| ici.extent = {64, 64, 1}; |
| ici.format = VK_FORMAT_UNDEFINED; |
| ici.mipLevels = 1; |
| ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| ici.samples = VK_SAMPLE_COUNT_1_BIT; |
| ici.tiling = VK_IMAGE_TILING_OPTIMAL; |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| |
| // undefined format |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01975"); |
| m_errorMonitor->SetUnexpectedError("VUID_Undefined"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| |
| // also undefined format |
| VkExternalFormatANDROID efa = {}; |
| efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| efa.externalFormat = 0; |
| ici.pNext = &efa; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01975"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| |
| // undefined format with an unknown external format |
| efa.externalFormat = 0xBADC0DE; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkExternalFormatANDROID-externalFormat-01894"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| |
| AHardwareBuffer *ahb; |
| AHardwareBuffer_Desc ahb_desc = {}; |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.width = 64; |
| ahb_desc.height = 64; |
| ahb_desc.layers = 1; |
| // Allocate an AHardwareBuffer |
| AHardwareBuffer_allocate(&ahb_desc, &ahb); |
| |
| // Retrieve it's properties to make it's external format 'known' (AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM) |
| VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {}; |
| ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; |
| VkAndroidHardwareBufferPropertiesANDROID ahb_props = {}; |
| ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; |
| ahb_props.pNext = &ahb_fmt_props; |
| PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps = |
| (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID"); |
| ASSERT_TRUE(pfn_GetAHBProps != nullptr); |
| pfn_GetAHBProps(dev, ahb, &ahb_props); |
| |
| // a defined image format with a non-zero external format |
| ici.format = VK_FORMAT_R8G8B8A8_UNORM; |
| efa.externalFormat = ahb_fmt_props.externalFormat; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01974"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| ici.format = VK_FORMAT_UNDEFINED; |
| |
| // external format while MUTABLE |
| ici.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02396"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| ici.flags = 0; |
| |
| // external format while usage other than SAMPLED |
| ici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02397"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| |
| // external format while tiline other than OPTIMAL |
| ici.tiling = VK_IMAGE_TILING_LINEAR; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02398"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| ici.tiling = VK_IMAGE_TILING_OPTIMAL; |
| |
| // imageType |
| VkExternalMemoryImageCreateInfo emici = {}; |
| emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; |
| emici.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; |
| ici.pNext = &emici; // remove efa from chain, insert emici |
| ici.format = VK_FORMAT_R8G8B8A8_UNORM; |
| ici.imageType = VK_IMAGE_TYPE_3D; |
| ici.extent = {64, 64, 64}; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02393"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| |
| // wrong mipLevels |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.extent = {64, 64, 1}; |
| ici.mipLevels = 6; // should be 7 |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02394"); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyFound(); |
| reset_img(); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferFetchUnboundImageInfo) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer retreive image properties while memory unbound."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkImage img = VK_NULL_HANDLE; |
| auto reset_img = [&img, dev]() { |
| if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL); |
| img = VK_NULL_HANDLE; |
| }; |
| |
| VkImageCreateInfo ici = {}; |
| ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| ici.pNext = nullptr; |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.arrayLayers = 1; |
| ici.extent = {64, 64, 1}; |
| ici.format = VK_FORMAT_R8G8B8A8_UNORM; |
| ici.mipLevels = 1; |
| ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| ici.samples = VK_SAMPLE_COUNT_1_BIT; |
| ici.tiling = VK_IMAGE_TILING_LINEAR; |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| |
| VkExternalMemoryImageCreateInfo emici = {}; |
| emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; |
| emici.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; |
| ici.pNext = &emici; |
| |
| m_errorMonitor->ExpectSuccess(); |
| vkCreateImage(dev, &ici, NULL, &img); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // attempt to fetch layout from unbound image |
| VkImageSubresource sub_rsrc = {}; |
| sub_rsrc.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| VkSubresourceLayout sub_layout = {}; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetImageSubresourceLayout-image-01895"); |
| vkGetImageSubresourceLayout(dev, img, &sub_rsrc, &sub_layout); |
| m_errorMonitor->VerifyFound(); |
| |
| // attempt to get memory reqs from unbound image |
| VkImageMemoryRequirementsInfo2 imri = {}; |
| imri.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; |
| imri.image = img; |
| VkMemoryRequirements2 mem_reqs = {}; |
| mem_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageMemoryRequirementsInfo2-image-01897"); |
| vkGetImageMemoryRequirements2(dev, &imri, &mem_reqs); |
| m_errorMonitor->VerifyFound(); |
| |
| reset_img(); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferMemoryAllocation) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer memory allocation."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkImage img = VK_NULL_HANDLE; |
| auto reset_img = [&img, dev]() { |
| if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL); |
| img = VK_NULL_HANDLE; |
| }; |
| VkDeviceMemory mem_handle = VK_NULL_HANDLE; |
| auto reset_mem = [&mem_handle, dev]() { |
| if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL); |
| mem_handle = VK_NULL_HANDLE; |
| }; |
| |
| PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps = |
| (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID"); |
| ASSERT_TRUE(pfn_GetAHBProps != nullptr); |
| |
| // AHB structs |
| AHardwareBuffer *ahb = nullptr; |
| AHardwareBuffer_Desc ahb_desc = {}; |
| VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {}; |
| ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; |
| VkAndroidHardwareBufferPropertiesANDROID ahb_props = {}; |
| ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; |
| ahb_props.pNext = &ahb_fmt_props; |
| VkImportAndroidHardwareBufferInfoANDROID iahbi = {}; |
| iahbi.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; |
| |
| // destroy and re-acquire an AHB, and fetch it's properties |
| auto recreate_ahb = [&ahb, &iahbi, &ahb_desc, &ahb_props, dev, pfn_GetAHBProps]() { |
| if (ahb) AHardwareBuffer_release(ahb); |
| ahb = nullptr; |
| AHardwareBuffer_allocate(&ahb_desc, &ahb); |
| if (ahb) { |
| pfn_GetAHBProps(dev, ahb, &ahb_props); |
| iahbi.buffer = ahb; |
| } |
| }; |
| |
| // Allocate an AHardwareBuffer |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.width = 64; |
| ahb_desc.height = 64; |
| ahb_desc.layers = 1; |
| recreate_ahb(); |
| |
| // Create an image w/ external format |
| VkExternalFormatANDROID efa = {}; |
| efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| efa.externalFormat = ahb_fmt_props.externalFormat; |
| |
| VkImageCreateInfo ici = {}; |
| ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| ici.pNext = &efa; |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.arrayLayers = 1; |
| ici.extent = {64, 64, 1}; |
| ici.format = VK_FORMAT_UNDEFINED; |
| ici.mipLevels = 1; |
| ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| ici.samples = VK_SAMPLE_COUNT_1_BIT; |
| ici.tiling = VK_IMAGE_TILING_OPTIMAL; |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| VkResult res = vkCreateImage(dev, &ici, NULL, &img); |
| ASSERT_VK_SUCCESS(res); |
| |
| VkMemoryAllocateInfo mai = {}; |
| mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mai.pNext = &iahbi; // Chained import struct |
| mai.allocationSize = ahb_props.allocationSize; |
| mai.memoryTypeIndex = 32; |
| // Set index to match one of the bits in ahb_props |
| for (int i = 0; i < 32; i++) { |
| if (ahb_props.memoryTypeBits & (1 << i)) { |
| mai.memoryTypeIndex = i; |
| break; |
| } |
| } |
| ASSERT_NE(32, mai.memoryTypeIndex); |
| |
| // Import w/ non-dedicated memory allocation |
| |
| // Import requires format AHB_FMT_BLOB and usage AHB_USAGE_GPU_DATA_BUFFER |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02384"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| |
| // Allocation size mismatch |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; |
| ahb_desc.height = 1; |
| recreate_ahb(); |
| mai.allocationSize = ahb_props.allocationSize + 1; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-allocationSize-02383"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| mai.allocationSize = ahb_props.allocationSize; |
| reset_mem(); |
| |
| // memoryTypeIndex mismatch |
| mai.memoryTypeIndex++; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| mai.memoryTypeIndex--; |
| reset_mem(); |
| |
| // Insert dedicated image memory allocation to mai chain |
| VkMemoryDedicatedAllocateInfo mdai = {}; |
| mdai.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; |
| mdai.image = img; |
| mdai.buffer = VK_NULL_HANDLE; |
| mdai.pNext = mai.pNext; |
| mai.pNext = &mdai; |
| |
| // Dedicated allocation with unmatched usage bits |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; |
| ahb_desc.height = 64; |
| recreate_ahb(); |
| mai.allocationSize = ahb_props.allocationSize; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02390"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| |
| // Dedicated allocation with incomplete mip chain |
| reset_img(); |
| ici.mipLevels = 2; |
| vkCreateImage(dev, &ici, NULL, &img); |
| mdai.image = img; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE; |
| recreate_ahb(); |
| |
| if (ahb) { |
| mai.allocationSize = ahb_props.allocationSize; |
| for (int i = 0; i < 32; i++) { |
| if (ahb_props.memoryTypeBits & (1 << i)) { |
| mai.memoryTypeIndex = i; |
| break; |
| } |
| } |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02389"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| } else { |
| // ERROR: AHardwareBuffer_allocate() with MIPMAP_COMPLETE fails. It returns -12, NO_MEMORY. |
| // The problem seems to happen in Pixel 2, not Pixel 3. |
| printf("%s AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE not supported, skipping tests\n", kSkipPrefix); |
| } |
| |
| // Dedicated allocation with mis-matched dimension |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.height = 32; |
| ahb_desc.width = 128; |
| recreate_ahb(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02388"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| |
| // Dedicated allocation with mis-matched VkFormat |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.height = 64; |
| ahb_desc.width = 64; |
| recreate_ahb(); |
| ici.mipLevels = 1; |
| ici.format = VK_FORMAT_B8G8R8A8_UNORM; |
| ici.pNext = NULL; |
| VkImage img2; |
| vkCreateImage(dev, &ici, NULL, &img2); |
| mdai.image = img2; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02387"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| vkDestroyImage(dev, img2, NULL); |
| mdai.image = img; |
| reset_mem(); |
| |
| // Missing required ahb usage |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884"); |
| recreate_ahb(); |
| m_errorMonitor->VerifyFound(); |
| |
| // Dedicated allocation with missing usage bits |
| // Setting up this test also triggers a slew of others |
| mai.allocationSize = ahb_props.allocationSize + 1; |
| mai.memoryTypeIndex = 0; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02390"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-allocationSize-02383"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02386"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| |
| // Non-import allocation - replace import struct in chain with export struct |
| VkExportMemoryAllocateInfo emai = {}; |
| emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; |
| emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; |
| mai.pNext = &emai; |
| emai.pNext = &mdai; // still dedicated |
| mdai.pNext = nullptr; |
| |
| // Export with allocation size non-zero |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| recreate_ahb(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-01874"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| reset_mem(); |
| |
| AHardwareBuffer_release(ahb); |
| reset_mem(); |
| reset_img(); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferCreateYCbCrSampler) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer YCbCr sampler creation."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE; |
| VkSamplerYcbcrConversionCreateInfo sycci = {}; |
| sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO; |
| sycci.format = VK_FORMAT_UNDEFINED; |
| sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904"); |
| vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv); |
| m_errorMonitor->VerifyFound(); |
| |
| VkExternalFormatANDROID efa = {}; |
| efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| efa.externalFormat = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; |
| sycci.format = VK_FORMAT_R8G8B8A8_UNORM; |
| sycci.pNext = &efa; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904"); |
| vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferPhysDevImageFormatProp2) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer GetPhysicalDeviceImageFormatProperties."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping test\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| if ((m_instance_api_version < VK_API_VERSION_1_1) && |
| !InstanceExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { |
| printf("%s %s extension not supported, skipping test\n", kSkipPrefix, |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| return; |
| } |
| |
| VkImageFormatProperties2 ifp = {}; |
| ifp.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; |
| VkPhysicalDeviceImageFormatInfo2 pdifi = {}; |
| pdifi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; |
| pdifi.format = VK_FORMAT_R8G8B8A8_UNORM; |
| pdifi.tiling = VK_IMAGE_TILING_OPTIMAL; |
| pdifi.type = VK_IMAGE_TYPE_2D; |
| pdifi.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| VkAndroidHardwareBufferUsageANDROID ahbu = {}; |
| ahbu.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; |
| ahbu.androidHardwareBufferUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ifp.pNext = &ahbu; |
| |
| // AHB_usage chained to input without a matching external image format struc chained to output |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868"); |
| vkGetPhysicalDeviceImageFormatProperties2(m_device->phy().handle(), &pdifi, &ifp); |
| m_errorMonitor->VerifyFound(); |
| |
| // output struct chained, but does not include VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID usage |
| VkPhysicalDeviceExternalImageFormatInfo pdeifi = {}; |
| pdeifi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; |
| pdeifi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; |
| pdifi.pNext = &pdeifi; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868"); |
| vkGetPhysicalDeviceImageFormatProperties2(m_device->phy().handle(), &pdifi, &ifp); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferCreateImageView) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer image view creation."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| // Allocate an AHB and fetch its properties |
| AHardwareBuffer *ahb = nullptr; |
| AHardwareBuffer_Desc ahb_desc = {}; |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.width = 64; |
| ahb_desc.height = 64; |
| ahb_desc.layers = 1; |
| AHardwareBuffer_allocate(&ahb_desc, &ahb); |
| |
| // Retrieve AHB properties to make it's external format 'known' |
| VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {}; |
| ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; |
| VkAndroidHardwareBufferPropertiesANDROID ahb_props = {}; |
| ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; |
| ahb_props.pNext = &ahb_fmt_props; |
| PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps = |
| (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID"); |
| ASSERT_TRUE(pfn_GetAHBProps != nullptr); |
| pfn_GetAHBProps(dev, ahb, &ahb_props); |
| AHardwareBuffer_release(ahb); |
| |
| // Give image an external format |
| VkExternalFormatANDROID efa = {}; |
| efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| efa.externalFormat = ahb_fmt_props.externalFormat; |
| |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; |
| ahb_desc.width = 64; |
| ahb_desc.height = 1; |
| ahb_desc.layers = 1; |
| AHardwareBuffer_allocate(&ahb_desc, &ahb); |
| |
| // Create another VkExternalFormatANDROID for test VUID-VkImageViewCreateInfo-image-02400 |
| VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props_Ycbcr = {}; |
| ahb_fmt_props_Ycbcr.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; |
| VkAndroidHardwareBufferPropertiesANDROID ahb_props_Ycbcr = {}; |
| ahb_props_Ycbcr.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; |
| ahb_props_Ycbcr.pNext = &ahb_fmt_props_Ycbcr; |
| pfn_GetAHBProps(dev, ahb, &ahb_props_Ycbcr); |
| AHardwareBuffer_release(ahb); |
| |
| VkExternalFormatANDROID efa_Ycbcr = {}; |
| efa_Ycbcr.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| efa_Ycbcr.externalFormat = ahb_fmt_props_Ycbcr.externalFormat; |
| |
| // Create the image |
| VkImage img = VK_NULL_HANDLE; |
| VkImageCreateInfo ici = {}; |
| ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| ici.pNext = &efa; |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.arrayLayers = 1; |
| ici.extent = {64, 64, 1}; |
| ici.format = VK_FORMAT_UNDEFINED; |
| ici.mipLevels = 1; |
| ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| ici.samples = VK_SAMPLE_COUNT_1_BIT; |
| ici.tiling = VK_IMAGE_TILING_OPTIMAL; |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| vkCreateImage(dev, &ici, NULL, &img); |
| |
| // Set up memory allocation |
| VkDeviceMemory img_mem = VK_NULL_HANDLE; |
| VkMemoryAllocateInfo mai = {}; |
| mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mai.allocationSize = 64 * 64 * 4; |
| mai.memoryTypeIndex = 0; |
| vkAllocateMemory(dev, &mai, NULL, &img_mem); |
| |
| // It shouldn't use vkGetImageMemoryRequirements for AndroidHardwareBuffer. |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "UNASSIGNED-CoreValidation-DrawState-InvalidImage"); |
| VkMemoryRequirements img_mem_reqs = {}; |
| vkGetImageMemoryRequirements(m_device->device(), img, &img_mem_reqs); |
| vkBindImageMemory(dev, img, img_mem, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Bind image to memory |
| vkDestroyImage(dev, img, NULL); |
| vkFreeMemory(dev, img_mem, NULL); |
| vkCreateImage(dev, &ici, NULL, &img); |
| vkAllocateMemory(dev, &mai, NULL, &img_mem); |
| vkBindImageMemory(dev, img, img_mem, 0); |
| |
| // Create a YCbCr conversion, with different external format, chain to view |
| VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE; |
| VkSamplerYcbcrConversionCreateInfo sycci = {}; |
| sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO; |
| sycci.pNext = &efa_Ycbcr; |
| sycci.format = VK_FORMAT_UNDEFINED; |
| sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv); |
| VkSamplerYcbcrConversionInfo syci = {}; |
| syci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO; |
| syci.conversion = ycbcr_conv; |
| |
| // Create a view |
| VkImageView image_view = VK_NULL_HANDLE; |
| VkImageViewCreateInfo ivci = {}; |
| ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
| ivci.pNext = &syci; |
| ivci.image = img; |
| ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| ivci.format = VK_FORMAT_UNDEFINED; |
| ivci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; |
| |
| auto reset_view = [&image_view, dev]() { |
| if (VK_NULL_HANDLE != image_view) vkDestroyImageView(dev, image_view, NULL); |
| image_view = VK_NULL_HANDLE; |
| }; |
| |
| // Up to this point, no errors expected |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Chained ycbcr conversion has different (external) format than image |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02400"); |
| // Also causes "unsupported format" - should be removed in future spec update |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-None-02273"); |
| vkCreateImageView(dev, &ivci, NULL, &image_view); |
| m_errorMonitor->VerifyFound(); |
| |
| reset_view(); |
| vkDestroySamplerYcbcrConversion(dev, ycbcr_conv, NULL); |
| sycci.pNext = &efa; |
| vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv); |
| syci.conversion = ycbcr_conv; |
| |
| // View component swizzle not IDENTITY |
| ivci.components.r = VK_COMPONENT_SWIZZLE_B; |
| ivci.components.b = VK_COMPONENT_SWIZZLE_R; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02401"); |
| // Also causes "unsupported format" - should be removed in future spec update |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-None-02273"); |
| vkCreateImageView(dev, &ivci, NULL, &image_view); |
| m_errorMonitor->VerifyFound(); |
| |
| reset_view(); |
| ivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; |
| ivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; |
| |
| // View with external format, when format is not UNDEFINED |
| ivci.format = VK_FORMAT_R5G6B5_UNORM_PACK16; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02399"); |
| // Also causes "view format different from image format" |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-01019"); |
| vkCreateImageView(dev, &ivci, NULL, &image_view); |
| m_errorMonitor->VerifyFound(); |
| |
| reset_view(); |
| vkDestroySamplerYcbcrConversion(dev, ycbcr_conv, NULL); |
| vkDestroyImageView(dev, image_view, NULL); |
| vkDestroyImage(dev, img, NULL); |
| vkFreeMemory(dev, img_mem, NULL); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferImportBuffer) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer import as buffer."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkDeviceMemory mem_handle = VK_NULL_HANDLE; |
| auto reset_mem = [&mem_handle, dev]() { |
| if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL); |
| mem_handle = VK_NULL_HANDLE; |
| }; |
| |
| PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps = |
| (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID"); |
| ASSERT_TRUE(pfn_GetAHBProps != nullptr); |
| |
| // AHB structs |
| AHardwareBuffer *ahb = nullptr; |
| AHardwareBuffer_Desc ahb_desc = {}; |
| VkAndroidHardwareBufferPropertiesANDROID ahb_props = {}; |
| ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; |
| VkImportAndroidHardwareBufferInfoANDROID iahbi = {}; |
| iahbi.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; |
| |
| // Allocate an AHardwareBuffer |
| ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB; |
| ahb_desc.usage = AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA; |
| ahb_desc.width = 512; |
| ahb_desc.height = 1; |
| ahb_desc.layers = 1; |
| AHardwareBuffer_allocate(&ahb_desc, &ahb); |
| m_errorMonitor->SetUnexpectedError("VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884"); |
| pfn_GetAHBProps(dev, ahb, &ahb_props); |
| iahbi.buffer = ahb; |
| |
| // Create export and import buffers |
| VkExternalMemoryBufferCreateInfo ext_buf_info = {}; |
| ext_buf_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR; |
| ext_buf_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; |
| |
| VkBufferCreateInfo bci = {}; |
| bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| bci.pNext = &ext_buf_info; |
| bci.size = ahb_props.allocationSize; |
| bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
| |
| VkBuffer buf = VK_NULL_HANDLE; |
| vkCreateBuffer(dev, &bci, NULL, &buf); |
| VkMemoryRequirements mem_reqs; |
| vkGetBufferMemoryRequirements(dev, buf, &mem_reqs); |
| |
| // Allocation info |
| VkMemoryAllocateInfo mai = vk_testing::DeviceMemory::get_resource_alloc_info(*m_device, mem_reqs, 0); |
| mai.pNext = &iahbi; // Chained import struct |
| VkPhysicalDeviceMemoryProperties memory_info; |
| vkGetPhysicalDeviceMemoryProperties(gpu(), &memory_info); |
| unsigned int i; |
| for (i = 0; i < memory_info.memoryTypeCount; i++) { |
| if ((ahb_props.memoryTypeBits & (1 << i))) { |
| mai.memoryTypeIndex = i; |
| break; |
| } |
| } |
| if (i >= memory_info.memoryTypeCount) { |
| printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); |
| AHardwareBuffer_release(ahb); |
| reset_mem(); |
| vkDestroyBuffer(dev, buf, NULL); |
| return; |
| } |
| |
| // Import as buffer requires format AHB_FMT_BLOB and usage AHB_USAGE_GPU_DATA_BUFFER |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881"); |
| // Also causes "non-dedicated allocation format/usage" error |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02384"); |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| m_errorMonitor->VerifyFound(); |
| |
| AHardwareBuffer_release(ahb); |
| reset_mem(); |
| vkDestroyBuffer(dev, buf, NULL); |
| } |
| |
| TEST_F(VkLayerTest, AndroidHardwareBufferExporttBuffer) { |
| TEST_DESCRIPTION("Verify AndroidHardwareBuffer export memory as AHB."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && |
| // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension |
| (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { |
| m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
| } else { |
| printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, |
| VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| VkDevice dev = m_device->device(); |
| |
| VkDeviceMemory mem_handle = VK_NULL_HANDLE; |
| |
| // Allocate device memory, no linked export struct indicating AHB handle type |
| VkMemoryAllocateInfo mai = {}; |
| mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mai.allocationSize = 65536; |
| mai.memoryTypeIndex = 0; |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| |
| PFN_vkGetMemoryAndroidHardwareBufferANDROID pfn_GetMemAHB = |
| (PFN_vkGetMemoryAndroidHardwareBufferANDROID)vkGetDeviceProcAddr(dev, "vkGetMemoryAndroidHardwareBufferANDROID"); |
| ASSERT_TRUE(pfn_GetMemAHB != nullptr); |
| |
| VkMemoryGetAndroidHardwareBufferInfoANDROID mgahbi = {}; |
| mgahbi.sType = VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; |
| mgahbi.memory = mem_handle; |
| AHardwareBuffer *ahb = nullptr; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882"); |
| pfn_GetMemAHB(dev, &mgahbi, &ahb); |
| m_errorMonitor->VerifyFound(); |
| |
| if (ahb) AHardwareBuffer_release(ahb); |
| ahb = nullptr; |
| if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL); |
| mem_handle = VK_NULL_HANDLE; |
| |
| // Add an export struct with AHB handle type to allocation info |
| VkExportMemoryAllocateInfo emai = {}; |
| emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; |
| emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; |
| mai.pNext = &emai; |
| |
| // Create an image, do not bind memory |
| VkImage img = VK_NULL_HANDLE; |
| VkImageCreateInfo ici = {}; |
| ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| ici.imageType = VK_IMAGE_TYPE_2D; |
| ici.arrayLayers = 1; |
| ici.extent = {128, 128, 1}; |
| ici.format = VK_FORMAT_R8G8B8A8_UNORM; |
| ici.mipLevels = 1; |
| ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| ici.samples = VK_SAMPLE_COUNT_1_BIT; |
| ici.tiling = VK_IMAGE_TILING_OPTIMAL; |
| ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| vkCreateImage(dev, &ici, NULL, &img); |
| ASSERT_TRUE(VK_NULL_HANDLE != img); |
| |
| // Add image to allocation chain as dedicated info, re-allocate |
| VkMemoryDedicatedAllocateInfo mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO}; |
| mdai.image = img; |
| emai.pNext = &mdai; |
| mai.allocationSize = 0; |
| vkAllocateMemory(dev, &mai, NULL, &mem_handle); |
| mgahbi.memory = mem_handle; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883"); |
| pfn_GetMemAHB(dev, &mgahbi, &ahb); |
| m_errorMonitor->VerifyFound(); |
| |
| if (ahb) AHardwareBuffer_release(ahb); |
| if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL); |
| vkDestroyImage(dev, img, NULL); |
| } |
| |
| #endif // VK_USE_PLATFORM_ANDROID_KHR |
| |
| TEST_F(VkLayerTest, ValidateStride) { |
| TEST_DESCRIPTION("Validate Stride."); |
| ASSERT_NO_FATAL_FAILURE(Init(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); |
| ASSERT_NO_FATAL_FAILURE(InitViewport()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkQueryPool query_pool; |
| VkQueryPoolCreateInfo query_pool_ci{}; |
| query_pool_ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
| query_pool_ci.queryType = VK_QUERY_TYPE_TIMESTAMP; |
| query_pool_ci.queryCount = 1; |
| vkCreateQueryPool(m_device->device(), &query_pool_ci, nullptr, &query_pool); |
| |
| m_commandBuffer->begin(); |
| vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1); |
| vkCmdWriteTimestamp(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); |
| m_commandBuffer->end(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| vkQueueWaitIdle(m_device->m_queue); |
| |
| char data_space; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetQueryPoolResults-flags-00814"); |
| vkGetQueryPoolResults(m_device->handle(), query_pool, 0, 1, sizeof(data_space), &data_space, 1, VK_QUERY_RESULT_WAIT_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetQueryPoolResults-flags-00815"); |
| vkGetQueryPoolResults(m_device->handle(), query_pool, 0, 1, sizeof(data_space), &data_space, 1, |
| (VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT)); |
| m_errorMonitor->VerifyFound(); |
| |
| char data_space4[4] = ""; |
| m_errorMonitor->ExpectSuccess(); |
| vkGetQueryPoolResults(m_device->handle(), query_pool, 0, 1, sizeof(data_space4), &data_space4, 4, VK_QUERY_RESULT_WAIT_BIT); |
| m_errorMonitor->VerifyNotFound(); |
| |
| char data_space8[8] = ""; |
| m_errorMonitor->ExpectSuccess(); |
| vkGetQueryPoolResults(m_device->handle(), query_pool, 0, 1, sizeof(data_space8), &data_space8, 8, |
| (VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT)); |
| m_errorMonitor->VerifyNotFound(); |
| |
| uint32_t qfi = 0; |
| VkBufferCreateInfo buff_create_info = {}; |
| buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buff_create_info.size = 128; |
| buff_create_info.usage = |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; |
| buff_create_info.queueFamilyIndexCount = 1; |
| buff_create_info.pQueueFamilyIndices = &qfi; |
| VkBufferObj buffer; |
| buffer.init(*m_device, buff_create_info); |
| |
| m_commandBuffer->reset(); |
| m_commandBuffer->begin(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdCopyQueryPoolResults-flags-00822"); |
| vkCmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool, 0, 1, buffer.handle(), 1, 1, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdCopyQueryPoolResults-flags-00823"); |
| vkCmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool, 0, 1, buffer.handle(), 1, 1, VK_QUERY_RESULT_64_BIT); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->ExpectSuccess(); |
| vkCmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool, 0, 1, buffer.handle(), 4, 4, 0); |
| m_errorMonitor->VerifyNotFound(); |
| |
| m_errorMonitor->ExpectSuccess(); |
| vkCmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool, 0, 1, buffer.handle(), 8, 8, VK_QUERY_RESULT_64_BIT); |
| m_errorMonitor->VerifyNotFound(); |
| |
| if (m_device->phy().features().multiDrawIndirect) { |
| CreatePipelineHelper helper(*this); |
| helper.InitInfo(); |
| helper.InitState(); |
| helper.CreateGraphicsPipeline(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, helper.pipeline_); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndirect-drawCount-00476"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndirect-drawCount-00488"); |
| vkCmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 100, 2); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->ExpectSuccess(); |
| vkCmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 2, 24); |
| m_errorMonitor->VerifyNotFound(); |
| |
| vkCmdBindIndexBuffer(m_commandBuffer->handle(), buffer.handle(), 0, VK_INDEX_TYPE_UINT16); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndexedIndirect-drawCount-00528"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndexedIndirect-drawCount-00540"); |
| vkCmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 100, 2); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->ExpectSuccess(); |
| vkCmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 2, 24); |
| m_errorMonitor->VerifyNotFound(); |
| |
| vkCmdEndRenderPass(m_commandBuffer->handle()); |
| m_commandBuffer->end(); |
| |
| } else { |
| printf("%s Test requires unsupported multiDrawIndirect feature. Skipped.\n", kSkipPrefix); |
| } |
| vkDestroyQueryPool(m_device->handle(), query_pool, NULL); |
| } |
| |
| TEST_F(VkLayerTest, WarningSwapchainCreateInfoPreTransform) { |
| TEST_DESCRIPTION("Print warning when preTransform doesn't match curretTransform"); |
| |
| if (!AddSurfaceInstanceExtension()) { |
| printf("%s surface extensions not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); |
| |
| if (!AddSwapchainDeviceExtension()) { |
| printf("%s swapchain extensions not supported, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-CoreValidation-SwapchainPreTransform"); |
| m_errorMonitor->SetUnexpectedError("VUID-VkSwapchainCreateInfoKHR-preTransform-01279"); |
| InitSwapchain(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| bool InitFrameworkForRayTracingTest(VkRenderFramework *renderFramework, std::vector<const char *> &instance_extension_names, |
| std::vector<const char *> &device_extension_names, void *user_data) { |
| const std::array<const char *, 1> required_instance_extensions = {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME}; |
| for (const char *required_instance_extension : required_instance_extensions) { |
| if (renderFramework->InstanceExtensionSupported(required_instance_extension)) { |
| instance_extension_names.push_back(required_instance_extension); |
| } else { |
| printf("%s %s instance extension not supported, skipping test\n", kSkipPrefix, required_instance_extension); |
| return false; |
| } |
| } |
| renderFramework->InitFramework(myDbgFunc, user_data); |
| |
| if (renderFramework->DeviceIsMockICD() || renderFramework->DeviceSimulation()) { |
| printf("%s Test not supported by MockICD, skipping tests\n", kSkipPrefix); |
| return false; |
| } |
| |
| const std::array<const char *, 2> required_device_extensions = { |
| VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, |
| VK_NV_RAY_TRACING_EXTENSION_NAME, |
| }; |
| for (const char *required_device_extension : required_device_extensions) { |
| if (renderFramework->DeviceExtensionSupported(renderFramework->gpu(), nullptr, required_device_extension)) { |
| device_extension_names.push_back(required_device_extension); |
| } else { |
| printf("%s %s device extension not supported, skipping test\n", kSkipPrefix, required_device_extension); |
| return false; |
| } |
| } |
| renderFramework->InitState(); |
| return true; |
| } |
| |
| TEST_F(VkLayerTest, ValidateGeometryNV) { |
| TEST_DESCRIPTION("Validate acceleration structure geometries."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| VkBufferObj vbo; |
| vbo.init(*m_device, 1024, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| VK_BUFFER_USAGE_RAY_TRACING_BIT_NV); |
| |
| VkBufferObj ibo; |
| ibo.init(*m_device, 1024, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| VK_BUFFER_USAGE_RAY_TRACING_BIT_NV); |
| |
| VkBufferObj tbo; |
| tbo.init(*m_device, 1024, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| VK_BUFFER_USAGE_RAY_TRACING_BIT_NV); |
| |
| VkBufferObj aabbbo; |
| aabbbo.init(*m_device, 1024, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| VK_BUFFER_USAGE_RAY_TRACING_BIT_NV); |
| |
| VkBufferCreateInfo unbound_buffer_ci = {}; |
| unbound_buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| unbound_buffer_ci.size = 1024; |
| unbound_buffer_ci.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_NV; |
| VkBufferObj unbound_buffer; |
| unbound_buffer.init_no_mem(*m_device, unbound_buffer_ci); |
| |
| const std::vector<float> vertices = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f}; |
| const std::vector<uint32_t> indicies = {0, 1, 2}; |
| const std::vector<float> aabbs = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; |
| const std::vector<float> transforms = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; |
| |
| uint8_t *mapped_vbo_buffer_data = (uint8_t *)vbo.memory().map(); |
| std::memcpy(mapped_vbo_buffer_data, (uint8_t *)vertices.data(), sizeof(float) * vertices.size()); |
| vbo.memory().unmap(); |
| |
| uint8_t *mapped_ibo_buffer_data = (uint8_t *)ibo.memory().map(); |
| std::memcpy(mapped_ibo_buffer_data, (uint8_t *)indicies.data(), sizeof(uint32_t) * indicies.size()); |
| ibo.memory().unmap(); |
| |
| uint8_t *mapped_tbo_buffer_data = (uint8_t *)tbo.memory().map(); |
| std::memcpy(mapped_tbo_buffer_data, (uint8_t *)transforms.data(), sizeof(float) * transforms.size()); |
| tbo.memory().unmap(); |
| |
| uint8_t *mapped_aabbbo_buffer_data = (uint8_t *)aabbbo.memory().map(); |
| std::memcpy(mapped_aabbbo_buffer_data, (uint8_t *)aabbs.data(), sizeof(float) * aabbs.size()); |
| aabbbo.memory().unmap(); |
| |
| VkGeometryNV valid_geometry_triangles = {}; |
| valid_geometry_triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV; |
| valid_geometry_triangles.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV; |
| valid_geometry_triangles.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; |
| valid_geometry_triangles.geometry.triangles.vertexData = vbo.handle(); |
| valid_geometry_triangles.geometry.triangles.vertexOffset = 0; |
| valid_geometry_triangles.geometry.triangles.vertexCount = 3; |
| valid_geometry_triangles.geometry.triangles.vertexStride = 12; |
| valid_geometry_triangles.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; |
| valid_geometry_triangles.geometry.triangles.indexData = ibo.handle(); |
| valid_geometry_triangles.geometry.triangles.indexOffset = 0; |
| valid_geometry_triangles.geometry.triangles.indexCount = 3; |
| valid_geometry_triangles.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; |
| valid_geometry_triangles.geometry.triangles.transformData = tbo.handle(); |
| valid_geometry_triangles.geometry.triangles.transformOffset = 0; |
| valid_geometry_triangles.geometry.aabbs = {}; |
| valid_geometry_triangles.geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; |
| |
| VkGeometryNV valid_geometry_aabbs = {}; |
| valid_geometry_aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV; |
| valid_geometry_aabbs.geometryType = VK_GEOMETRY_TYPE_AABBS_NV; |
| valid_geometry_aabbs.geometry.triangles = {}; |
| valid_geometry_aabbs.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; |
| valid_geometry_aabbs.geometry.aabbs = {}; |
| valid_geometry_aabbs.geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; |
| valid_geometry_aabbs.geometry.aabbs.aabbData = aabbbo.handle(); |
| valid_geometry_aabbs.geometry.aabbs.numAABBs = 1; |
| valid_geometry_aabbs.geometry.aabbs.offset = 0; |
| valid_geometry_aabbs.geometry.aabbs.stride = 24; |
| |
| PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV = reinterpret_cast<PFN_vkCreateAccelerationStructureNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkCreateAccelerationStructureNV")); |
| assert(vkCreateAccelerationStructureNV != nullptr); |
| |
| const auto GetCreateInfo = [](const VkGeometryNV &geometry) { |
| VkAccelerationStructureCreateInfoNV as_create_info = {}; |
| as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.instanceCount = 0; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| return as_create_info; |
| }; |
| |
| VkAccelerationStructureNV as; |
| |
| // Invalid vertex format. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexFormat = VK_FORMAT_R64_UINT; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-vertexFormat-02430"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex offset - not multiple of component size. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-vertexOffset-02429"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexOffset = 12 * 1024; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-vertexOffset-02428"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex buffer - no such buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexData = VkBuffer(123456789); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-vertexData-parameter"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex buffer - no memory bound. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexData = unbound_buffer.handle(); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-vertexOffset-02428"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Invalid index offset - not multiple of index size. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-indexOffset-02432"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexOffset = 2048; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-indexOffset-02431"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index count - must be 0 if type is VK_INDEX_TYPE_NONE_NV. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_NV; |
| geometry.geometry.triangles.indexData = VK_NULL_HANDLE; |
| geometry.geometry.triangles.indexCount = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-indexCount-02436"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index data - must be VK_NULL_HANDLE if type is VK_INDEX_TYPE_NONE_NV. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_NV; |
| geometry.geometry.triangles.indexData = ibo.handle(); |
| geometry.geometry.triangles.indexCount = 0; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-indexData-02434"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Invalid transform offset - not multiple of 16. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.transformOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-transformOffset-02438"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid transform offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.transformOffset = 2048; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryTrianglesNV-transformOffset-02437"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Invalid aabb offset - not multiple of 8. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.offset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryAABBNV-offset-02440"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid aabb offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.offset = 8 * 1024; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryAABBNV-offset-02439"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid aabb stride - not multiple of 8. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.stride = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkGeometryAABBNV-stride-02441"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| void GetSimpleGeometryForAccelerationStructureTests(const VkDeviceObj &device, VkBufferObj *vbo, VkBufferObj *ibo, |
| VkGeometryNV *geometry) { |
| vbo->init(device, 1024); |
| ibo->init(device, 1024); |
| |
| *geometry = {}; |
| geometry->sType = VK_STRUCTURE_TYPE_GEOMETRY_NV; |
| geometry->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV; |
| geometry->geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; |
| geometry->geometry.triangles.vertexData = vbo->handle(); |
| geometry->geometry.triangles.vertexOffset = 0; |
| geometry->geometry.triangles.vertexCount = 3; |
| geometry->geometry.triangles.vertexStride = 12; |
| geometry->geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; |
| geometry->geometry.triangles.indexData = ibo->handle(); |
| geometry->geometry.triangles.indexOffset = 0; |
| geometry->geometry.triangles.indexCount = 3; |
| geometry->geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; |
| geometry->geometry.triangles.transformData = VK_NULL_HANDLE; |
| geometry->geometry.triangles.transformOffset = 0; |
| geometry->geometry.aabbs = {}; |
| geometry->geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; |
| } |
| |
| TEST_F(VkLayerTest, ValidateCreateAccelerationStructureNV) { |
| TEST_DESCRIPTION("Validate acceleration structure creation."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV = reinterpret_cast<PFN_vkCreateAccelerationStructureNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkCreateAccelerationStructureNV")); |
| assert(vkCreateAccelerationStructureNV != nullptr); |
| |
| VkBufferObj vbo; |
| VkBufferObj ibo; |
| VkGeometryNV geometry; |
| GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = {}; |
| as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| |
| VkAccelerationStructureNV as = VK_NULL_HANDLE; |
| |
| // Top level can not have geometry |
| { |
| VkAccelerationStructureCreateInfoNV bad_top_level_create_info = as_create_info; |
| bad_top_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| bad_top_level_create_info.info.instanceCount = 0; |
| bad_top_level_create_info.info.geometryCount = 1; |
| bad_top_level_create_info.info.pGeometries = &geometry; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAccelerationStructureInfoNV-type-02425"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &bad_top_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Bot level can not have instances |
| { |
| VkAccelerationStructureCreateInfoNV bad_bot_level_create_info = as_create_info; |
| bad_bot_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_bot_level_create_info.info.instanceCount = 1; |
| bad_bot_level_create_info.info.geometryCount = 0; |
| bad_bot_level_create_info.info.pGeometries = nullptr; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAccelerationStructureInfoNV-type-02426"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &bad_bot_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not prefer both fast trace and fast build |
| { |
| VkAccelerationStructureCreateInfoNV bad_flags_level_create_info = as_create_info; |
| bad_flags_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_flags_level_create_info.info.instanceCount = 0; |
| bad_flags_level_create_info.info.geometryCount = 1; |
| bad_flags_level_create_info.info.pGeometries = &geometry; |
| bad_flags_level_create_info.info.flags = |
| VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAccelerationStructureInfoNV-flags-02592"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &bad_flags_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not have geometry or instance for compacting |
| { |
| VkAccelerationStructureCreateInfoNV bad_compacting_as_create_info = as_create_info; |
| bad_compacting_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_compacting_as_create_info.info.instanceCount = 0; |
| bad_compacting_as_create_info.info.geometryCount = 1; |
| bad_compacting_as_create_info.info.pGeometries = &geometry; |
| bad_compacting_as_create_info.info.flags = 0; |
| bad_compacting_as_create_info.compactedSize = 1024; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkAccelerationStructureCreateInfoNV-compactedSize-02421"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &bad_compacting_as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not mix different geometry types into single bottom level acceleration structure |
| { |
| VkGeometryNV aabb_geometry = {}; |
| aabb_geometry.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV; |
| aabb_geometry.geometryType = VK_GEOMETRY_TYPE_AABBS_NV; |
| aabb_geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; |
| aabb_geometry.geometry.aabbs = {}; |
| aabb_geometry.geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; |
| // Buffer contents do not matter for this test. |
| aabb_geometry.geometry.aabbs.aabbData = geometry.geometry.triangles.vertexData; |
| aabb_geometry.geometry.aabbs.numAABBs = 1; |
| aabb_geometry.geometry.aabbs.offset = 0; |
| aabb_geometry.geometry.aabbs.stride = 24; |
| |
| std::vector<VkGeometryNV> geometries = {geometry, aabb_geometry}; |
| |
| VkAccelerationStructureCreateInfoNV mix_geometry_types_as_create_info = as_create_info; |
| mix_geometry_types_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| mix_geometry_types_as_create_info.info.instanceCount = 0; |
| mix_geometry_types_as_create_info.info.geometryCount = static_cast<uint32_t>(geometries.size()); |
| mix_geometry_types_as_create_info.info.pGeometries = geometries.data(); |
| mix_geometry_types_as_create_info.info.flags = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "UNASSIGNED-VkAccelerationStructureInfoNV-pGeometries-XXXX"); |
| vkCreateAccelerationStructureNV(m_device->handle(), &mix_geometry_types_as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, ValidateBindAccelerationStructureNV) { |
| TEST_DESCRIPTION("Validate acceleration structure binding."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV = |
| reinterpret_cast<PFN_vkBindAccelerationStructureMemoryNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkBindAccelerationStructureMemoryNV")); |
| assert(vkBindAccelerationStructureMemoryNV != nullptr); |
| |
| VkBufferObj vbo; |
| VkBufferObj ibo; |
| VkGeometryNV geometry; |
| GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = {}; |
| as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| as_create_info.info.instanceCount = 0; |
| |
| VkAccelerationStructureObj as(*m_device, as_create_info, false); |
| m_errorMonitor->VerifyNotFound(); |
| |
| VkMemoryRequirements as_memory_requirements = as.memory_requirements().memoryRequirements; |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info = {}; |
| as_bind_info.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV; |
| as_bind_info.accelerationStructure = as.handle(); |
| |
| VkMemoryAllocateInfo as_memory_alloc = {}; |
| as_memory_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| as_memory_alloc.allocationSize = as_memory_requirements.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(as_memory_requirements.memoryTypeBits, &as_memory_alloc, 0)); |
| |
| // Can not bind already freed memory |
| { |
| VkDeviceMemory as_memory_freed = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_freed)); |
| vkFreeMemory(device(), as_memory_freed, NULL); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_freed = as_bind_info; |
| as_bind_info_freed.memory = as_memory_freed; |
| as_bind_info_freed.memoryOffset = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-memory-parameter"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_freed); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not bind with bad alignment |
| if (as_memory_requirements.alignment > 1) { |
| VkMemoryAllocateInfo as_memory_alloc_bad_alignment = as_memory_alloc; |
| as_memory_alloc_bad_alignment.allocationSize += 1; |
| |
| VkDeviceMemory as_memory_bad_alignment = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc_bad_alignment, NULL, &as_memory_bad_alignment)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_alignment = as_bind_info; |
| as_bind_info_bad_alignment.memory = as_memory_bad_alignment; |
| as_bind_info_bad_alignment.memoryOffset = 1; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02594"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_alignment); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), as_memory_bad_alignment, NULL); |
| } |
| |
| // Can not bind with offset outside the allocation |
| { |
| VkDeviceMemory as_memory_bad_offset = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_bad_offset)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_offset = as_bind_info; |
| as_bind_info_bad_offset.memory = as_memory_bad_offset; |
| as_bind_info_bad_offset.memoryOffset = |
| (as_memory_alloc.allocationSize + as_memory_requirements.alignment) & ~(as_memory_requirements.alignment - 1); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02451"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), as_memory_bad_offset, NULL); |
| } |
| |
| // Can not bind with offset that doesn't leave enough size |
| { |
| VkDeviceSize offset = (as_memory_requirements.size - 1) & ~(as_memory_requirements.alignment - 1); |
| if (offset > 0 && (as_memory_requirements.size < (as_memory_alloc.allocationSize - as_memory_requirements.alignment))) { |
| VkDeviceMemory as_memory_bad_offset = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_bad_offset)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_offset = as_bind_info; |
| as_bind_info_bad_offset.memory = as_memory_bad_offset; |
| as_bind_info_bad_offset.memoryOffset = offset; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-size-02595"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), as_memory_bad_offset, NULL); |
| } |
| } |
| |
| // Can not bind with memory that has unsupported memory type |
| { |
| VkPhysicalDeviceMemoryProperties memory_properties = {}; |
| vkGetPhysicalDeviceMemoryProperties(m_device->phy().handle(), &memory_properties); |
| |
| uint32_t supported_memory_type_bits = as_memory_requirements.memoryTypeBits; |
| uint32_t unsupported_mem_type_bits = ((1 << memory_properties.memoryTypeCount) - 1) & ~supported_memory_type_bits; |
| if (unsupported_mem_type_bits != 0) { |
| VkMemoryAllocateInfo as_memory_alloc_bad_type = as_memory_alloc; |
| ASSERT_TRUE(m_device->phy().set_memory_type(unsupported_mem_type_bits, &as_memory_alloc_bad_type, 0)); |
| |
| VkDeviceMemory as_memory_bad_type = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc_bad_type, NULL, &as_memory_bad_type)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_type = as_bind_info; |
| as_bind_info_bad_type.memory = as_memory_bad_type; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-memory-02593"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_type); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), as_memory_bad_type, NULL); |
| } |
| } |
| |
| // Can not bind memory twice |
| { |
| VkAccelerationStructureObj as_twice(*m_device, as_create_info, false); |
| |
| VkDeviceMemory as_memory_twice_1 = VK_NULL_HANDLE; |
| VkDeviceMemory as_memory_twice_2 = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_twice_1)); |
| ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_twice_2)); |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_twice_1 = as_bind_info; |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_twice_2 = as_bind_info; |
| as_bind_info_twice_1.accelerationStructure = as_twice.handle(); |
| as_bind_info_twice_2.accelerationStructure = as_twice.handle(); |
| as_bind_info_twice_1.memory = as_memory_twice_1; |
| as_bind_info_twice_2.memory = as_memory_twice_2; |
| |
| ASSERT_VK_SUCCESS(vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_twice_1)); |
| m_errorMonitor->VerifyNotFound(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-02450"); |
| (void)vkBindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_twice_2); |
| m_errorMonitor->VerifyFound(); |
| |
| vkFreeMemory(device(), as_memory_twice_1, NULL); |
| vkFreeMemory(device(), as_memory_twice_2, NULL); |
| } |
| } |
| |
| TEST_F(VkLayerTest, ValidateCmdBuildAccelerationStructureNV) { |
| TEST_DESCRIPTION("Validate acceleration structure building."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV = |
| reinterpret_cast<PFN_vkCmdBuildAccelerationStructureNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkCmdBuildAccelerationStructureNV")); |
| assert(vkCmdBuildAccelerationStructureNV != nullptr); |
| |
| VkBufferObj vbo; |
| VkBufferObj ibo; |
| VkGeometryNV geometry; |
| GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = {}; |
| bot_level_as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| bot_level_as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| VkAccelerationStructureObj bot_level_as(*m_device, bot_level_as_create_info); |
| m_errorMonitor->VerifyNotFound(); |
| |
| VkBufferObj bot_level_as_scratch; |
| bot_level_as.create_scratch_buffer(*m_device, &bot_level_as_scratch); |
| |
| // Command buffer must be in recording state |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-recording"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->begin(); |
| |
| // Incompatible type |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_type = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_type.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| as_build_info_with_incompatible_type.instanceCount = 1; |
| as_build_info_with_incompatible_type.geometryCount = 0; |
| |
| // This is duplicated since it triggers one error for different types and one error for lower instance count - the |
| // build info is incompatible but still needs to be valid to get past the stateless checks. |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &as_build_info_with_incompatible_type, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Incompatible flags |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_flags = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_flags.flags = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &as_build_info_with_incompatible_flags, VK_NULL_HANDLE, 0, |
| VK_FALSE, bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Incompatible build size |
| VkGeometryNV geometry_with_more_vertices = geometry; |
| geometry_with_more_vertices.geometry.triangles.vertexCount += 1; |
| |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_geometry = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_geometry.pGeometries = &geometry_with_more_vertices; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &as_build_info_with_incompatible_geometry, VK_NULL_HANDLE, 0, |
| VK_FALSE, bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Scratch buffer too small |
| VkBufferCreateInfo too_small_scratch_buffer_info = {}; |
| too_small_scratch_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| too_small_scratch_buffer_info.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_NV; |
| too_small_scratch_buffer_info.size = 1; |
| VkBufferObj too_small_scratch_buffer(*m_device, too_small_scratch_buffer_info); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-update-02491"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as.handle(), VK_NULL_HANDLE, too_small_scratch_buffer.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Scratch buffer with offset too small |
| VkDeviceSize scratch_buffer_offset = 5; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-update-02491"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), scratch_buffer_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| // Src must have been built before |
| VkAccelerationStructureObj bot_level_as_updated(*m_device, bot_level_as_create_info); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-update-02489"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_TRUE, |
| bot_level_as_updated.handle(), bot_level_as.handle(), bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Src must have been built before with the VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV flag |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as.handle(), VK_NULL_HANDLE, bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyNotFound(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBuildAccelerationStructureNV-update-02489"); |
| vkCmdBuildAccelerationStructureNV(m_commandBuffer->handle(), &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_TRUE, |
| bot_level_as_updated.handle(), bot_level_as.handle(), bot_level_as_scratch.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, ValidateGetAccelerationStructureHandleNV) { |
| TEST_DESCRIPTION("Validate acceleration structure handle querying."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV = |
| reinterpret_cast<PFN_vkGetAccelerationStructureHandleNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkGetAccelerationStructureHandleNV")); |
| assert(vkGetAccelerationStructureHandleNV != nullptr); |
| |
| VkBufferObj vbo; |
| VkBufferObj ibo; |
| VkGeometryNV geometry; |
| GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = {}; |
| bot_level_as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| bot_level_as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| // Not enough space for the handle |
| { |
| VkAccelerationStructureObj bot_level_as(*m_device, bot_level_as_create_info); |
| m_errorMonitor->VerifyNotFound(); |
| |
| uint64_t handle = 0; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkGetAccelerationStructureHandleNV-dataSize-02240"); |
| vkGetAccelerationStructureHandleNV(m_device->handle(), bot_level_as.handle(), sizeof(uint8_t), &handle); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // No memory bound to acceleration structure |
| { |
| VkAccelerationStructureObj bot_level_as(*m_device, bot_level_as_create_info, /*init_memory=*/false); |
| m_errorMonitor->VerifyNotFound(); |
| |
| uint64_t handle = 0; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "UNASSIGNED-vkGetAccelerationStructureHandleNV-accelerationStructure-XXXX"); |
| vkGetAccelerationStructureHandleNV(m_device->handle(), bot_level_as.handle(), sizeof(uint64_t), &handle); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, ValidateCmdCopyAccelerationStructureNV) { |
| TEST_DESCRIPTION("Validate acceleration structure copying."); |
| if (!InitFrameworkForRayTracingTest(this, m_instance_extension_names, m_device_extension_names, m_errorMonitor)) { |
| return; |
| } |
| |
| PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV = reinterpret_cast<PFN_vkCmdCopyAccelerationStructureNV>( |
| vkGetDeviceProcAddr(m_device->handle(), "vkCmdCopyAccelerationStructureNV")); |
| assert(vkCmdCopyAccelerationStructureNV != nullptr); |
| |
| VkBufferObj vbo; |
| VkBufferObj ibo; |
| VkGeometryNV geometry; |
| GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = {}; |
| as_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV; |
| as_create_info.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV; |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.instanceCount = 0; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| |
| VkAccelerationStructureObj src_as(*m_device, as_create_info); |
| VkAccelerationStructureObj dst_as(*m_device, as_create_info); |
| VkAccelerationStructureObj dst_as_without_mem(*m_device, as_create_info, false); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Command buffer must be in recording state |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-recording"); |
| vkCmdCopyAccelerationStructureNV(m_commandBuffer->handle(), dst_as.handle(), src_as.handle(), |
| VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->begin(); |
| |
| // Src must have been created with allow compaction flag |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdCopyAccelerationStructureNV-src-02497"); |
| vkCmdCopyAccelerationStructureNV(m_commandBuffer->handle(), dst_as.handle(), src_as.handle(), |
| VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| // Dst must have been bound with memory |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, |
| "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkAccelerationStructureNV"); |
| vkCmdCopyAccelerationStructureNV(m_commandBuffer->handle(), dst_as_without_mem.handle(), src_as.handle(), |
| VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| } |