From b2901c9ec5b6e131623170b3ca3b9bd79bb25545 Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Thu, 17 Nov 2022 00:39:05 +0000 Subject: Adding new Vulkan metrics to GPU Stats Following fields are added into GpuStatsAppInfo for tracking: bool createdGlesContext = false; bool createdVulkanDevice = false; bool createdVulkanSwapchain = false; uint32_t vulkanApiVersion = 0; uint64_t vulkanDeviceFeaturesEnabled = 0; std::vector vulkanInstanceExtensions = {}; std::vector vulkanDeviceExtensions = {}; Extensions are tracked as 32-bit hashes. setTargetStatsArray GPU service function added to provide an array of stat values, used for reporting list of extensions. Bug: b/244286661 Test: adb shell dumpsys gpu Test: atest GpuStatsTest Change-Id: I4ae4e3b687cd6274a9b4127a336dd0f91f5f9e39 --- vulkan/libvulkan/driver.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 766451824a..15b637cf17 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -1178,6 +1178,27 @@ VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, return VK_ERROR_INCOMPATIBLE_DRIVER; } + // TODO(b/259516419) avoid getting stats from hwui + // const bool reportStats = (pCreateInfo->pApplicationInfo == nullptr ) + // || (strcmp("android framework", + // pCreateInfo->pApplicationInfo->pEngineName) != 0); + const bool reportStats = true; + if (reportStats) { + // Set stats for Vulkan api version requested with application info + if (pCreateInfo->pApplicationInfo) { + const uint32_t vulkanApiVersion = + pCreateInfo->pApplicationInfo->apiVersion; + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::CREATED_VULKAN_API_VERSION, + vulkanApiVersion); + } + + // Update stats for the extensions requested + android::GraphicsEnv::getInstance().setVulkanInstanceExtensions( + pCreateInfo->enabledExtensionCount, + pCreateInfo->ppEnabledExtensionNames); + } + *pInstance = instance; return VK_SUCCESS; @@ -1280,6 +1301,65 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, *pDevice = dev; + // TODO(b/259516419) avoid getting stats from hwui + const bool reportStats = true; + if (reportStats) { + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::CREATED_VULKAN_DEVICE); + + // Set stats for creating a Vulkan device and report features in use + const VkPhysicalDeviceFeatures* pEnabledFeatures = + pCreateInfo->pEnabledFeatures; + if (!pEnabledFeatures) { + // Use features from the chained VkPhysicalDeviceFeatures2 + // structure, if given + const VkPhysicalDeviceFeatures2* features2 = + reinterpret_cast( + pCreateInfo->pNext); + while (features2 && + features2->sType != + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) { + features2 = reinterpret_cast( + features2->pNext); + } + if (features2) { + pEnabledFeatures = &features2->features; + } + } + const VkBool32* pFeatures = + reinterpret_cast(pEnabledFeatures); + if (pFeatures) { + // VkPhysicalDeviceFeatures consists of VkBool32 values, go over all + // of them using pointer arithmetic here and save the features in a + // 64-bit bitfield + static_assert( + (sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32)) <= 64, + "VkPhysicalDeviceFeatures has too many elements for bitfield " + "packing"); + static_assert( + (sizeof(VkPhysicalDeviceFeatures) % sizeof(VkBool32)) == 0, + "VkPhysicalDeviceFeatures has invalid size for bitfield " + "packing"); + const int numFeatures = + sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32); + + uint64_t enableFeatureBits = 0; + for (int i = 0; i < numFeatures; i++) { + if (pFeatures[i] != VK_FALSE) { + enableFeatureBits |= (uint64_t(1) << i); + } + } + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::VULKAN_DEVICE_FEATURES_ENABLED, + enableFeatureBits); + } + + // Update stats for the extensions requested + android::GraphicsEnv::getInstance().setVulkanDeviceExtensions( + pCreateInfo->enabledExtensionCount, + pCreateInfo->ppEnabledExtensionNames); + } + return VK_SUCCESS; } -- cgit v1.2.3-59-g8ed1b From 08c7bb1fdb33d6ad34ba1b2de3ac0579750456fe Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 9 Dec 2022 08:10:18 +1300 Subject: libvulkan: Implement EXT_swapchain_maintenance1 The loader now implements EXT_swapchain_maintenance1 and EXT_surface_maintenance1, which fix assorted issues with the original swapchain extension. Our implementation of EXT_swapchain_maintenance1 is conditional on the underlying driver having support for importing sync fds as external fences (which requires Vulkan 1.1 + support for VK_KHR_external_fence_fd). Bug: b/255376900 Change-Id: I72ce770a7296e4e97cccf13bad420aa5a1001a6a --- vulkan/libvulkan/driver.cpp | 56 +++- vulkan/libvulkan/driver_gen.cpp | 20 ++ vulkan/libvulkan/driver_gen.h | 4 + vulkan/libvulkan/swapchain.cpp | 624 ++++++++++++++++++++++++++----------- vulkan/libvulkan/swapchain.h | 1 + vulkan/scripts/driver_generator.py | 6 + 6 files changed, 528 insertions(+), 183 deletions(-) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 9ed992b230..b7e19d4296 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -636,6 +636,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::GOOGLE_surfaceless_query: + case ProcHook::EXT_surface_maintenance1: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -657,9 +658,11 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_shared_presentable_image: case ProcHook::KHR_swapchain: case ProcHook::EXT_hdr_metadata: + case ProcHook::EXT_swapchain_maintenance1: case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: case ProcHook::EXTENSION_CORE_1_2: @@ -690,16 +693,22 @@ void CreateInfoWrapper::FilterExtension(const char* name) { ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::KHR_incremental_present: - case ProcHook::GOOGLE_display_timing: case ProcHook::KHR_shared_presentable_image: + case ProcHook::GOOGLE_display_timing: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; + case ProcHook::EXT_swapchain_maintenance1: + // map VK_KHR_swapchain_maintenance1 to KHR_external_fence_fd + name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; + ext_bit = ProcHook::KHR_external_fence_fd; + break; case ProcHook::EXT_hdr_metadata: case ProcHook::KHR_bind_memory2: hook_extensions_.set(ext_bit); break; case ProcHook::ANDROID_external_memory_android_hardware_buffer: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_UNKNOWN: // Extensions we don't need to do anything about at this level break; @@ -715,6 +724,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: + case ProcHook::EXT_surface_maintenance1: case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: @@ -751,6 +761,8 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); + if (ext_bit == ProcHook::KHR_external_fence_fd) + hook_extensions_.set(ProcHook::EXT_swapchain_maintenance1); hal_extensions_.set(ext_bit); } @@ -940,6 +952,9 @@ VkResult EnumerateInstanceExtensionProperties( VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); + loader_extensions.push_back({ + VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, @@ -1072,6 +1087,33 @@ VkResult GetAndroidNativeBufferSpecVersion9Support( return result; } +bool CanSupportSwapchainMaintenance1Extension(VkPhysicalDevice physicalDevice) { + const auto& driver = GetData(physicalDevice).driver; + if (!driver.GetPhysicalDeviceExternalFenceProperties) + return false; + + // Requires support for external fences imported from sync fds. + // This is _almost_ universal on Android, but may be missing on + // some extremely old drivers, or on strange implementations like + // cuttlefish. + VkPhysicalDeviceExternalFenceInfo fenceInfo = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + nullptr, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT + }; + VkExternalFenceProperties fenceProperties = { + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + nullptr, + 0, 0, 0 + }; + + GetPhysicalDeviceExternalFenceProperties(physicalDevice, &fenceInfo, &fenceProperties); + if (fenceProperties.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT) + return true; + + return false; +} + VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, @@ -1149,6 +1191,12 @@ VkResult EnumerateDeviceExtensionProperties( VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION}); } + if (CanSupportSwapchainMaintenance1Extension(physicalDevice)) { + loader_extensions.push_back({ + VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION}); + } + // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( @@ -1644,6 +1692,12 @@ void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, imageCompressionControlSwapchainInChain = true; } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { + auto smf = reinterpret_cast( + pFeats); + smf->swapchainMaintenance1 = true; + } break; + default: break; } diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index de98aa7e61..798af5c6a6 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -162,6 +162,15 @@ VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 } } +VKAPI_ATTR VkResult checkedReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + if (GetData(device).hook_extensions[ProcHook::EXT_swapchain_maintenance1]) { + return ReleaseSwapchainImagesEXT(device, pReleaseInfo); + } else { + Logger(device).Err(device, "VK_EXT_swapchain_maintenance1 not enabled. vkReleaseSwapchainImagesEXT not executed."); + return VK_SUCCESS; + } +} + // clang-format on const ProcHook g_proc_hooks[] = { @@ -544,6 +553,13 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast(QueueSubmit), nullptr, }, + { + "vkReleaseSwapchainImagesEXT", + ProcHook::DEVICE, + ProcHook::EXT_swapchain_maintenance1, + reinterpret_cast(ReleaseSwapchainImagesEXT), + reinterpret_cast(checkedReleaseSwapchainImagesEXT), + }, { "vkSetHdrMetadataEXT", ProcHook::DEVICE, @@ -580,6 +596,8 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; + if (strcmp(name, "VK_EXT_swapchain_maintenance1") == 0) return ProcHook::EXT_swapchain_maintenance1; + if (strcmp(name, "VK_EXT_surface_maintenance1") == 0) return ProcHook::EXT_surface_maintenance1; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2; @@ -587,6 +605,7 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities; if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities; if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities; + if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } @@ -666,6 +685,7 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); + INIT_PROC_EXT(KHR_external_fence_fd, true, dev, ImportFenceFdKHR); INIT_PROC(false, dev, BindImageMemory2); INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 2f60086a27..31ba04ba1f 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -49,6 +49,8 @@ struct ProcHook { KHR_surface, KHR_surface_protected_capabilities, KHR_swapchain, + EXT_swapchain_maintenance1, + EXT_surface_maintenance1, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, KHR_get_physical_device_properties2, @@ -56,6 +58,7 @@ struct ProcHook { KHR_external_memory_capabilities, KHR_external_semaphore_capabilities, KHR_external_fence_capabilities, + KHR_external_fence_fd, EXTENSION_CORE_1_0, EXTENSION_CORE_1_1, @@ -118,6 +121,7 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; + PFN_vkImportFenceFdKHR ImportFenceFdKHR; PFN_vkBindImageMemory2 BindImageMemory2; PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 1bf7abb758..0dac6ad1aa 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -291,6 +291,9 @@ struct Swapchain { release_fence(-1), dequeued(false) {} VkImage image; + // If the image is bound to memory, an sp to the underlying gralloc buffer. + // Otherwise, nullptr; the image will be bound to memory as part of + // AcquireNextImage. android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is @@ -652,100 +655,40 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); - int err; - int width, height; - int transform_hint; - int max_buffer_count; - if (surface == VK_NULL_HANDLE) { - const InstanceData& instance_data = GetData(pdev); - ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; - bool surfaceless_enabled = - instance_data.hook_extensions.test(surfaceless); - if (!surfaceless_enabled) { - // It is an error to pass a surface==VK_NULL_HANDLE unless the - // VK_GOOGLE_surfaceless_query extension is enabled - return VK_ERROR_SURFACE_LOST_KHR; - } - // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this - // extension for this function is for - // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following - // four values cannot be known without a surface. Default values will - // be supplied anyway, but cannot be relied upon. - width = 0xFFFFFFFF; - height = 0xFFFFFFFF; - transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - capabilities->minImageCount = 0xFFFFFFFF; - capabilities->maxImageCount = 0xFFFFFFFF; - } else { - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + // Implement in terms of GetPhysicalDeviceSurfaceCapabilities2KHR - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, - &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, - &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - capabilities->minImageCount = std::min(max_buffer_count, 3); - capabilities->maxImageCount = static_cast(max_buffer_count); - } - - capabilities->currentExtent = - VkExtent2D{static_cast(width), static_cast(height)}; + VkPhysicalDeviceSurfaceInfo2KHR info2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, + nullptr, + surface + }; - // TODO(http://b/134182502): Figure out what the max extent should be. - capabilities->minImageExtent = VkExtent2D{1, 1}; - capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + VkSurfaceCapabilities2KHR caps2 = { + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, + nullptr, + {}, + }; - if (capabilities->maxImageExtent.height < - capabilities->currentExtent.height) { - capabilities->maxImageExtent.height = - capabilities->currentExtent.height; - } + VkResult result = GetPhysicalDeviceSurfaceCapabilities2KHR(pdev, &info2, &caps2); + *capabilities = caps2.surfaceCapabilities; + return result; +} - if (capabilities->maxImageExtent.width < - capabilities->currentExtent.width) { - capabilities->maxImageExtent.width = capabilities->currentExtent.width; +// Does the call-twice and VK_INCOMPLETE handling for querying lists +// of things, where we already have the full set built in a vector. +template +VkResult CopyWithIncomplete(std::vector const& things, + T* callerPtr, uint32_t* callerCount) { + VkResult result = VK_SUCCESS; + if (callerPtr) { + if (things.size() > *callerCount) + result = VK_INCOMPLETE; + *callerCount = std::min(uint32_t(things.size()), *callerCount); + std::copy(things.begin(), things.begin() + *callerCount, callerPtr); + } else { + *callerCount = things.size(); } - - capabilities->maxImageArrayLayers = 1; - - capabilities->supportedTransforms = kSupportedTransforms; - capabilities->currentTransform = - TranslateNativeToVulkanTransform(transform_hint); - - // On Android, window composition is a WindowManager property, not something - // associated with the bufferqueue. It can't be changed from here. - capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - - capabilities->supportedUsageFlags = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - - return VK_SUCCESS; + return result; } VKAPI_ATTR @@ -862,21 +805,7 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // Android users. This includes the ANGLE team (a layered implementation of // OpenGL-ES). - VkResult result = VK_SUCCESS; - if (formats) { - uint32_t transfer_count = all_formats.size(); - if (transfer_count > *count) { - transfer_count = *count; - result = VK_INCOMPLETE; - } - std::copy(all_formats.begin(), all_formats.begin() + transfer_count, - formats); - *count = transfer_count; - } else { - *count = all_formats.size(); - } - - return result; + return CopyWithIncomplete(all_formats, formats, count); } VKAPI_ATTR @@ -886,19 +815,134 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { ATRACE_CALL(); - VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, pSurfaceInfo->surface, - &pSurfaceCapabilities->surfaceCapabilities); + auto surface = pSurfaceInfo->surface; + auto capabilities = &pSurfaceCapabilities->surfaceCapabilities; + + VkSurfacePresentModeEXT const *pPresentMode = nullptr; + for (auto pNext = reinterpret_cast(pSurfaceInfo->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + switch (pNext->sType) { + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: + pPresentMode = reinterpret_cast(pNext); + break; + + default: + break; + } + } - VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities; - while (caps->pNext) { - caps = reinterpret_cast(caps->pNext); + int err; + int width, height; + int transform_hint; + int max_buffer_count; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(physicalDevice); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 0xFFFFFFFF; + height = 0xFFFFFFFF; + transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + capabilities->minImageCount = 0xFFFFFFFF; + capabilities->maxImageCount = 0xFFFFFFFF; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - switch (caps->sType) { + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + if (pPresentMode && IsSharedPresentMode(pPresentMode->presentMode)) { + capabilities->minImageCount = 1; + capabilities->maxImageCount = 1; + } else if (pPresentMode && pPresentMode->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + // TODO: use undequeued buffer requirement for more precise bound + capabilities->minImageCount = std::min(max_buffer_count, 4); + capabilities->maxImageCount = static_cast(max_buffer_count); + } else { + // TODO: if we're able to, provide better bounds on the number of buffers + // for other modes as well. + capabilities->minImageCount = std::min(max_buffer_count, 3); + capabilities->maxImageCount = static_cast(max_buffer_count); + } + } + + capabilities->currentExtent = + VkExtent2D{static_cast(width), static_cast(height)}; + + // TODO(http://b/134182502): Figure out what the max extent should be. + capabilities->minImageExtent = VkExtent2D{1, 1}; + capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + + if (capabilities->maxImageExtent.height < + capabilities->currentExtent.height) { + capabilities->maxImageExtent.height = + capabilities->currentExtent.height; + } + + if (capabilities->maxImageExtent.width < + capabilities->currentExtent.width) { + capabilities->maxImageExtent.width = capabilities->currentExtent.width; + } + + capabilities->maxImageArrayLayers = 1; + + capabilities->supportedTransforms = kSupportedTransforms; + capabilities->currentTransform = + TranslateNativeToVulkanTransform(transform_hint); + + // On Android, window composition is a WindowManager property, not something + // associated with the bufferqueue. It can't be changed from here. + capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + + capabilities->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + for (auto pNext = reinterpret_cast(pSurfaceCapabilities->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + + switch (pNext->sType) { case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: { VkSharedPresentSurfaceCapabilitiesKHR* shared_caps = - reinterpret_cast( - caps); + reinterpret_cast(pNext); // Claim same set of usage flags are supported for // shared present modes as for other modes. shared_caps->sharedPresentSupportedUsageFlags = @@ -908,17 +952,64 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { VkSurfaceProtectedCapabilitiesKHR* protected_caps = - reinterpret_cast(caps); + reinterpret_cast(pNext); protected_caps->supportsProtected = VK_TRUE; } break; + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { + VkSurfacePresentScalingCapabilitiesEXT* scaling_caps = + reinterpret_cast(pNext); + // By default, Android stretches the buffer to fit the window, + // without preserving aspect ratio. Other modes are technically possible + // but consult with CoGS team before exposing them here! + scaling_caps->supportedPresentScaling = VK_PRESENT_SCALING_STRETCH_BIT_EXT; + + // Since we always scale, we don't support any gravity. + scaling_caps->supportedPresentGravityX = 0; + scaling_caps->supportedPresentGravityY = 0; + + // Scaled image limits are just the basic image limits + scaling_caps->minScaledImageExtent = capabilities->minImageExtent; + scaling_caps->maxScaledImageExtent = capabilities->maxImageExtent; + } break; + + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { + VkSurfacePresentModeCompatibilityEXT* mode_caps = + reinterpret_cast(pNext); + + ALOG_ASSERT(pPresentMode, + "querying VkSurfacePresentModeCompatibilityEXT " + "requires VkSurfacePresentModeEXT to be provided"); + std::vector compatibleModes; + compatibleModes.push_back(pPresentMode->presentMode); + + switch (pPresentMode->presentMode) { + // Shared modes are both compatible with each other. + case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + break; + case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR); + break; + default: + // Other modes are only compatible with themselves. + // TODO: consider whether switching between FIFO and MAILBOX is reasonable + break; + } + + // Note: this does not generate VK_INCOMPLETE since we're nested inside + // a larger query and there would be no way to determine exactly where it came from. + CopyWithIncomplete(compatibleModes, mode_caps->pPresentModes, + &mode_caps->presentModeCount); + } break; + default: // Ignore all other extension structs break; } } - return result; + return VK_SUCCESS; } VKAPI_ATTR @@ -1077,18 +1168,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); } - uint32_t num_modes = uint32_t(present_modes.size()); - - VkResult result = VK_SUCCESS; - if (modes) { - if (*count < num_modes) - result = VK_INCOMPLETE; - *count = std::min(*count, num_modes); - std::copy_n(present_modes.data(), *count, modes); - } else { - *count = num_modes; - } - return result; + return CopyWithIncomplete(present_modes, modes, count); } VKAPI_ATTR @@ -1374,8 +1454,7 @@ VkResult CreateSwapchainKHR(VkDevice device, } VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || - create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + if (IsSharedPresentMode(create_info->presentMode)) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; err = native_window_set_shared_buffer_mode(window, true); if (err != android::OK) { @@ -1525,8 +1604,6 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform)); - // -- Dequeue all buffers and create a VkImage for each -- - // Any failures during or after this must cancel the dequeued buffers. VkSwapchainImageCreateInfoANDROID swapchain_image_create = { #pragma clang diagnostic push @@ -1543,13 +1620,18 @@ VkResult CreateSwapchainKHR(VkDevice device, #pragma clang diagnostic pop .pNext = &swapchain_image_create, }; + VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &image_native_buffer, + .pNext = nullptr, .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, - .extent = {0, 0, 1}, + .extent = { + create_info->imageExtent.width, + create_info->imageExtent.height, + 1 + }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -1560,60 +1642,87 @@ VkResult CreateSwapchainKHR(VkDevice device, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; + // Note: don't do deferred allocation for shared present modes. There's only one buffer + // involved so very little benefit. + if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) && + !IsSharedPresentMode(create_info->presentMode)) { + // Don't want to touch the underlying gralloc buffers yet; + // instead just create unbound VkImages which will later be bound to memory inside + // AcquireNextImage. + VkImageSwapchainCreateInfoKHR image_swapchain_create = { + .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .swapchain = HandleFromSwapchain(swapchain), + }; + image_create.pNext = &image_swapchain_create; - ANativeWindowBuffer* buffer; - err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); - if (err != android::OK) { - ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - switch (-err) { - case ENOMEM: - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; - break; - default: - result = VK_ERROR_SURFACE_LOST_KHR; - break; + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + img.buffer = nullptr; + img.dequeued = false; + + result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ for deferred swapchain image failed: %u", result); + break; } - break; } - img.buffer = buffer; - img.dequeued = true; - - image_create.extent = - VkExtent3D{static_cast(img.buffer->width), - static_cast(img.buffer->height), - 1}; - image_native_buffer.handle = img.buffer->handle; - image_native_buffer.stride = img.buffer->stride; - image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = int(img.buffer->usage); - android_convertGralloc0To1Usage(int(img.buffer->usage), - &image_native_buffer.usage2.producer, - &image_native_buffer.usage2.consumer); - image_native_buffer.usage3 = img.buffer->usage; - - ATRACE_BEGIN("CreateImage"); - result = - dispatch.CreateImage(device, &image_create, nullptr, &img.image); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ native buffer failed: %u", result); - break; + } else { + // -- Dequeue all buffers and create a VkImage for each -- + // Any failures during or after this must cancel the dequeued buffers. + + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + + ANativeWindowBuffer* buffer; + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { + ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; + } + break; + } + img.buffer = buffer; + img.dequeued = true; + + image_native_buffer.handle = img.buffer->handle; + image_native_buffer.stride = img.buffer->stride; + image_native_buffer.format = img.buffer->format; + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), + &image_native_buffer.usage2.producer, + &image_native_buffer.usage2.consumer); + image_native_buffer.usage3 = img.buffer->usage; + image_create.pNext = &image_native_buffer; + + ATRACE_BEGIN("CreateImage"); + result = + dispatch.CreateImage(device, &image_create, nullptr, &img.image); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ native buffer failed: %u", result); + break; + } } - } - // -- Cancel all buffers, returning them to the queue -- - // If an error occurred before, also destroy the VkImage and release the - // buffer reference. Otherwise, we retain a strong reference to the buffer. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - if (!swapchain->shared) { - window->cancelBuffer(window, img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; + // -- Cancel all buffers, returning them to the queue -- + // If an error occurred before, also destroy the VkImage and release the + // buffer reference. Otherwise, we retain a strong reference to the buffer. + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; + } } } } @@ -1736,6 +1845,64 @@ VkResult AcquireNextImageKHR(VkDevice device, break; } } + + // If this is a deferred alloc swapchain, this may be the first time we've + // seen a particular buffer. If so, there should be an empty slot. Find it, + // and bind the gralloc buffer to the VkImage for that slot. If there is no + // empty slot, then we dequeued an unexpected buffer. Non-deferred swapchains + // will also take this path, but will never have an empty slot since we + // populated them all upfront. + if (idx == swapchain.num_images) { + for (idx = 0; idx < swapchain.num_images; idx++) { + if (!swapchain.images[idx].buffer) { + // Note: this structure is technically required for + // Vulkan correctness, even though the driver is probably going + // to use everything from the VkNativeBufferANDROID below. + // This is kindof silly, but it's how we did the ANB + // side of VK_KHR_swapchain v69, so we're stuck with it unless + // we want to go tinkering with the ANB spec some more. + VkBindImageMemorySwapchainInfoKHR bimsi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, + .pNext = nullptr, + .swapchain = swapchain_handle, + .imageIndex = idx, + }; + VkNativeBufferANDROID nb = { + .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, + .pNext = &bimsi, + .handle = buffer->handle, + .stride = buffer->stride, + .format = buffer->format, + .usage = int(buffer->usage), + }; + VkBindImageMemoryInfo bimi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + .pNext = &nb, + .image = swapchain.images[idx].image, + .memory = VK_NULL_HANDLE, + .memoryOffset = 0, + }; + result = GetData(device).driver.BindImageMemory2(device, 1, &bimi); + if (result != VK_SUCCESS) { + // This shouldn't really happen. If it does, something is probably + // unrecoverably wrong with the swapchain and its images. Cancel + // the buffer and declare the swapchain broken. + ALOGE("failed to do deferred gralloc buffer bind"); + window->cancelBuffer(window, buffer, fence_fd); + return VK_ERROR_OUT_OF_DATE_KHR; + } + + swapchain.images[idx].dequeued = true; + swapchain.images[idx].dequeue_fence = fence_fd; + swapchain.images[idx].buffer = buffer; + break; + } + } + } + + // The buffer doesn't match any slot. This shouldn't normally happen, but is + // possible if the bufferqueue is reconfigured behind libvulkan's back. If this + // happens, just declare the swapchain to be broken and the app will recreate it. if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); @@ -1861,12 +2028,32 @@ static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTime } } +// EXT_swapchain_maintenance1 present mode change +static bool SetSwapchainPresentMode(ANativeWindow *window, VkPresentModeKHR mode) { + // There is no dynamic switching between non-shared present modes. + // All we support is switching between demand and continuous refresh. + if (!IsSharedPresentMode(mode)) + return true; + + int err = native_window_set_auto_refresh(window, + mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + if (err != android::OK) { + ALOGE("native_window_set_auto_refresh() failed: %s (%d)", + strerror(-err), err); + return false; + } + + return true; +} + static VkResult PresentOneSwapchain( VkQueue queue, Swapchain& swapchain, uint32_t imageIndex, const VkPresentRegionKHR *pRegion, const VkPresentTimeGOOGLE *pTime, + VkFence presentFence, + const VkPresentModeKHR *pPresentMode, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores) { @@ -1897,12 +2084,33 @@ static VkResult PresentOneSwapchain( ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { + if (presentFence != VK_NULL_HANDLE) { + int fence_copy = fence < 0 ? -1 : dup(fence); + VkImportFenceFdInfoKHR iffi = { + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, + nullptr, + presentFence, + VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + fence_copy, + }; + if (VK_SUCCESS != dispatch.ImportFenceFdKHR(device, &iffi) && fence_copy >= 0) { + // ImportFenceFdKHR takes ownership only if it succeeds + close(fence_copy); + } + } + if (pRegion) { SetSwapchainSurfaceDamage(window, pRegion); } if (pTime) { SetSwapchainFrameTimestamp(swapchain, pTime); } + if (pPresentMode) { + if (!SetSwapchainPresentMode(window, *pPresentMode)) + swapchain_result = WorstPresentResult(swapchain_result, + VK_ERROR_SURFACE_LOST_KHR); + } err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error @@ -1983,6 +2191,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Look at the pNext chain for supported extension structs: const VkPresentRegionsKHR* present_regions = nullptr; const VkPresentTimesInfoGOOGLE* present_times = nullptr; + const VkSwapchainPresentFenceInfoEXT* present_fences = nullptr; + const VkSwapchainPresentModeInfoEXT* present_modes = nullptr; + const VkPresentRegionsKHR* next = reinterpret_cast(present_info->pNext); while (next) { @@ -1994,6 +2205,14 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times = reinterpret_cast(next); break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: + present_fences = + reinterpret_cast(next); + break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: + present_modes = + reinterpret_cast(next); + break; default: ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", next->sType); @@ -2009,6 +2228,15 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times->swapchainCount != present_info->swapchainCount, "VkPresentTimesInfoGOOGLE::swapchainCount != " "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_fences && + present_fences->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentFenceInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_modes && + present_modes->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentModeInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + const VkPresentRegionKHR* regions = (present_regions) ? present_regions->pRegions : nullptr; const VkPresentTimeGOOGLE* times = @@ -2024,6 +2252,8 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info->pImageIndices[sc], (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr, times ? ×[sc] : nullptr, + present_fences ? present_fences->pFences[sc] : VK_NULL_HANDLE, + present_modes ? &present_modes->pPresentModes[sc] : nullptr, present_info->waitSemaphoreCount, present_info->pWaitSemaphores); @@ -2248,5 +2478,35 @@ VkResult BindImageMemory2KHR(VkDevice device, out_bind_infos.empty() ? pBindInfos : out_bind_infos.data()); } +VKAPI_ATTR +VkResult ReleaseSwapchainImagesEXT(VkDevice /*device*/, + const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + ATRACE_CALL(); + + Swapchain& swapchain = *SwapchainFromHandle(pReleaseInfo->swapchain); + ANativeWindow* window = swapchain.surface.window.get(); + + // If in shared present mode, don't actually release the image back to the BQ. + // Both sides share it forever. + if (swapchain.shared) + return VK_SUCCESS; + + for (uint32_t i = 0; i < pReleaseInfo->imageIndexCount; i++) { + Swapchain::Image& img = swapchain.images[pReleaseInfo->pImageIndices[i]]; + window->cancelBuffer(window, img.buffer.get(), img.dequeue_fence); + + // cancelBuffer has taken ownership of the dequeue fence + img.dequeue_fence = -1; + // if we're still holding a release fence, get rid of it now + if (img.release_fence >= 0) { + close(img.release_fence); + img.release_fence = -1; + } + img.dequeued = false; + } + + return VK_SUCCESS; +} + } // namespace driver } // namespace vulkan diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index 4912ef1a33..280fe9b5a3 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -46,6 +46,7 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice ph VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult ReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); // clang-format on } // namespace driver diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index af56764a21..78b550c202 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -35,6 +35,8 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_KHR_surface', 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', + 'VK_EXT_swapchain_maintenance1', + 'VK_EXT_surface_maintenance1', ] # Extensions known to vulkan::driver level. @@ -46,6 +48,7 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 'VK_KHR_external_memory_capabilities', 'VK_KHR_external_semaphore_capabilities', 'VK_KHR_external_fence_capabilities', + 'VK_KHR_external_fence_fd', ] # Functions needed at vulkan::driver level. @@ -112,6 +115,9 @@ _NEEDED_COMMANDS = [ # For promoted VK_KHR_external_fence_capabilities 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalFencePropertiesKHR', + + # VK_KHR_swapchain_maintenance1 requirement + 'vkImportFenceFdKHR', ] # Functions intercepted at vulkan::driver level. -- cgit v1.2.3-59-g8ed1b From ac40c1e284453e10a7c2b6f2c6090fc4be322398 Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Wed, 21 Dec 2022 23:16:21 +0000 Subject: Revert "libvulkan: Implement EXT_swapchain_maintenance1" This reverts commit 08c7bb1fdb33d6ad34ba1b2de3ac0579750456fe. Reason for revert: Possibly the cause of b/263412882 (will revert and see if that clears up the problem) Change-Id: If217e36c67fcea8b5270dbf20b0c13c42d1da09a --- vulkan/libvulkan/driver.cpp | 56 +--- vulkan/libvulkan/driver_gen.cpp | 20 -- vulkan/libvulkan/driver_gen.h | 4 - vulkan/libvulkan/swapchain.cpp | 624 +++++++++++-------------------------- vulkan/libvulkan/swapchain.h | 1 - vulkan/scripts/driver_generator.py | 6 - 6 files changed, 183 insertions(+), 528 deletions(-) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index b7e19d4296..9ed992b230 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -636,7 +636,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::GOOGLE_surfaceless_query: - case ProcHook::EXT_surface_maintenance1: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -658,11 +657,9 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_shared_presentable_image: case ProcHook::KHR_swapchain: case ProcHook::EXT_hdr_metadata: - case ProcHook::EXT_swapchain_maintenance1: case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: - case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: case ProcHook::EXTENSION_CORE_1_2: @@ -693,22 +690,16 @@ void CreateInfoWrapper::FilterExtension(const char* name) { ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::KHR_incremental_present: - case ProcHook::KHR_shared_presentable_image: case ProcHook::GOOGLE_display_timing: + case ProcHook::KHR_shared_presentable_image: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; - case ProcHook::EXT_swapchain_maintenance1: - // map VK_KHR_swapchain_maintenance1 to KHR_external_fence_fd - name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; - ext_bit = ProcHook::KHR_external_fence_fd; - break; case ProcHook::EXT_hdr_metadata: case ProcHook::KHR_bind_memory2: hook_extensions_.set(ext_bit); break; case ProcHook::ANDROID_external_memory_android_hardware_buffer: - case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_UNKNOWN: // Extensions we don't need to do anything about at this level break; @@ -724,7 +715,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: - case ProcHook::EXT_surface_maintenance1: case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: @@ -761,8 +751,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); - if (ext_bit == ProcHook::KHR_external_fence_fd) - hook_extensions_.set(ProcHook::EXT_swapchain_maintenance1); hal_extensions_.set(ext_bit); } @@ -952,9 +940,6 @@ VkResult EnumerateInstanceExtensionProperties( VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); - loader_extensions.push_back({ - VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, - VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, @@ -1087,33 +1072,6 @@ VkResult GetAndroidNativeBufferSpecVersion9Support( return result; } -bool CanSupportSwapchainMaintenance1Extension(VkPhysicalDevice physicalDevice) { - const auto& driver = GetData(physicalDevice).driver; - if (!driver.GetPhysicalDeviceExternalFenceProperties) - return false; - - // Requires support for external fences imported from sync fds. - // This is _almost_ universal on Android, but may be missing on - // some extremely old drivers, or on strange implementations like - // cuttlefish. - VkPhysicalDeviceExternalFenceInfo fenceInfo = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - nullptr, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT - }; - VkExternalFenceProperties fenceProperties = { - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, - nullptr, - 0, 0, 0 - }; - - GetPhysicalDeviceExternalFenceProperties(physicalDevice, &fenceInfo, &fenceProperties); - if (fenceProperties.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT) - return true; - - return false; -} - VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, @@ -1191,12 +1149,6 @@ VkResult EnumerateDeviceExtensionProperties( VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION}); } - if (CanSupportSwapchainMaintenance1Extension(physicalDevice)) { - loader_extensions.push_back({ - VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, - VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION}); - } - // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( @@ -1692,12 +1644,6 @@ void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, imageCompressionControlSwapchainInChain = true; } break; - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { - auto smf = reinterpret_cast( - pFeats); - smf->swapchainMaintenance1 = true; - } break; - default: break; } diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 798af5c6a6..de98aa7e61 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -162,15 +162,6 @@ VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 } } -VKAPI_ATTR VkResult checkedReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { - if (GetData(device).hook_extensions[ProcHook::EXT_swapchain_maintenance1]) { - return ReleaseSwapchainImagesEXT(device, pReleaseInfo); - } else { - Logger(device).Err(device, "VK_EXT_swapchain_maintenance1 not enabled. vkReleaseSwapchainImagesEXT not executed."); - return VK_SUCCESS; - } -} - // clang-format on const ProcHook g_proc_hooks[] = { @@ -553,13 +544,6 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast(QueueSubmit), nullptr, }, - { - "vkReleaseSwapchainImagesEXT", - ProcHook::DEVICE, - ProcHook::EXT_swapchain_maintenance1, - reinterpret_cast(ReleaseSwapchainImagesEXT), - reinterpret_cast(checkedReleaseSwapchainImagesEXT), - }, { "vkSetHdrMetadataEXT", ProcHook::DEVICE, @@ -596,8 +580,6 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; - if (strcmp(name, "VK_EXT_swapchain_maintenance1") == 0) return ProcHook::EXT_swapchain_maintenance1; - if (strcmp(name, "VK_EXT_surface_maintenance1") == 0) return ProcHook::EXT_surface_maintenance1; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2; @@ -605,7 +587,6 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities; if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities; if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities; - if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } @@ -685,7 +666,6 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); - INIT_PROC_EXT(KHR_external_fence_fd, true, dev, ImportFenceFdKHR); INIT_PROC(false, dev, BindImageMemory2); INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 31ba04ba1f..2f60086a27 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -49,8 +49,6 @@ struct ProcHook { KHR_surface, KHR_surface_protected_capabilities, KHR_swapchain, - EXT_swapchain_maintenance1, - EXT_surface_maintenance1, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, KHR_get_physical_device_properties2, @@ -58,7 +56,6 @@ struct ProcHook { KHR_external_memory_capabilities, KHR_external_semaphore_capabilities, KHR_external_fence_capabilities, - KHR_external_fence_fd, EXTENSION_CORE_1_0, EXTENSION_CORE_1_1, @@ -121,7 +118,6 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; - PFN_vkImportFenceFdKHR ImportFenceFdKHR; PFN_vkBindImageMemory2 BindImageMemory2; PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 0dac6ad1aa..1bf7abb758 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -291,9 +291,6 @@ struct Swapchain { release_fence(-1), dequeued(false) {} VkImage image; - // If the image is bound to memory, an sp to the underlying gralloc buffer. - // Otherwise, nullptr; the image will be bound to memory as part of - // AcquireNextImage. android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is @@ -655,40 +652,100 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); - // Implement in terms of GetPhysicalDeviceSurfaceCapabilities2KHR + int err; + int width, height; + int transform_hint; + int max_buffer_count; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(pdev); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 0xFFFFFFFF; + height = 0xFFFFFFFF; + transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + capabilities->minImageCount = 0xFFFFFFFF; + capabilities->maxImageCount = 0xFFFFFFFF; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - VkPhysicalDeviceSurfaceInfo2KHR info2 = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, - nullptr, - surface - }; + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } - VkSurfaceCapabilities2KHR caps2 = { - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, - nullptr, - {}, - }; + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } - VkResult result = GetPhysicalDeviceSurfaceCapabilities2KHR(pdev, &info2, &caps2); - *capabilities = caps2.surfaceCapabilities; - return result; -} + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + capabilities->minImageCount = std::min(max_buffer_count, 3); + capabilities->maxImageCount = static_cast(max_buffer_count); + } -// Does the call-twice and VK_INCOMPLETE handling for querying lists -// of things, where we already have the full set built in a vector. -template -VkResult CopyWithIncomplete(std::vector const& things, - T* callerPtr, uint32_t* callerCount) { - VkResult result = VK_SUCCESS; - if (callerPtr) { - if (things.size() > *callerCount) - result = VK_INCOMPLETE; - *callerCount = std::min(uint32_t(things.size()), *callerCount); - std::copy(things.begin(), things.begin() + *callerCount, callerPtr); - } else { - *callerCount = things.size(); + capabilities->currentExtent = + VkExtent2D{static_cast(width), static_cast(height)}; + + // TODO(http://b/134182502): Figure out what the max extent should be. + capabilities->minImageExtent = VkExtent2D{1, 1}; + capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + + if (capabilities->maxImageExtent.height < + capabilities->currentExtent.height) { + capabilities->maxImageExtent.height = + capabilities->currentExtent.height; } - return result; + + if (capabilities->maxImageExtent.width < + capabilities->currentExtent.width) { + capabilities->maxImageExtent.width = capabilities->currentExtent.width; + } + + capabilities->maxImageArrayLayers = 1; + + capabilities->supportedTransforms = kSupportedTransforms; + capabilities->currentTransform = + TranslateNativeToVulkanTransform(transform_hint); + + // On Android, window composition is a WindowManager property, not something + // associated with the bufferqueue. It can't be changed from here. + capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + + capabilities->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + return VK_SUCCESS; } VKAPI_ATTR @@ -805,7 +862,21 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // Android users. This includes the ANGLE team (a layered implementation of // OpenGL-ES). - return CopyWithIncomplete(all_formats, formats, count); + VkResult result = VK_SUCCESS; + if (formats) { + uint32_t transfer_count = all_formats.size(); + if (transfer_count > *count) { + transfer_count = *count; + result = VK_INCOMPLETE; + } + std::copy(all_formats.begin(), all_formats.begin() + transfer_count, + formats); + *count = transfer_count; + } else { + *count = all_formats.size(); + } + + return result; } VKAPI_ATTR @@ -815,134 +886,19 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { ATRACE_CALL(); - auto surface = pSurfaceInfo->surface; - auto capabilities = &pSurfaceCapabilities->surfaceCapabilities; - - VkSurfacePresentModeEXT const *pPresentMode = nullptr; - for (auto pNext = reinterpret_cast(pSurfaceInfo->pNext); - pNext; pNext = reinterpret_cast(pNext->pNext)) { - switch (pNext->sType) { - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: - pPresentMode = reinterpret_cast(pNext); - break; - - default: - break; - } - } + VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR( + physicalDevice, pSurfaceInfo->surface, + &pSurfaceCapabilities->surfaceCapabilities); - int err; - int width, height; - int transform_hint; - int max_buffer_count; - if (surface == VK_NULL_HANDLE) { - const InstanceData& instance_data = GetData(physicalDevice); - ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; - bool surfaceless_enabled = - instance_data.hook_extensions.test(surfaceless); - if (!surfaceless_enabled) { - // It is an error to pass a surface==VK_NULL_HANDLE unless the - // VK_GOOGLE_surfaceless_query extension is enabled - return VK_ERROR_SURFACE_LOST_KHR; - } - // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this - // extension for this function is for - // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following - // four values cannot be known without a surface. Default values will - // be supplied anyway, but cannot be relied upon. - width = 0xFFFFFFFF; - height = 0xFFFFFFFF; - transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - capabilities->minImageCount = 0xFFFFFFFF; - capabilities->maxImageCount = 0xFFFFFFFF; - } else { - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities; + while (caps->pNext) { + caps = reinterpret_cast(caps->pNext); - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, - &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, - &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - if (pPresentMode && IsSharedPresentMode(pPresentMode->presentMode)) { - capabilities->minImageCount = 1; - capabilities->maxImageCount = 1; - } else if (pPresentMode && pPresentMode->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - // TODO: use undequeued buffer requirement for more precise bound - capabilities->minImageCount = std::min(max_buffer_count, 4); - capabilities->maxImageCount = static_cast(max_buffer_count); - } else { - // TODO: if we're able to, provide better bounds on the number of buffers - // for other modes as well. - capabilities->minImageCount = std::min(max_buffer_count, 3); - capabilities->maxImageCount = static_cast(max_buffer_count); - } - } - - capabilities->currentExtent = - VkExtent2D{static_cast(width), static_cast(height)}; - - // TODO(http://b/134182502): Figure out what the max extent should be. - capabilities->minImageExtent = VkExtent2D{1, 1}; - capabilities->maxImageExtent = VkExtent2D{4096, 4096}; - - if (capabilities->maxImageExtent.height < - capabilities->currentExtent.height) { - capabilities->maxImageExtent.height = - capabilities->currentExtent.height; - } - - if (capabilities->maxImageExtent.width < - capabilities->currentExtent.width) { - capabilities->maxImageExtent.width = capabilities->currentExtent.width; - } - - capabilities->maxImageArrayLayers = 1; - - capabilities->supportedTransforms = kSupportedTransforms; - capabilities->currentTransform = - TranslateNativeToVulkanTransform(transform_hint); - - // On Android, window composition is a WindowManager property, not something - // associated with the bufferqueue. It can't be changed from here. - capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - - capabilities->supportedUsageFlags = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - - for (auto pNext = reinterpret_cast(pSurfaceCapabilities->pNext); - pNext; pNext = reinterpret_cast(pNext->pNext)) { - - switch (pNext->sType) { + switch (caps->sType) { case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: { VkSharedPresentSurfaceCapabilitiesKHR* shared_caps = - reinterpret_cast(pNext); + reinterpret_cast( + caps); // Claim same set of usage flags are supported for // shared present modes as for other modes. shared_caps->sharedPresentSupportedUsageFlags = @@ -952,64 +908,17 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { VkSurfaceProtectedCapabilitiesKHR* protected_caps = - reinterpret_cast(pNext); + reinterpret_cast(caps); protected_caps->supportsProtected = VK_TRUE; } break; - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { - VkSurfacePresentScalingCapabilitiesEXT* scaling_caps = - reinterpret_cast(pNext); - // By default, Android stretches the buffer to fit the window, - // without preserving aspect ratio. Other modes are technically possible - // but consult with CoGS team before exposing them here! - scaling_caps->supportedPresentScaling = VK_PRESENT_SCALING_STRETCH_BIT_EXT; - - // Since we always scale, we don't support any gravity. - scaling_caps->supportedPresentGravityX = 0; - scaling_caps->supportedPresentGravityY = 0; - - // Scaled image limits are just the basic image limits - scaling_caps->minScaledImageExtent = capabilities->minImageExtent; - scaling_caps->maxScaledImageExtent = capabilities->maxImageExtent; - } break; - - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { - VkSurfacePresentModeCompatibilityEXT* mode_caps = - reinterpret_cast(pNext); - - ALOG_ASSERT(pPresentMode, - "querying VkSurfacePresentModeCompatibilityEXT " - "requires VkSurfacePresentModeEXT to be provided"); - std::vector compatibleModes; - compatibleModes.push_back(pPresentMode->presentMode); - - switch (pPresentMode->presentMode) { - // Shared modes are both compatible with each other. - case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: - compatibleModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); - break; - case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: - compatibleModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR); - break; - default: - // Other modes are only compatible with themselves. - // TODO: consider whether switching between FIFO and MAILBOX is reasonable - break; - } - - // Note: this does not generate VK_INCOMPLETE since we're nested inside - // a larger query and there would be no way to determine exactly where it came from. - CopyWithIncomplete(compatibleModes, mode_caps->pPresentModes, - &mode_caps->presentModeCount); - } break; - default: // Ignore all other extension structs break; } } - return VK_SUCCESS; + return result; } VKAPI_ATTR @@ -1168,7 +1077,18 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); } - return CopyWithIncomplete(present_modes, modes, count); + uint32_t num_modes = uint32_t(present_modes.size()); + + VkResult result = VK_SUCCESS; + if (modes) { + if (*count < num_modes) + result = VK_INCOMPLETE; + *count = std::min(*count, num_modes); + std::copy_n(present_modes.data(), *count, modes); + } else { + *count = num_modes; + } + return result; } VKAPI_ATTR @@ -1454,7 +1374,8 @@ VkResult CreateSwapchainKHR(VkDevice device, } VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (IsSharedPresentMode(create_info->presentMode)) { + if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; err = native_window_set_shared_buffer_mode(window, true); if (err != android::OK) { @@ -1604,6 +1525,8 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform)); + // -- Dequeue all buffers and create a VkImage for each -- + // Any failures during or after this must cancel the dequeued buffers. VkSwapchainImageCreateInfoANDROID swapchain_image_create = { #pragma clang diagnostic push @@ -1620,18 +1543,13 @@ VkResult CreateSwapchainKHR(VkDevice device, #pragma clang diagnostic pop .pNext = &swapchain_image_create, }; - VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = nullptr, + .pNext = &image_native_buffer, .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, - .extent = { - create_info->imageExtent.width, - create_info->imageExtent.height, - 1 - }, + .extent = {0, 0, 1}, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -1642,87 +1560,60 @@ VkResult CreateSwapchainKHR(VkDevice device, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; - // Note: don't do deferred allocation for shared present modes. There's only one buffer - // involved so very little benefit. - if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) && - !IsSharedPresentMode(create_info->presentMode)) { - // Don't want to touch the underlying gralloc buffers yet; - // instead just create unbound VkImages which will later be bound to memory inside - // AcquireNextImage. - VkImageSwapchainCreateInfoKHR image_swapchain_create = { - .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = nullptr, - .swapchain = HandleFromSwapchain(swapchain), - }; - image_create.pNext = &image_swapchain_create; - - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - img.buffer = nullptr; - img.dequeued = false; + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; - result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ for deferred swapchain image failed: %u", result); - break; + ANativeWindowBuffer* buffer; + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { + ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; } + break; } - } else { - // -- Dequeue all buffers and create a VkImage for each -- - // Any failures during or after this must cancel the dequeued buffers. - - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - - ANativeWindowBuffer* buffer; - err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); - if (err != android::OK) { - ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - switch (-err) { - case ENOMEM: - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; - break; - default: - result = VK_ERROR_SURFACE_LOST_KHR; - break; - } - break; - } - img.buffer = buffer; - img.dequeued = true; - - image_native_buffer.handle = img.buffer->handle; - image_native_buffer.stride = img.buffer->stride; - image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = int(img.buffer->usage); - android_convertGralloc0To1Usage(int(img.buffer->usage), - &image_native_buffer.usage2.producer, - &image_native_buffer.usage2.consumer); - image_native_buffer.usage3 = img.buffer->usage; - image_create.pNext = &image_native_buffer; - - ATRACE_BEGIN("CreateImage"); - result = - dispatch.CreateImage(device, &image_create, nullptr, &img.image); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ native buffer failed: %u", result); - break; - } + img.buffer = buffer; + img.dequeued = true; + + image_create.extent = + VkExtent3D{static_cast(img.buffer->width), + static_cast(img.buffer->height), + 1}; + image_native_buffer.handle = img.buffer->handle; + image_native_buffer.stride = img.buffer->stride; + image_native_buffer.format = img.buffer->format; + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), + &image_native_buffer.usage2.producer, + &image_native_buffer.usage2.consumer); + image_native_buffer.usage3 = img.buffer->usage; + + ATRACE_BEGIN("CreateImage"); + result = + dispatch.CreateImage(device, &image_create, nullptr, &img.image); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ native buffer failed: %u", result); + break; } + } - // -- Cancel all buffers, returning them to the queue -- - // If an error occurred before, also destroy the VkImage and release the - // buffer reference. Otherwise, we retain a strong reference to the buffer. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - if (!swapchain->shared) { - window->cancelBuffer(window, img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; - } + // -- Cancel all buffers, returning them to the queue -- + // If an error occurred before, also destroy the VkImage and release the + // buffer reference. Otherwise, we retain a strong reference to the buffer. + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; } } } @@ -1845,64 +1736,6 @@ VkResult AcquireNextImageKHR(VkDevice device, break; } } - - // If this is a deferred alloc swapchain, this may be the first time we've - // seen a particular buffer. If so, there should be an empty slot. Find it, - // and bind the gralloc buffer to the VkImage for that slot. If there is no - // empty slot, then we dequeued an unexpected buffer. Non-deferred swapchains - // will also take this path, but will never have an empty slot since we - // populated them all upfront. - if (idx == swapchain.num_images) { - for (idx = 0; idx < swapchain.num_images; idx++) { - if (!swapchain.images[idx].buffer) { - // Note: this structure is technically required for - // Vulkan correctness, even though the driver is probably going - // to use everything from the VkNativeBufferANDROID below. - // This is kindof silly, but it's how we did the ANB - // side of VK_KHR_swapchain v69, so we're stuck with it unless - // we want to go tinkering with the ANB spec some more. - VkBindImageMemorySwapchainInfoKHR bimsi = { - .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, - .pNext = nullptr, - .swapchain = swapchain_handle, - .imageIndex = idx, - }; - VkNativeBufferANDROID nb = { - .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, - .pNext = &bimsi, - .handle = buffer->handle, - .stride = buffer->stride, - .format = buffer->format, - .usage = int(buffer->usage), - }; - VkBindImageMemoryInfo bimi = { - .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - .pNext = &nb, - .image = swapchain.images[idx].image, - .memory = VK_NULL_HANDLE, - .memoryOffset = 0, - }; - result = GetData(device).driver.BindImageMemory2(device, 1, &bimi); - if (result != VK_SUCCESS) { - // This shouldn't really happen. If it does, something is probably - // unrecoverably wrong with the swapchain and its images. Cancel - // the buffer and declare the swapchain broken. - ALOGE("failed to do deferred gralloc buffer bind"); - window->cancelBuffer(window, buffer, fence_fd); - return VK_ERROR_OUT_OF_DATE_KHR; - } - - swapchain.images[idx].dequeued = true; - swapchain.images[idx].dequeue_fence = fence_fd; - swapchain.images[idx].buffer = buffer; - break; - } - } - } - - // The buffer doesn't match any slot. This shouldn't normally happen, but is - // possible if the bufferqueue is reconfigured behind libvulkan's back. If this - // happens, just declare the swapchain to be broken and the app will recreate it. if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); @@ -2028,32 +1861,12 @@ static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTime } } -// EXT_swapchain_maintenance1 present mode change -static bool SetSwapchainPresentMode(ANativeWindow *window, VkPresentModeKHR mode) { - // There is no dynamic switching between non-shared present modes. - // All we support is switching between demand and continuous refresh. - if (!IsSharedPresentMode(mode)) - return true; - - int err = native_window_set_auto_refresh(window, - mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); - if (err != android::OK) { - ALOGE("native_window_set_auto_refresh() failed: %s (%d)", - strerror(-err), err); - return false; - } - - return true; -} - static VkResult PresentOneSwapchain( VkQueue queue, Swapchain& swapchain, uint32_t imageIndex, const VkPresentRegionKHR *pRegion, const VkPresentTimeGOOGLE *pTime, - VkFence presentFence, - const VkPresentModeKHR *pPresentMode, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores) { @@ -2084,33 +1897,12 @@ static VkResult PresentOneSwapchain( ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { - if (presentFence != VK_NULL_HANDLE) { - int fence_copy = fence < 0 ? -1 : dup(fence); - VkImportFenceFdInfoKHR iffi = { - VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, - nullptr, - presentFence, - VK_FENCE_IMPORT_TEMPORARY_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, - fence_copy, - }; - if (VK_SUCCESS != dispatch.ImportFenceFdKHR(device, &iffi) && fence_copy >= 0) { - // ImportFenceFdKHR takes ownership only if it succeeds - close(fence_copy); - } - } - if (pRegion) { SetSwapchainSurfaceDamage(window, pRegion); } if (pTime) { SetSwapchainFrameTimestamp(swapchain, pTime); } - if (pPresentMode) { - if (!SetSwapchainPresentMode(window, *pPresentMode)) - swapchain_result = WorstPresentResult(swapchain_result, - VK_ERROR_SURFACE_LOST_KHR); - } err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error @@ -2191,9 +1983,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Look at the pNext chain for supported extension structs: const VkPresentRegionsKHR* present_regions = nullptr; const VkPresentTimesInfoGOOGLE* present_times = nullptr; - const VkSwapchainPresentFenceInfoEXT* present_fences = nullptr; - const VkSwapchainPresentModeInfoEXT* present_modes = nullptr; - const VkPresentRegionsKHR* next = reinterpret_cast(present_info->pNext); while (next) { @@ -2205,14 +1994,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times = reinterpret_cast(next); break; - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: - present_fences = - reinterpret_cast(next); - break; - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: - present_modes = - reinterpret_cast(next); - break; default: ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", next->sType); @@ -2228,15 +2009,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times->swapchainCount != present_info->swapchainCount, "VkPresentTimesInfoGOOGLE::swapchainCount != " "VkPresentInfo::swapchainCount"); - ALOGV_IF(present_fences && - present_fences->swapchainCount != present_info->swapchainCount, - "VkSwapchainPresentFenceInfoEXT::swapchainCount != " - "VkPresentInfo::swapchainCount"); - ALOGV_IF(present_modes && - present_modes->swapchainCount != present_info->swapchainCount, - "VkSwapchainPresentModeInfoEXT::swapchainCount != " - "VkPresentInfo::swapchainCount"); - const VkPresentRegionKHR* regions = (present_regions) ? present_regions->pRegions : nullptr; const VkPresentTimeGOOGLE* times = @@ -2252,8 +2024,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info->pImageIndices[sc], (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr, times ? ×[sc] : nullptr, - present_fences ? present_fences->pFences[sc] : VK_NULL_HANDLE, - present_modes ? &present_modes->pPresentModes[sc] : nullptr, present_info->waitSemaphoreCount, present_info->pWaitSemaphores); @@ -2478,35 +2248,5 @@ VkResult BindImageMemory2KHR(VkDevice device, out_bind_infos.empty() ? pBindInfos : out_bind_infos.data()); } -VKAPI_ATTR -VkResult ReleaseSwapchainImagesEXT(VkDevice /*device*/, - const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { - ATRACE_CALL(); - - Swapchain& swapchain = *SwapchainFromHandle(pReleaseInfo->swapchain); - ANativeWindow* window = swapchain.surface.window.get(); - - // If in shared present mode, don't actually release the image back to the BQ. - // Both sides share it forever. - if (swapchain.shared) - return VK_SUCCESS; - - for (uint32_t i = 0; i < pReleaseInfo->imageIndexCount; i++) { - Swapchain::Image& img = swapchain.images[pReleaseInfo->pImageIndices[i]]; - window->cancelBuffer(window, img.buffer.get(), img.dequeue_fence); - - // cancelBuffer has taken ownership of the dequeue fence - img.dequeue_fence = -1; - // if we're still holding a release fence, get rid of it now - if (img.release_fence >= 0) { - close(img.release_fence); - img.release_fence = -1; - } - img.dequeued = false; - } - - return VK_SUCCESS; -} - } // namespace driver } // namespace vulkan diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index 280fe9b5a3..4912ef1a33 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -46,7 +46,6 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice ph VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -VKAPI_ATTR VkResult ReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); // clang-format on } // namespace driver diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index 78b550c202..af56764a21 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -35,8 +35,6 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_KHR_surface', 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', - 'VK_EXT_swapchain_maintenance1', - 'VK_EXT_surface_maintenance1', ] # Extensions known to vulkan::driver level. @@ -48,7 +46,6 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 'VK_KHR_external_memory_capabilities', 'VK_KHR_external_semaphore_capabilities', 'VK_KHR_external_fence_capabilities', - 'VK_KHR_external_fence_fd', ] # Functions needed at vulkan::driver level. @@ -115,9 +112,6 @@ _NEEDED_COMMANDS = [ # For promoted VK_KHR_external_fence_capabilities 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalFencePropertiesKHR', - - # VK_KHR_swapchain_maintenance1 requirement - 'vkImportFenceFdKHR', ] # Functions intercepted at vulkan::driver level. -- cgit v1.2.3-59-g8ed1b From 2dcb4f0064d3d6a01105d2c8a12368c347d85227 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Thu, 22 Dec 2022 14:40:23 +1300 Subject: Reland: "libvulkan: Implement EXT_swapchain_maintenance1"" This reverts commit ac40c1e284453e10a7c2b6f2c6090fc4be322398 and incorporates a fix for the memory corruption that caused us to revert it initially. Bug: b/255376900 Change-Id: I3d8ab1977ea705bebdb8cd2c69d39f06ab5c4158 --- vulkan/libvulkan/driver.cpp | 62 +++- vulkan/libvulkan/driver_gen.cpp | 20 ++ vulkan/libvulkan/driver_gen.h | 4 + vulkan/libvulkan/swapchain.cpp | 624 ++++++++++++++++++++++++++----------- vulkan/libvulkan/swapchain.h | 1 + vulkan/scripts/driver_generator.py | 6 + 6 files changed, 534 insertions(+), 183 deletions(-) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 9ed992b230..273cdd547e 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -636,6 +636,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::GOOGLE_surfaceless_query: + case ProcHook::EXT_surface_maintenance1: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -657,9 +658,11 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_shared_presentable_image: case ProcHook::KHR_swapchain: case ProcHook::EXT_hdr_metadata: + case ProcHook::EXT_swapchain_maintenance1: case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: case ProcHook::EXTENSION_CORE_1_2: @@ -690,16 +693,22 @@ void CreateInfoWrapper::FilterExtension(const char* name) { ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::KHR_incremental_present: - case ProcHook::GOOGLE_display_timing: case ProcHook::KHR_shared_presentable_image: + case ProcHook::GOOGLE_display_timing: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; + case ProcHook::EXT_swapchain_maintenance1: + // map VK_KHR_swapchain_maintenance1 to KHR_external_fence_fd + name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; + ext_bit = ProcHook::KHR_external_fence_fd; + break; case ProcHook::EXT_hdr_metadata: case ProcHook::KHR_bind_memory2: hook_extensions_.set(ext_bit); break; case ProcHook::ANDROID_external_memory_android_hardware_buffer: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_UNKNOWN: // Extensions we don't need to do anything about at this level break; @@ -715,6 +724,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: + case ProcHook::EXT_surface_maintenance1: case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: @@ -747,10 +757,18 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (strcmp(name, props.extensionName) != 0) continue; + if (ext_bit != ProcHook::EXTENSION_UNKNOWN && + hal_extensions_.test(ext_bit)) { + ALOGI("CreateInfoWrapper::FilterExtension: already have '%s'.", name); + continue; + } + filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); + if (ext_bit == ProcHook::KHR_external_fence_fd) + hook_extensions_.set(ProcHook::EXT_swapchain_maintenance1); hal_extensions_.set(ext_bit); } @@ -940,6 +958,9 @@ VkResult EnumerateInstanceExtensionProperties( VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); + loader_extensions.push_back({ + VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, @@ -1072,6 +1093,33 @@ VkResult GetAndroidNativeBufferSpecVersion9Support( return result; } +bool CanSupportSwapchainMaintenance1Extension(VkPhysicalDevice physicalDevice) { + const auto& driver = GetData(physicalDevice).driver; + if (!driver.GetPhysicalDeviceExternalFenceProperties) + return false; + + // Requires support for external fences imported from sync fds. + // This is _almost_ universal on Android, but may be missing on + // some extremely old drivers, or on strange implementations like + // cuttlefish. + VkPhysicalDeviceExternalFenceInfo fenceInfo = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + nullptr, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT + }; + VkExternalFenceProperties fenceProperties = { + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + nullptr, + 0, 0, 0 + }; + + GetPhysicalDeviceExternalFenceProperties(physicalDevice, &fenceInfo, &fenceProperties); + if (fenceProperties.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT) + return true; + + return false; +} + VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, @@ -1149,6 +1197,12 @@ VkResult EnumerateDeviceExtensionProperties( VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION}); } + if (CanSupportSwapchainMaintenance1Extension(physicalDevice)) { + loader_extensions.push_back({ + VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION}); + } + // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( @@ -1644,6 +1698,12 @@ void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, imageCompressionControlSwapchainInChain = true; } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { + auto smf = reinterpret_cast( + pFeats); + smf->swapchainMaintenance1 = true; + } break; + default: break; } diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index de98aa7e61..798af5c6a6 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -162,6 +162,15 @@ VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 } } +VKAPI_ATTR VkResult checkedReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + if (GetData(device).hook_extensions[ProcHook::EXT_swapchain_maintenance1]) { + return ReleaseSwapchainImagesEXT(device, pReleaseInfo); + } else { + Logger(device).Err(device, "VK_EXT_swapchain_maintenance1 not enabled. vkReleaseSwapchainImagesEXT not executed."); + return VK_SUCCESS; + } +} + // clang-format on const ProcHook g_proc_hooks[] = { @@ -544,6 +553,13 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast(QueueSubmit), nullptr, }, + { + "vkReleaseSwapchainImagesEXT", + ProcHook::DEVICE, + ProcHook::EXT_swapchain_maintenance1, + reinterpret_cast(ReleaseSwapchainImagesEXT), + reinterpret_cast(checkedReleaseSwapchainImagesEXT), + }, { "vkSetHdrMetadataEXT", ProcHook::DEVICE, @@ -580,6 +596,8 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; + if (strcmp(name, "VK_EXT_swapchain_maintenance1") == 0) return ProcHook::EXT_swapchain_maintenance1; + if (strcmp(name, "VK_EXT_surface_maintenance1") == 0) return ProcHook::EXT_surface_maintenance1; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2; @@ -587,6 +605,7 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities; if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities; if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities; + if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } @@ -666,6 +685,7 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); + INIT_PROC_EXT(KHR_external_fence_fd, true, dev, ImportFenceFdKHR); INIT_PROC(false, dev, BindImageMemory2); INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 2f60086a27..31ba04ba1f 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -49,6 +49,8 @@ struct ProcHook { KHR_surface, KHR_surface_protected_capabilities, KHR_swapchain, + EXT_swapchain_maintenance1, + EXT_surface_maintenance1, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, KHR_get_physical_device_properties2, @@ -56,6 +58,7 @@ struct ProcHook { KHR_external_memory_capabilities, KHR_external_semaphore_capabilities, KHR_external_fence_capabilities, + KHR_external_fence_fd, EXTENSION_CORE_1_0, EXTENSION_CORE_1_1, @@ -118,6 +121,7 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; + PFN_vkImportFenceFdKHR ImportFenceFdKHR; PFN_vkBindImageMemory2 BindImageMemory2; PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index b03200e4a7..1bff50dd7f 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -291,6 +291,9 @@ struct Swapchain { release_fence(-1), dequeued(false) {} VkImage image; + // If the image is bound to memory, an sp to the underlying gralloc buffer. + // Otherwise, nullptr; the image will be bound to memory as part of + // AcquireNextImage. android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is @@ -656,100 +659,40 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); - int err; - int width, height; - int transform_hint; - int max_buffer_count; - if (surface == VK_NULL_HANDLE) { - const InstanceData& instance_data = GetData(pdev); - ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; - bool surfaceless_enabled = - instance_data.hook_extensions.test(surfaceless); - if (!surfaceless_enabled) { - // It is an error to pass a surface==VK_NULL_HANDLE unless the - // VK_GOOGLE_surfaceless_query extension is enabled - return VK_ERROR_SURFACE_LOST_KHR; - } - // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this - // extension for this function is for - // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following - // four values cannot be known without a surface. Default values will - // be supplied anyway, but cannot be relied upon. - width = 0xFFFFFFFF; - height = 0xFFFFFFFF; - transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - capabilities->minImageCount = 0xFFFFFFFF; - capabilities->maxImageCount = 0xFFFFFFFF; - } else { - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + // Implement in terms of GetPhysicalDeviceSurfaceCapabilities2KHR - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, - &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, - &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - capabilities->minImageCount = std::min(max_buffer_count, 3); - capabilities->maxImageCount = static_cast(max_buffer_count); - } - - capabilities->currentExtent = - VkExtent2D{static_cast(width), static_cast(height)}; + VkPhysicalDeviceSurfaceInfo2KHR info2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, + nullptr, + surface + }; - // TODO(http://b/134182502): Figure out what the max extent should be. - capabilities->minImageExtent = VkExtent2D{1, 1}; - capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + VkSurfaceCapabilities2KHR caps2 = { + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, + nullptr, + {}, + }; - if (capabilities->maxImageExtent.height < - capabilities->currentExtent.height) { - capabilities->maxImageExtent.height = - capabilities->currentExtent.height; - } + VkResult result = GetPhysicalDeviceSurfaceCapabilities2KHR(pdev, &info2, &caps2); + *capabilities = caps2.surfaceCapabilities; + return result; +} - if (capabilities->maxImageExtent.width < - capabilities->currentExtent.width) { - capabilities->maxImageExtent.width = capabilities->currentExtent.width; +// Does the call-twice and VK_INCOMPLETE handling for querying lists +// of things, where we already have the full set built in a vector. +template +VkResult CopyWithIncomplete(std::vector const& things, + T* callerPtr, uint32_t* callerCount) { + VkResult result = VK_SUCCESS; + if (callerPtr) { + if (things.size() > *callerCount) + result = VK_INCOMPLETE; + *callerCount = std::min(uint32_t(things.size()), *callerCount); + std::copy(things.begin(), things.begin() + *callerCount, callerPtr); + } else { + *callerCount = things.size(); } - - capabilities->maxImageArrayLayers = 1; - - capabilities->supportedTransforms = kSupportedTransforms; - capabilities->currentTransform = - TranslateNativeToVulkanTransform(transform_hint); - - // On Android, window composition is a WindowManager property, not something - // associated with the bufferqueue. It can't be changed from here. - capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - - capabilities->supportedUsageFlags = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - - return VK_SUCCESS; + return result; } VKAPI_ATTR @@ -882,21 +825,7 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // Android users. This includes the ANGLE team (a layered implementation of // OpenGL-ES). - VkResult result = VK_SUCCESS; - if (formats) { - uint32_t transfer_count = all_formats.size(); - if (transfer_count > *count) { - transfer_count = *count; - result = VK_INCOMPLETE; - } - std::copy(all_formats.begin(), all_formats.begin() + transfer_count, - formats); - *count = transfer_count; - } else { - *count = all_formats.size(); - } - - return result; + return CopyWithIncomplete(all_formats, formats, count); } VKAPI_ATTR @@ -906,19 +835,134 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { ATRACE_CALL(); - VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, pSurfaceInfo->surface, - &pSurfaceCapabilities->surfaceCapabilities); + auto surface = pSurfaceInfo->surface; + auto capabilities = &pSurfaceCapabilities->surfaceCapabilities; + + VkSurfacePresentModeEXT const *pPresentMode = nullptr; + for (auto pNext = reinterpret_cast(pSurfaceInfo->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + switch (pNext->sType) { + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: + pPresentMode = reinterpret_cast(pNext); + break; + + default: + break; + } + } - VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities; - while (caps->pNext) { - caps = reinterpret_cast(caps->pNext); + int err; + int width, height; + int transform_hint; + int max_buffer_count; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(physicalDevice); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 0xFFFFFFFF; + height = 0xFFFFFFFF; + transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + capabilities->minImageCount = 0xFFFFFFFF; + capabilities->maxImageCount = 0xFFFFFFFF; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - switch (caps->sType) { + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + if (pPresentMode && IsSharedPresentMode(pPresentMode->presentMode)) { + capabilities->minImageCount = 1; + capabilities->maxImageCount = 1; + } else if (pPresentMode && pPresentMode->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + // TODO: use undequeued buffer requirement for more precise bound + capabilities->minImageCount = std::min(max_buffer_count, 4); + capabilities->maxImageCount = static_cast(max_buffer_count); + } else { + // TODO: if we're able to, provide better bounds on the number of buffers + // for other modes as well. + capabilities->minImageCount = std::min(max_buffer_count, 3); + capabilities->maxImageCount = static_cast(max_buffer_count); + } + } + + capabilities->currentExtent = + VkExtent2D{static_cast(width), static_cast(height)}; + + // TODO(http://b/134182502): Figure out what the max extent should be. + capabilities->minImageExtent = VkExtent2D{1, 1}; + capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + + if (capabilities->maxImageExtent.height < + capabilities->currentExtent.height) { + capabilities->maxImageExtent.height = + capabilities->currentExtent.height; + } + + if (capabilities->maxImageExtent.width < + capabilities->currentExtent.width) { + capabilities->maxImageExtent.width = capabilities->currentExtent.width; + } + + capabilities->maxImageArrayLayers = 1; + + capabilities->supportedTransforms = kSupportedTransforms; + capabilities->currentTransform = + TranslateNativeToVulkanTransform(transform_hint); + + // On Android, window composition is a WindowManager property, not something + // associated with the bufferqueue. It can't be changed from here. + capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + + capabilities->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + for (auto pNext = reinterpret_cast(pSurfaceCapabilities->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + + switch (pNext->sType) { case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: { VkSharedPresentSurfaceCapabilitiesKHR* shared_caps = - reinterpret_cast( - caps); + reinterpret_cast(pNext); // Claim same set of usage flags are supported for // shared present modes as for other modes. shared_caps->sharedPresentSupportedUsageFlags = @@ -928,17 +972,64 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { VkSurfaceProtectedCapabilitiesKHR* protected_caps = - reinterpret_cast(caps); + reinterpret_cast(pNext); protected_caps->supportsProtected = VK_TRUE; } break; + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { + VkSurfacePresentScalingCapabilitiesEXT* scaling_caps = + reinterpret_cast(pNext); + // By default, Android stretches the buffer to fit the window, + // without preserving aspect ratio. Other modes are technically possible + // but consult with CoGS team before exposing them here! + scaling_caps->supportedPresentScaling = VK_PRESENT_SCALING_STRETCH_BIT_EXT; + + // Since we always scale, we don't support any gravity. + scaling_caps->supportedPresentGravityX = 0; + scaling_caps->supportedPresentGravityY = 0; + + // Scaled image limits are just the basic image limits + scaling_caps->minScaledImageExtent = capabilities->minImageExtent; + scaling_caps->maxScaledImageExtent = capabilities->maxImageExtent; + } break; + + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { + VkSurfacePresentModeCompatibilityEXT* mode_caps = + reinterpret_cast(pNext); + + ALOG_ASSERT(pPresentMode, + "querying VkSurfacePresentModeCompatibilityEXT " + "requires VkSurfacePresentModeEXT to be provided"); + std::vector compatibleModes; + compatibleModes.push_back(pPresentMode->presentMode); + + switch (pPresentMode->presentMode) { + // Shared modes are both compatible with each other. + case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + break; + case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR); + break; + default: + // Other modes are only compatible with themselves. + // TODO: consider whether switching between FIFO and MAILBOX is reasonable + break; + } + + // Note: this does not generate VK_INCOMPLETE since we're nested inside + // a larger query and there would be no way to determine exactly where it came from. + CopyWithIncomplete(compatibleModes, mode_caps->pPresentModes, + &mode_caps->presentModeCount); + } break; + default: // Ignore all other extension structs break; } } - return result; + return VK_SUCCESS; } VKAPI_ATTR @@ -1097,18 +1188,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); } - uint32_t num_modes = uint32_t(present_modes.size()); - - VkResult result = VK_SUCCESS; - if (modes) { - if (*count < num_modes) - result = VK_INCOMPLETE; - *count = std::min(*count, num_modes); - std::copy_n(present_modes.data(), *count, modes); - } else { - *count = num_modes; - } - return result; + return CopyWithIncomplete(present_modes, modes, count); } VKAPI_ATTR @@ -1394,8 +1474,7 @@ VkResult CreateSwapchainKHR(VkDevice device, } VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || - create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + if (IsSharedPresentMode(create_info->presentMode)) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; err = native_window_set_shared_buffer_mode(window, true); if (err != android::OK) { @@ -1545,8 +1624,6 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform)); - // -- Dequeue all buffers and create a VkImage for each -- - // Any failures during or after this must cancel the dequeued buffers. VkSwapchainImageCreateInfoANDROID swapchain_image_create = { #pragma clang diagnostic push @@ -1563,13 +1640,18 @@ VkResult CreateSwapchainKHR(VkDevice device, #pragma clang diagnostic pop .pNext = &swapchain_image_create, }; + VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &image_native_buffer, + .pNext = nullptr, .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, - .extent = {0, 0, 1}, + .extent = { + create_info->imageExtent.width, + create_info->imageExtent.height, + 1 + }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -1580,60 +1662,87 @@ VkResult CreateSwapchainKHR(VkDevice device, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; + // Note: don't do deferred allocation for shared present modes. There's only one buffer + // involved so very little benefit. + if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) && + !IsSharedPresentMode(create_info->presentMode)) { + // Don't want to touch the underlying gralloc buffers yet; + // instead just create unbound VkImages which will later be bound to memory inside + // AcquireNextImage. + VkImageSwapchainCreateInfoKHR image_swapchain_create = { + .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .swapchain = HandleFromSwapchain(swapchain), + }; + image_create.pNext = &image_swapchain_create; - ANativeWindowBuffer* buffer; - err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); - if (err != android::OK) { - ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - switch (-err) { - case ENOMEM: - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; - break; - default: - result = VK_ERROR_SURFACE_LOST_KHR; - break; + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + img.buffer = nullptr; + img.dequeued = false; + + result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ for deferred swapchain image failed: %u", result); + break; } - break; } - img.buffer = buffer; - img.dequeued = true; - - image_create.extent = - VkExtent3D{static_cast(img.buffer->width), - static_cast(img.buffer->height), - 1}; - image_native_buffer.handle = img.buffer->handle; - image_native_buffer.stride = img.buffer->stride; - image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = int(img.buffer->usage); - android_convertGralloc0To1Usage(int(img.buffer->usage), - &image_native_buffer.usage2.producer, - &image_native_buffer.usage2.consumer); - image_native_buffer.usage3 = img.buffer->usage; - - ATRACE_BEGIN("CreateImage"); - result = - dispatch.CreateImage(device, &image_create, nullptr, &img.image); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ native buffer failed: %u", result); - break; + } else { + // -- Dequeue all buffers and create a VkImage for each -- + // Any failures during or after this must cancel the dequeued buffers. + + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + + ANativeWindowBuffer* buffer; + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { + ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; + } + break; + } + img.buffer = buffer; + img.dequeued = true; + + image_native_buffer.handle = img.buffer->handle; + image_native_buffer.stride = img.buffer->stride; + image_native_buffer.format = img.buffer->format; + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), + &image_native_buffer.usage2.producer, + &image_native_buffer.usage2.consumer); + image_native_buffer.usage3 = img.buffer->usage; + image_create.pNext = &image_native_buffer; + + ATRACE_BEGIN("CreateImage"); + result = + dispatch.CreateImage(device, &image_create, nullptr, &img.image); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ native buffer failed: %u", result); + break; + } } - } - // -- Cancel all buffers, returning them to the queue -- - // If an error occurred before, also destroy the VkImage and release the - // buffer reference. Otherwise, we retain a strong reference to the buffer. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - if (!swapchain->shared) { - window->cancelBuffer(window, img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; + // -- Cancel all buffers, returning them to the queue -- + // If an error occurred before, also destroy the VkImage and release the + // buffer reference. Otherwise, we retain a strong reference to the buffer. + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; + } } } } @@ -1756,6 +1865,64 @@ VkResult AcquireNextImageKHR(VkDevice device, break; } } + + // If this is a deferred alloc swapchain, this may be the first time we've + // seen a particular buffer. If so, there should be an empty slot. Find it, + // and bind the gralloc buffer to the VkImage for that slot. If there is no + // empty slot, then we dequeued an unexpected buffer. Non-deferred swapchains + // will also take this path, but will never have an empty slot since we + // populated them all upfront. + if (idx == swapchain.num_images) { + for (idx = 0; idx < swapchain.num_images; idx++) { + if (!swapchain.images[idx].buffer) { + // Note: this structure is technically required for + // Vulkan correctness, even though the driver is probably going + // to use everything from the VkNativeBufferANDROID below. + // This is kindof silly, but it's how we did the ANB + // side of VK_KHR_swapchain v69, so we're stuck with it unless + // we want to go tinkering with the ANB spec some more. + VkBindImageMemorySwapchainInfoKHR bimsi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, + .pNext = nullptr, + .swapchain = swapchain_handle, + .imageIndex = idx, + }; + VkNativeBufferANDROID nb = { + .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, + .pNext = &bimsi, + .handle = buffer->handle, + .stride = buffer->stride, + .format = buffer->format, + .usage = int(buffer->usage), + }; + VkBindImageMemoryInfo bimi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + .pNext = &nb, + .image = swapchain.images[idx].image, + .memory = VK_NULL_HANDLE, + .memoryOffset = 0, + }; + result = GetData(device).driver.BindImageMemory2(device, 1, &bimi); + if (result != VK_SUCCESS) { + // This shouldn't really happen. If it does, something is probably + // unrecoverably wrong with the swapchain and its images. Cancel + // the buffer and declare the swapchain broken. + ALOGE("failed to do deferred gralloc buffer bind"); + window->cancelBuffer(window, buffer, fence_fd); + return VK_ERROR_OUT_OF_DATE_KHR; + } + + swapchain.images[idx].dequeued = true; + swapchain.images[idx].dequeue_fence = fence_fd; + swapchain.images[idx].buffer = buffer; + break; + } + } + } + + // The buffer doesn't match any slot. This shouldn't normally happen, but is + // possible if the bufferqueue is reconfigured behind libvulkan's back. If this + // happens, just declare the swapchain to be broken and the app will recreate it. if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); @@ -1881,12 +2048,32 @@ static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTime } } +// EXT_swapchain_maintenance1 present mode change +static bool SetSwapchainPresentMode(ANativeWindow *window, VkPresentModeKHR mode) { + // There is no dynamic switching between non-shared present modes. + // All we support is switching between demand and continuous refresh. + if (!IsSharedPresentMode(mode)) + return true; + + int err = native_window_set_auto_refresh(window, + mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + if (err != android::OK) { + ALOGE("native_window_set_auto_refresh() failed: %s (%d)", + strerror(-err), err); + return false; + } + + return true; +} + static VkResult PresentOneSwapchain( VkQueue queue, Swapchain& swapchain, uint32_t imageIndex, const VkPresentRegionKHR *pRegion, const VkPresentTimeGOOGLE *pTime, + VkFence presentFence, + const VkPresentModeKHR *pPresentMode, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores) { @@ -1917,12 +2104,33 @@ static VkResult PresentOneSwapchain( ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { + if (presentFence != VK_NULL_HANDLE) { + int fence_copy = fence < 0 ? -1 : dup(fence); + VkImportFenceFdInfoKHR iffi = { + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, + nullptr, + presentFence, + VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + fence_copy, + }; + if (VK_SUCCESS != dispatch.ImportFenceFdKHR(device, &iffi) && fence_copy >= 0) { + // ImportFenceFdKHR takes ownership only if it succeeds + close(fence_copy); + } + } + if (pRegion) { SetSwapchainSurfaceDamage(window, pRegion); } if (pTime) { SetSwapchainFrameTimestamp(swapchain, pTime); } + if (pPresentMode) { + if (!SetSwapchainPresentMode(window, *pPresentMode)) + swapchain_result = WorstPresentResult(swapchain_result, + VK_ERROR_SURFACE_LOST_KHR); + } err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error @@ -2003,6 +2211,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Look at the pNext chain for supported extension structs: const VkPresentRegionsKHR* present_regions = nullptr; const VkPresentTimesInfoGOOGLE* present_times = nullptr; + const VkSwapchainPresentFenceInfoEXT* present_fences = nullptr; + const VkSwapchainPresentModeInfoEXT* present_modes = nullptr; + const VkPresentRegionsKHR* next = reinterpret_cast(present_info->pNext); while (next) { @@ -2014,6 +2225,14 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times = reinterpret_cast(next); break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: + present_fences = + reinterpret_cast(next); + break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: + present_modes = + reinterpret_cast(next); + break; default: ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", next->sType); @@ -2029,6 +2248,15 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times->swapchainCount != present_info->swapchainCount, "VkPresentTimesInfoGOOGLE::swapchainCount != " "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_fences && + present_fences->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentFenceInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_modes && + present_modes->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentModeInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + const VkPresentRegionKHR* regions = (present_regions) ? present_regions->pRegions : nullptr; const VkPresentTimeGOOGLE* times = @@ -2044,6 +2272,8 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info->pImageIndices[sc], (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr, times ? ×[sc] : nullptr, + present_fences ? present_fences->pFences[sc] : VK_NULL_HANDLE, + present_modes ? &present_modes->pPresentModes[sc] : nullptr, present_info->waitSemaphoreCount, present_info->pWaitSemaphores); @@ -2268,5 +2498,35 @@ VkResult BindImageMemory2KHR(VkDevice device, out_bind_infos.empty() ? pBindInfos : out_bind_infos.data()); } +VKAPI_ATTR +VkResult ReleaseSwapchainImagesEXT(VkDevice /*device*/, + const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + ATRACE_CALL(); + + Swapchain& swapchain = *SwapchainFromHandle(pReleaseInfo->swapchain); + ANativeWindow* window = swapchain.surface.window.get(); + + // If in shared present mode, don't actually release the image back to the BQ. + // Both sides share it forever. + if (swapchain.shared) + return VK_SUCCESS; + + for (uint32_t i = 0; i < pReleaseInfo->imageIndexCount; i++) { + Swapchain::Image& img = swapchain.images[pReleaseInfo->pImageIndices[i]]; + window->cancelBuffer(window, img.buffer.get(), img.dequeue_fence); + + // cancelBuffer has taken ownership of the dequeue fence + img.dequeue_fence = -1; + // if we're still holding a release fence, get rid of it now + if (img.release_fence >= 0) { + close(img.release_fence); + img.release_fence = -1; + } + img.dequeued = false; + } + + return VK_SUCCESS; +} + } // namespace driver } // namespace vulkan diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index 4912ef1a33..280fe9b5a3 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -46,6 +46,7 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice ph VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult ReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); // clang-format on } // namespace driver diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index af56764a21..78b550c202 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -35,6 +35,8 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_KHR_surface', 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', + 'VK_EXT_swapchain_maintenance1', + 'VK_EXT_surface_maintenance1', ] # Extensions known to vulkan::driver level. @@ -46,6 +48,7 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 'VK_KHR_external_memory_capabilities', 'VK_KHR_external_semaphore_capabilities', 'VK_KHR_external_fence_capabilities', + 'VK_KHR_external_fence_fd', ] # Functions needed at vulkan::driver level. @@ -112,6 +115,9 @@ _NEEDED_COMMANDS = [ # For promoted VK_KHR_external_fence_capabilities 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalFencePropertiesKHR', + + # VK_KHR_swapchain_maintenance1 requirement + 'vkImportFenceFdKHR', ] # Functions intercepted at vulkan::driver level. -- cgit v1.2.3-59-g8ed1b From 334a4105c8d52848c48c4c843a33522423010c4c Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Thu, 22 Dec 2022 18:51:09 +0000 Subject: Revert "Reland: "libvulkan: Implement EXT_swapchain_maintenance1""" This reverts commit 2dcb4f0064d3d6a01105d2c8a12368c347d85227. Reason for revert: Appears to cause HWASAN failures. See b/263442454, b/263446408, b/263444233, and b/263445588. Change-Id: I6de0027ae2db803445a66de575dda97826b8eb6a --- vulkan/libvulkan/driver.cpp | 62 +--- vulkan/libvulkan/driver_gen.cpp | 20 -- vulkan/libvulkan/driver_gen.h | 4 - vulkan/libvulkan/swapchain.cpp | 624 +++++++++++-------------------------- vulkan/libvulkan/swapchain.h | 1 - vulkan/scripts/driver_generator.py | 6 - 6 files changed, 183 insertions(+), 534 deletions(-) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 273cdd547e..9ed992b230 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -636,7 +636,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::GOOGLE_surfaceless_query: - case ProcHook::EXT_surface_maintenance1: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -658,11 +657,9 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_shared_presentable_image: case ProcHook::KHR_swapchain: case ProcHook::EXT_hdr_metadata: - case ProcHook::EXT_swapchain_maintenance1: case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: - case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: case ProcHook::EXTENSION_CORE_1_2: @@ -693,22 +690,16 @@ void CreateInfoWrapper::FilterExtension(const char* name) { ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::KHR_incremental_present: - case ProcHook::KHR_shared_presentable_image: case ProcHook::GOOGLE_display_timing: + case ProcHook::KHR_shared_presentable_image: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; - case ProcHook::EXT_swapchain_maintenance1: - // map VK_KHR_swapchain_maintenance1 to KHR_external_fence_fd - name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; - ext_bit = ProcHook::KHR_external_fence_fd; - break; case ProcHook::EXT_hdr_metadata: case ProcHook::KHR_bind_memory2: hook_extensions_.set(ext_bit); break; case ProcHook::ANDROID_external_memory_android_hardware_buffer: - case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_UNKNOWN: // Extensions we don't need to do anything about at this level break; @@ -724,7 +715,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: - case ProcHook::EXT_surface_maintenance1: case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: @@ -757,18 +747,10 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (strcmp(name, props.extensionName) != 0) continue; - if (ext_bit != ProcHook::EXTENSION_UNKNOWN && - hal_extensions_.test(ext_bit)) { - ALOGI("CreateInfoWrapper::FilterExtension: already have '%s'.", name); - continue; - } - filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); - if (ext_bit == ProcHook::KHR_external_fence_fd) - hook_extensions_.set(ProcHook::EXT_swapchain_maintenance1); hal_extensions_.set(ext_bit); } @@ -958,9 +940,6 @@ VkResult EnumerateInstanceExtensionProperties( VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); - loader_extensions.push_back({ - VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, - VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, @@ -1093,33 +1072,6 @@ VkResult GetAndroidNativeBufferSpecVersion9Support( return result; } -bool CanSupportSwapchainMaintenance1Extension(VkPhysicalDevice physicalDevice) { - const auto& driver = GetData(physicalDevice).driver; - if (!driver.GetPhysicalDeviceExternalFenceProperties) - return false; - - // Requires support for external fences imported from sync fds. - // This is _almost_ universal on Android, but may be missing on - // some extremely old drivers, or on strange implementations like - // cuttlefish. - VkPhysicalDeviceExternalFenceInfo fenceInfo = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - nullptr, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT - }; - VkExternalFenceProperties fenceProperties = { - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, - nullptr, - 0, 0, 0 - }; - - GetPhysicalDeviceExternalFenceProperties(physicalDevice, &fenceInfo, &fenceProperties); - if (fenceProperties.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT) - return true; - - return false; -} - VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, @@ -1197,12 +1149,6 @@ VkResult EnumerateDeviceExtensionProperties( VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION}); } - if (CanSupportSwapchainMaintenance1Extension(physicalDevice)) { - loader_extensions.push_back({ - VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, - VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION}); - } - // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( @@ -1698,12 +1644,6 @@ void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, imageCompressionControlSwapchainInChain = true; } break; - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { - auto smf = reinterpret_cast( - pFeats); - smf->swapchainMaintenance1 = true; - } break; - default: break; } diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 798af5c6a6..de98aa7e61 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -162,15 +162,6 @@ VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 } } -VKAPI_ATTR VkResult checkedReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { - if (GetData(device).hook_extensions[ProcHook::EXT_swapchain_maintenance1]) { - return ReleaseSwapchainImagesEXT(device, pReleaseInfo); - } else { - Logger(device).Err(device, "VK_EXT_swapchain_maintenance1 not enabled. vkReleaseSwapchainImagesEXT not executed."); - return VK_SUCCESS; - } -} - // clang-format on const ProcHook g_proc_hooks[] = { @@ -553,13 +544,6 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast(QueueSubmit), nullptr, }, - { - "vkReleaseSwapchainImagesEXT", - ProcHook::DEVICE, - ProcHook::EXT_swapchain_maintenance1, - reinterpret_cast(ReleaseSwapchainImagesEXT), - reinterpret_cast(checkedReleaseSwapchainImagesEXT), - }, { "vkSetHdrMetadataEXT", ProcHook::DEVICE, @@ -596,8 +580,6 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; - if (strcmp(name, "VK_EXT_swapchain_maintenance1") == 0) return ProcHook::EXT_swapchain_maintenance1; - if (strcmp(name, "VK_EXT_surface_maintenance1") == 0) return ProcHook::EXT_surface_maintenance1; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2; @@ -605,7 +587,6 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities; if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities; if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities; - if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } @@ -685,7 +666,6 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); - INIT_PROC_EXT(KHR_external_fence_fd, true, dev, ImportFenceFdKHR); INIT_PROC(false, dev, BindImageMemory2); INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 31ba04ba1f..2f60086a27 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -49,8 +49,6 @@ struct ProcHook { KHR_surface, KHR_surface_protected_capabilities, KHR_swapchain, - EXT_swapchain_maintenance1, - EXT_surface_maintenance1, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, KHR_get_physical_device_properties2, @@ -58,7 +56,6 @@ struct ProcHook { KHR_external_memory_capabilities, KHR_external_semaphore_capabilities, KHR_external_fence_capabilities, - KHR_external_fence_fd, EXTENSION_CORE_1_0, EXTENSION_CORE_1_1, @@ -121,7 +118,6 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; - PFN_vkImportFenceFdKHR ImportFenceFdKHR; PFN_vkBindImageMemory2 BindImageMemory2; PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 1bff50dd7f..b03200e4a7 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -291,9 +291,6 @@ struct Swapchain { release_fence(-1), dequeued(false) {} VkImage image; - // If the image is bound to memory, an sp to the underlying gralloc buffer. - // Otherwise, nullptr; the image will be bound to memory as part of - // AcquireNextImage. android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is @@ -659,40 +656,100 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); - // Implement in terms of GetPhysicalDeviceSurfaceCapabilities2KHR + int err; + int width, height; + int transform_hint; + int max_buffer_count; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(pdev); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 0xFFFFFFFF; + height = 0xFFFFFFFF; + transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + capabilities->minImageCount = 0xFFFFFFFF; + capabilities->maxImageCount = 0xFFFFFFFF; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - VkPhysicalDeviceSurfaceInfo2KHR info2 = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, - nullptr, - surface - }; + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } - VkSurfaceCapabilities2KHR caps2 = { - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, - nullptr, - {}, - }; + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } - VkResult result = GetPhysicalDeviceSurfaceCapabilities2KHR(pdev, &info2, &caps2); - *capabilities = caps2.surfaceCapabilities; - return result; -} + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + capabilities->minImageCount = std::min(max_buffer_count, 3); + capabilities->maxImageCount = static_cast(max_buffer_count); + } -// Does the call-twice and VK_INCOMPLETE handling for querying lists -// of things, where we already have the full set built in a vector. -template -VkResult CopyWithIncomplete(std::vector const& things, - T* callerPtr, uint32_t* callerCount) { - VkResult result = VK_SUCCESS; - if (callerPtr) { - if (things.size() > *callerCount) - result = VK_INCOMPLETE; - *callerCount = std::min(uint32_t(things.size()), *callerCount); - std::copy(things.begin(), things.begin() + *callerCount, callerPtr); - } else { - *callerCount = things.size(); + capabilities->currentExtent = + VkExtent2D{static_cast(width), static_cast(height)}; + + // TODO(http://b/134182502): Figure out what the max extent should be. + capabilities->minImageExtent = VkExtent2D{1, 1}; + capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + + if (capabilities->maxImageExtent.height < + capabilities->currentExtent.height) { + capabilities->maxImageExtent.height = + capabilities->currentExtent.height; } - return result; + + if (capabilities->maxImageExtent.width < + capabilities->currentExtent.width) { + capabilities->maxImageExtent.width = capabilities->currentExtent.width; + } + + capabilities->maxImageArrayLayers = 1; + + capabilities->supportedTransforms = kSupportedTransforms; + capabilities->currentTransform = + TranslateNativeToVulkanTransform(transform_hint); + + // On Android, window composition is a WindowManager property, not something + // associated with the bufferqueue. It can't be changed from here. + capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + + capabilities->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + return VK_SUCCESS; } VKAPI_ATTR @@ -825,7 +882,21 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // Android users. This includes the ANGLE team (a layered implementation of // OpenGL-ES). - return CopyWithIncomplete(all_formats, formats, count); + VkResult result = VK_SUCCESS; + if (formats) { + uint32_t transfer_count = all_formats.size(); + if (transfer_count > *count) { + transfer_count = *count; + result = VK_INCOMPLETE; + } + std::copy(all_formats.begin(), all_formats.begin() + transfer_count, + formats); + *count = transfer_count; + } else { + *count = all_formats.size(); + } + + return result; } VKAPI_ATTR @@ -835,134 +906,19 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { ATRACE_CALL(); - auto surface = pSurfaceInfo->surface; - auto capabilities = &pSurfaceCapabilities->surfaceCapabilities; - - VkSurfacePresentModeEXT const *pPresentMode = nullptr; - for (auto pNext = reinterpret_cast(pSurfaceInfo->pNext); - pNext; pNext = reinterpret_cast(pNext->pNext)) { - switch (pNext->sType) { - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: - pPresentMode = reinterpret_cast(pNext); - break; - - default: - break; - } - } + VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR( + physicalDevice, pSurfaceInfo->surface, + &pSurfaceCapabilities->surfaceCapabilities); - int err; - int width, height; - int transform_hint; - int max_buffer_count; - if (surface == VK_NULL_HANDLE) { - const InstanceData& instance_data = GetData(physicalDevice); - ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; - bool surfaceless_enabled = - instance_data.hook_extensions.test(surfaceless); - if (!surfaceless_enabled) { - // It is an error to pass a surface==VK_NULL_HANDLE unless the - // VK_GOOGLE_surfaceless_query extension is enabled - return VK_ERROR_SURFACE_LOST_KHR; - } - // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this - // extension for this function is for - // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following - // four values cannot be known without a surface. Default values will - // be supplied anyway, but cannot be relied upon. - width = 0xFFFFFFFF; - height = 0xFFFFFFFF; - transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - capabilities->minImageCount = 0xFFFFFFFF; - capabilities->maxImageCount = 0xFFFFFFFF; - } else { - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities; + while (caps->pNext) { + caps = reinterpret_cast(caps->pNext); - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, - &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, - &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - if (pPresentMode && IsSharedPresentMode(pPresentMode->presentMode)) { - capabilities->minImageCount = 1; - capabilities->maxImageCount = 1; - } else if (pPresentMode && pPresentMode->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - // TODO: use undequeued buffer requirement for more precise bound - capabilities->minImageCount = std::min(max_buffer_count, 4); - capabilities->maxImageCount = static_cast(max_buffer_count); - } else { - // TODO: if we're able to, provide better bounds on the number of buffers - // for other modes as well. - capabilities->minImageCount = std::min(max_buffer_count, 3); - capabilities->maxImageCount = static_cast(max_buffer_count); - } - } - - capabilities->currentExtent = - VkExtent2D{static_cast(width), static_cast(height)}; - - // TODO(http://b/134182502): Figure out what the max extent should be. - capabilities->minImageExtent = VkExtent2D{1, 1}; - capabilities->maxImageExtent = VkExtent2D{4096, 4096}; - - if (capabilities->maxImageExtent.height < - capabilities->currentExtent.height) { - capabilities->maxImageExtent.height = - capabilities->currentExtent.height; - } - - if (capabilities->maxImageExtent.width < - capabilities->currentExtent.width) { - capabilities->maxImageExtent.width = capabilities->currentExtent.width; - } - - capabilities->maxImageArrayLayers = 1; - - capabilities->supportedTransforms = kSupportedTransforms; - capabilities->currentTransform = - TranslateNativeToVulkanTransform(transform_hint); - - // On Android, window composition is a WindowManager property, not something - // associated with the bufferqueue. It can't be changed from here. - capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - - capabilities->supportedUsageFlags = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - - for (auto pNext = reinterpret_cast(pSurfaceCapabilities->pNext); - pNext; pNext = reinterpret_cast(pNext->pNext)) { - - switch (pNext->sType) { + switch (caps->sType) { case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: { VkSharedPresentSurfaceCapabilitiesKHR* shared_caps = - reinterpret_cast(pNext); + reinterpret_cast( + caps); // Claim same set of usage flags are supported for // shared present modes as for other modes. shared_caps->sharedPresentSupportedUsageFlags = @@ -972,64 +928,17 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { VkSurfaceProtectedCapabilitiesKHR* protected_caps = - reinterpret_cast(pNext); + reinterpret_cast(caps); protected_caps->supportsProtected = VK_TRUE; } break; - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { - VkSurfacePresentScalingCapabilitiesEXT* scaling_caps = - reinterpret_cast(pNext); - // By default, Android stretches the buffer to fit the window, - // without preserving aspect ratio. Other modes are technically possible - // but consult with CoGS team before exposing them here! - scaling_caps->supportedPresentScaling = VK_PRESENT_SCALING_STRETCH_BIT_EXT; - - // Since we always scale, we don't support any gravity. - scaling_caps->supportedPresentGravityX = 0; - scaling_caps->supportedPresentGravityY = 0; - - // Scaled image limits are just the basic image limits - scaling_caps->minScaledImageExtent = capabilities->minImageExtent; - scaling_caps->maxScaledImageExtent = capabilities->maxImageExtent; - } break; - - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { - VkSurfacePresentModeCompatibilityEXT* mode_caps = - reinterpret_cast(pNext); - - ALOG_ASSERT(pPresentMode, - "querying VkSurfacePresentModeCompatibilityEXT " - "requires VkSurfacePresentModeEXT to be provided"); - std::vector compatibleModes; - compatibleModes.push_back(pPresentMode->presentMode); - - switch (pPresentMode->presentMode) { - // Shared modes are both compatible with each other. - case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: - compatibleModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); - break; - case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: - compatibleModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR); - break; - default: - // Other modes are only compatible with themselves. - // TODO: consider whether switching between FIFO and MAILBOX is reasonable - break; - } - - // Note: this does not generate VK_INCOMPLETE since we're nested inside - // a larger query and there would be no way to determine exactly where it came from. - CopyWithIncomplete(compatibleModes, mode_caps->pPresentModes, - &mode_caps->presentModeCount); - } break; - default: // Ignore all other extension structs break; } } - return VK_SUCCESS; + return result; } VKAPI_ATTR @@ -1188,7 +1097,18 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); } - return CopyWithIncomplete(present_modes, modes, count); + uint32_t num_modes = uint32_t(present_modes.size()); + + VkResult result = VK_SUCCESS; + if (modes) { + if (*count < num_modes) + result = VK_INCOMPLETE; + *count = std::min(*count, num_modes); + std::copy_n(present_modes.data(), *count, modes); + } else { + *count = num_modes; + } + return result; } VKAPI_ATTR @@ -1474,7 +1394,8 @@ VkResult CreateSwapchainKHR(VkDevice device, } VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (IsSharedPresentMode(create_info->presentMode)) { + if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; err = native_window_set_shared_buffer_mode(window, true); if (err != android::OK) { @@ -1624,6 +1545,8 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform)); + // -- Dequeue all buffers and create a VkImage for each -- + // Any failures during or after this must cancel the dequeued buffers. VkSwapchainImageCreateInfoANDROID swapchain_image_create = { #pragma clang diagnostic push @@ -1640,18 +1563,13 @@ VkResult CreateSwapchainKHR(VkDevice device, #pragma clang diagnostic pop .pNext = &swapchain_image_create, }; - VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = nullptr, + .pNext = &image_native_buffer, .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, - .extent = { - create_info->imageExtent.width, - create_info->imageExtent.height, - 1 - }, + .extent = {0, 0, 1}, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -1662,87 +1580,60 @@ VkResult CreateSwapchainKHR(VkDevice device, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; - // Note: don't do deferred allocation for shared present modes. There's only one buffer - // involved so very little benefit. - if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) && - !IsSharedPresentMode(create_info->presentMode)) { - // Don't want to touch the underlying gralloc buffers yet; - // instead just create unbound VkImages which will later be bound to memory inside - // AcquireNextImage. - VkImageSwapchainCreateInfoKHR image_swapchain_create = { - .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = nullptr, - .swapchain = HandleFromSwapchain(swapchain), - }; - image_create.pNext = &image_swapchain_create; - - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - img.buffer = nullptr; - img.dequeued = false; + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; - result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ for deferred swapchain image failed: %u", result); - break; + ANativeWindowBuffer* buffer; + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { + ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; } + break; } - } else { - // -- Dequeue all buffers and create a VkImage for each -- - // Any failures during or after this must cancel the dequeued buffers. - - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - - ANativeWindowBuffer* buffer; - err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); - if (err != android::OK) { - ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - switch (-err) { - case ENOMEM: - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; - break; - default: - result = VK_ERROR_SURFACE_LOST_KHR; - break; - } - break; - } - img.buffer = buffer; - img.dequeued = true; - - image_native_buffer.handle = img.buffer->handle; - image_native_buffer.stride = img.buffer->stride; - image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = int(img.buffer->usage); - android_convertGralloc0To1Usage(int(img.buffer->usage), - &image_native_buffer.usage2.producer, - &image_native_buffer.usage2.consumer); - image_native_buffer.usage3 = img.buffer->usage; - image_create.pNext = &image_native_buffer; - - ATRACE_BEGIN("CreateImage"); - result = - dispatch.CreateImage(device, &image_create, nullptr, &img.image); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ native buffer failed: %u", result); - break; - } + img.buffer = buffer; + img.dequeued = true; + + image_create.extent = + VkExtent3D{static_cast(img.buffer->width), + static_cast(img.buffer->height), + 1}; + image_native_buffer.handle = img.buffer->handle; + image_native_buffer.stride = img.buffer->stride; + image_native_buffer.format = img.buffer->format; + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), + &image_native_buffer.usage2.producer, + &image_native_buffer.usage2.consumer); + image_native_buffer.usage3 = img.buffer->usage; + + ATRACE_BEGIN("CreateImage"); + result = + dispatch.CreateImage(device, &image_create, nullptr, &img.image); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ native buffer failed: %u", result); + break; } + } - // -- Cancel all buffers, returning them to the queue -- - // If an error occurred before, also destroy the VkImage and release the - // buffer reference. Otherwise, we retain a strong reference to the buffer. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - if (!swapchain->shared) { - window->cancelBuffer(window, img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; - } + // -- Cancel all buffers, returning them to the queue -- + // If an error occurred before, also destroy the VkImage and release the + // buffer reference. Otherwise, we retain a strong reference to the buffer. + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; } } } @@ -1865,64 +1756,6 @@ VkResult AcquireNextImageKHR(VkDevice device, break; } } - - // If this is a deferred alloc swapchain, this may be the first time we've - // seen a particular buffer. If so, there should be an empty slot. Find it, - // and bind the gralloc buffer to the VkImage for that slot. If there is no - // empty slot, then we dequeued an unexpected buffer. Non-deferred swapchains - // will also take this path, but will never have an empty slot since we - // populated them all upfront. - if (idx == swapchain.num_images) { - for (idx = 0; idx < swapchain.num_images; idx++) { - if (!swapchain.images[idx].buffer) { - // Note: this structure is technically required for - // Vulkan correctness, even though the driver is probably going - // to use everything from the VkNativeBufferANDROID below. - // This is kindof silly, but it's how we did the ANB - // side of VK_KHR_swapchain v69, so we're stuck with it unless - // we want to go tinkering with the ANB spec some more. - VkBindImageMemorySwapchainInfoKHR bimsi = { - .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, - .pNext = nullptr, - .swapchain = swapchain_handle, - .imageIndex = idx, - }; - VkNativeBufferANDROID nb = { - .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, - .pNext = &bimsi, - .handle = buffer->handle, - .stride = buffer->stride, - .format = buffer->format, - .usage = int(buffer->usage), - }; - VkBindImageMemoryInfo bimi = { - .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - .pNext = &nb, - .image = swapchain.images[idx].image, - .memory = VK_NULL_HANDLE, - .memoryOffset = 0, - }; - result = GetData(device).driver.BindImageMemory2(device, 1, &bimi); - if (result != VK_SUCCESS) { - // This shouldn't really happen. If it does, something is probably - // unrecoverably wrong with the swapchain and its images. Cancel - // the buffer and declare the swapchain broken. - ALOGE("failed to do deferred gralloc buffer bind"); - window->cancelBuffer(window, buffer, fence_fd); - return VK_ERROR_OUT_OF_DATE_KHR; - } - - swapchain.images[idx].dequeued = true; - swapchain.images[idx].dequeue_fence = fence_fd; - swapchain.images[idx].buffer = buffer; - break; - } - } - } - - // The buffer doesn't match any slot. This shouldn't normally happen, but is - // possible if the bufferqueue is reconfigured behind libvulkan's back. If this - // happens, just declare the swapchain to be broken and the app will recreate it. if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); @@ -2048,32 +1881,12 @@ static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTime } } -// EXT_swapchain_maintenance1 present mode change -static bool SetSwapchainPresentMode(ANativeWindow *window, VkPresentModeKHR mode) { - // There is no dynamic switching between non-shared present modes. - // All we support is switching between demand and continuous refresh. - if (!IsSharedPresentMode(mode)) - return true; - - int err = native_window_set_auto_refresh(window, - mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); - if (err != android::OK) { - ALOGE("native_window_set_auto_refresh() failed: %s (%d)", - strerror(-err), err); - return false; - } - - return true; -} - static VkResult PresentOneSwapchain( VkQueue queue, Swapchain& swapchain, uint32_t imageIndex, const VkPresentRegionKHR *pRegion, const VkPresentTimeGOOGLE *pTime, - VkFence presentFence, - const VkPresentModeKHR *pPresentMode, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores) { @@ -2104,33 +1917,12 @@ static VkResult PresentOneSwapchain( ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { - if (presentFence != VK_NULL_HANDLE) { - int fence_copy = fence < 0 ? -1 : dup(fence); - VkImportFenceFdInfoKHR iffi = { - VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, - nullptr, - presentFence, - VK_FENCE_IMPORT_TEMPORARY_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, - fence_copy, - }; - if (VK_SUCCESS != dispatch.ImportFenceFdKHR(device, &iffi) && fence_copy >= 0) { - // ImportFenceFdKHR takes ownership only if it succeeds - close(fence_copy); - } - } - if (pRegion) { SetSwapchainSurfaceDamage(window, pRegion); } if (pTime) { SetSwapchainFrameTimestamp(swapchain, pTime); } - if (pPresentMode) { - if (!SetSwapchainPresentMode(window, *pPresentMode)) - swapchain_result = WorstPresentResult(swapchain_result, - VK_ERROR_SURFACE_LOST_KHR); - } err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error @@ -2211,9 +2003,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Look at the pNext chain for supported extension structs: const VkPresentRegionsKHR* present_regions = nullptr; const VkPresentTimesInfoGOOGLE* present_times = nullptr; - const VkSwapchainPresentFenceInfoEXT* present_fences = nullptr; - const VkSwapchainPresentModeInfoEXT* present_modes = nullptr; - const VkPresentRegionsKHR* next = reinterpret_cast(present_info->pNext); while (next) { @@ -2225,14 +2014,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times = reinterpret_cast(next); break; - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: - present_fences = - reinterpret_cast(next); - break; - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: - present_modes = - reinterpret_cast(next); - break; default: ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", next->sType); @@ -2248,15 +2029,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times->swapchainCount != present_info->swapchainCount, "VkPresentTimesInfoGOOGLE::swapchainCount != " "VkPresentInfo::swapchainCount"); - ALOGV_IF(present_fences && - present_fences->swapchainCount != present_info->swapchainCount, - "VkSwapchainPresentFenceInfoEXT::swapchainCount != " - "VkPresentInfo::swapchainCount"); - ALOGV_IF(present_modes && - present_modes->swapchainCount != present_info->swapchainCount, - "VkSwapchainPresentModeInfoEXT::swapchainCount != " - "VkPresentInfo::swapchainCount"); - const VkPresentRegionKHR* regions = (present_regions) ? present_regions->pRegions : nullptr; const VkPresentTimeGOOGLE* times = @@ -2272,8 +2044,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info->pImageIndices[sc], (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr, times ? ×[sc] : nullptr, - present_fences ? present_fences->pFences[sc] : VK_NULL_HANDLE, - present_modes ? &present_modes->pPresentModes[sc] : nullptr, present_info->waitSemaphoreCount, present_info->pWaitSemaphores); @@ -2498,35 +2268,5 @@ VkResult BindImageMemory2KHR(VkDevice device, out_bind_infos.empty() ? pBindInfos : out_bind_infos.data()); } -VKAPI_ATTR -VkResult ReleaseSwapchainImagesEXT(VkDevice /*device*/, - const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { - ATRACE_CALL(); - - Swapchain& swapchain = *SwapchainFromHandle(pReleaseInfo->swapchain); - ANativeWindow* window = swapchain.surface.window.get(); - - // If in shared present mode, don't actually release the image back to the BQ. - // Both sides share it forever. - if (swapchain.shared) - return VK_SUCCESS; - - for (uint32_t i = 0; i < pReleaseInfo->imageIndexCount; i++) { - Swapchain::Image& img = swapchain.images[pReleaseInfo->pImageIndices[i]]; - window->cancelBuffer(window, img.buffer.get(), img.dequeue_fence); - - // cancelBuffer has taken ownership of the dequeue fence - img.dequeue_fence = -1; - // if we're still holding a release fence, get rid of it now - if (img.release_fence >= 0) { - close(img.release_fence); - img.release_fence = -1; - } - img.dequeued = false; - } - - return VK_SUCCESS; -} - } // namespace driver } // namespace vulkan diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index 280fe9b5a3..4912ef1a33 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -46,7 +46,6 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice ph VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -VKAPI_ATTR VkResult ReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); // clang-format on } // namespace driver diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index 78b550c202..af56764a21 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -35,8 +35,6 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_KHR_surface', 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', - 'VK_EXT_swapchain_maintenance1', - 'VK_EXT_surface_maintenance1', ] # Extensions known to vulkan::driver level. @@ -48,7 +46,6 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 'VK_KHR_external_memory_capabilities', 'VK_KHR_external_semaphore_capabilities', 'VK_KHR_external_fence_capabilities', - 'VK_KHR_external_fence_fd', ] # Functions needed at vulkan::driver level. @@ -115,9 +112,6 @@ _NEEDED_COMMANDS = [ # For promoted VK_KHR_external_fence_capabilities 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalFencePropertiesKHR', - - # VK_KHR_swapchain_maintenance1 requirement - 'vkImportFenceFdKHR', ] # Functions intercepted at vulkan::driver level. -- cgit v1.2.3-59-g8ed1b From 9d0d9ff3d92bea4584f9b6f14bc2a348268c42b4 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 28 Dec 2022 01:58:31 +0000 Subject: Revert "Revert "Reland: "libvulkan: Implement EXT_swapchain_maintenance1"""" This reverts commit 334a4105c8d52848c48c4c843a33522423010c4c. Reason for revert: all failures tracked to original CL, not the reland. No issues seen now in manual hwasan tests. Change-Id: Icd2f12f18b5f1a77237703983e11bced16cb8865 --- vulkan/libvulkan/driver.cpp | 62 +++- vulkan/libvulkan/driver_gen.cpp | 20 ++ vulkan/libvulkan/driver_gen.h | 4 + vulkan/libvulkan/swapchain.cpp | 624 ++++++++++++++++++++++++++----------- vulkan/libvulkan/swapchain.h | 1 + vulkan/scripts/driver_generator.py | 6 + 6 files changed, 534 insertions(+), 183 deletions(-) (limited to 'vulkan/libvulkan/driver.cpp') diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 9ed992b230..273cdd547e 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -636,6 +636,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::GOOGLE_surfaceless_query: + case ProcHook::EXT_surface_maintenance1: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -657,9 +658,11 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_shared_presentable_image: case ProcHook::KHR_swapchain: case ProcHook::EXT_hdr_metadata: + case ProcHook::EXT_swapchain_maintenance1: case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: case ProcHook::EXTENSION_CORE_1_2: @@ -690,16 +693,22 @@ void CreateInfoWrapper::FilterExtension(const char* name) { ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::KHR_incremental_present: - case ProcHook::GOOGLE_display_timing: case ProcHook::KHR_shared_presentable_image: + case ProcHook::GOOGLE_display_timing: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; + case ProcHook::EXT_swapchain_maintenance1: + // map VK_KHR_swapchain_maintenance1 to KHR_external_fence_fd + name = VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; + ext_bit = ProcHook::KHR_external_fence_fd; + break; case ProcHook::EXT_hdr_metadata: case ProcHook::KHR_bind_memory2: hook_extensions_.set(ext_bit); break; case ProcHook::ANDROID_external_memory_android_hardware_buffer: + case ProcHook::KHR_external_fence_fd: case ProcHook::EXTENSION_UNKNOWN: // Extensions we don't need to do anything about at this level break; @@ -715,6 +724,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: + case ProcHook::EXT_surface_maintenance1: case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: @@ -747,10 +757,18 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (strcmp(name, props.extensionName) != 0) continue; + if (ext_bit != ProcHook::EXTENSION_UNKNOWN && + hal_extensions_.test(ext_bit)) { + ALOGI("CreateInfoWrapper::FilterExtension: already have '%s'.", name); + continue; + } + filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); + if (ext_bit == ProcHook::KHR_external_fence_fd) + hook_extensions_.set(ProcHook::EXT_swapchain_maintenance1); hal_extensions_.set(ext_bit); } @@ -940,6 +958,9 @@ VkResult EnumerateInstanceExtensionProperties( VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); + loader_extensions.push_back({ + VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, @@ -1072,6 +1093,33 @@ VkResult GetAndroidNativeBufferSpecVersion9Support( return result; } +bool CanSupportSwapchainMaintenance1Extension(VkPhysicalDevice physicalDevice) { + const auto& driver = GetData(physicalDevice).driver; + if (!driver.GetPhysicalDeviceExternalFenceProperties) + return false; + + // Requires support for external fences imported from sync fds. + // This is _almost_ universal on Android, but may be missing on + // some extremely old drivers, or on strange implementations like + // cuttlefish. + VkPhysicalDeviceExternalFenceInfo fenceInfo = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + nullptr, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT + }; + VkExternalFenceProperties fenceProperties = { + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + nullptr, + 0, 0, 0 + }; + + GetPhysicalDeviceExternalFenceProperties(physicalDevice, &fenceInfo, &fenceProperties); + if (fenceProperties.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT) + return true; + + return false; +} + VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, @@ -1149,6 +1197,12 @@ VkResult EnumerateDeviceExtensionProperties( VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION}); } + if (CanSupportSwapchainMaintenance1Extension(physicalDevice)) { + loader_extensions.push_back({ + VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, + VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION}); + } + // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( @@ -1644,6 +1698,12 @@ void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, imageCompressionControlSwapchainInChain = true; } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { + auto smf = reinterpret_cast( + pFeats); + smf->swapchainMaintenance1 = true; + } break; + default: break; } diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index de98aa7e61..798af5c6a6 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -162,6 +162,15 @@ VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 } } +VKAPI_ATTR VkResult checkedReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + if (GetData(device).hook_extensions[ProcHook::EXT_swapchain_maintenance1]) { + return ReleaseSwapchainImagesEXT(device, pReleaseInfo); + } else { + Logger(device).Err(device, "VK_EXT_swapchain_maintenance1 not enabled. vkReleaseSwapchainImagesEXT not executed."); + return VK_SUCCESS; + } +} + // clang-format on const ProcHook g_proc_hooks[] = { @@ -544,6 +553,13 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast(QueueSubmit), nullptr, }, + { + "vkReleaseSwapchainImagesEXT", + ProcHook::DEVICE, + ProcHook::EXT_swapchain_maintenance1, + reinterpret_cast(ReleaseSwapchainImagesEXT), + reinterpret_cast(checkedReleaseSwapchainImagesEXT), + }, { "vkSetHdrMetadataEXT", ProcHook::DEVICE, @@ -580,6 +596,8 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; + if (strcmp(name, "VK_EXT_swapchain_maintenance1") == 0) return ProcHook::EXT_swapchain_maintenance1; + if (strcmp(name, "VK_EXT_surface_maintenance1") == 0) return ProcHook::EXT_surface_maintenance1; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2; @@ -587,6 +605,7 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities; if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities; if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities; + if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } @@ -666,6 +685,7 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); + INIT_PROC_EXT(KHR_external_fence_fd, true, dev, ImportFenceFdKHR); INIT_PROC(false, dev, BindImageMemory2); INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 2f60086a27..31ba04ba1f 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -49,6 +49,8 @@ struct ProcHook { KHR_surface, KHR_surface_protected_capabilities, KHR_swapchain, + EXT_swapchain_maintenance1, + EXT_surface_maintenance1, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, KHR_get_physical_device_properties2, @@ -56,6 +58,7 @@ struct ProcHook { KHR_external_memory_capabilities, KHR_external_semaphore_capabilities, KHR_external_fence_capabilities, + KHR_external_fence_fd, EXTENSION_CORE_1_0, EXTENSION_CORE_1_1, @@ -118,6 +121,7 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; + PFN_vkImportFenceFdKHR ImportFenceFdKHR; PFN_vkBindImageMemory2 BindImageMemory2; PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index b03200e4a7..1bff50dd7f 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -291,6 +291,9 @@ struct Swapchain { release_fence(-1), dequeued(false) {} VkImage image; + // If the image is bound to memory, an sp to the underlying gralloc buffer. + // Otherwise, nullptr; the image will be bound to memory as part of + // AcquireNextImage. android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is @@ -656,100 +659,40 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); - int err; - int width, height; - int transform_hint; - int max_buffer_count; - if (surface == VK_NULL_HANDLE) { - const InstanceData& instance_data = GetData(pdev); - ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; - bool surfaceless_enabled = - instance_data.hook_extensions.test(surfaceless); - if (!surfaceless_enabled) { - // It is an error to pass a surface==VK_NULL_HANDLE unless the - // VK_GOOGLE_surfaceless_query extension is enabled - return VK_ERROR_SURFACE_LOST_KHR; - } - // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this - // extension for this function is for - // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following - // four values cannot be known without a surface. Default values will - // be supplied anyway, but cannot be relied upon. - width = 0xFFFFFFFF; - height = 0xFFFFFFFF; - transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - capabilities->minImageCount = 0xFFFFFFFF; - capabilities->maxImageCount = 0xFFFFFFFF; - } else { - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + // Implement in terms of GetPhysicalDeviceSurfaceCapabilities2KHR - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, - &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, - &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - capabilities->minImageCount = std::min(max_buffer_count, 3); - capabilities->maxImageCount = static_cast(max_buffer_count); - } - - capabilities->currentExtent = - VkExtent2D{static_cast(width), static_cast(height)}; + VkPhysicalDeviceSurfaceInfo2KHR info2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, + nullptr, + surface + }; - // TODO(http://b/134182502): Figure out what the max extent should be. - capabilities->minImageExtent = VkExtent2D{1, 1}; - capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + VkSurfaceCapabilities2KHR caps2 = { + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, + nullptr, + {}, + }; - if (capabilities->maxImageExtent.height < - capabilities->currentExtent.height) { - capabilities->maxImageExtent.height = - capabilities->currentExtent.height; - } + VkResult result = GetPhysicalDeviceSurfaceCapabilities2KHR(pdev, &info2, &caps2); + *capabilities = caps2.surfaceCapabilities; + return result; +} - if (capabilities->maxImageExtent.width < - capabilities->currentExtent.width) { - capabilities->maxImageExtent.width = capabilities->currentExtent.width; +// Does the call-twice and VK_INCOMPLETE handling for querying lists +// of things, where we already have the full set built in a vector. +template +VkResult CopyWithIncomplete(std::vector const& things, + T* callerPtr, uint32_t* callerCount) { + VkResult result = VK_SUCCESS; + if (callerPtr) { + if (things.size() > *callerCount) + result = VK_INCOMPLETE; + *callerCount = std::min(uint32_t(things.size()), *callerCount); + std::copy(things.begin(), things.begin() + *callerCount, callerPtr); + } else { + *callerCount = things.size(); } - - capabilities->maxImageArrayLayers = 1; - - capabilities->supportedTransforms = kSupportedTransforms; - capabilities->currentTransform = - TranslateNativeToVulkanTransform(transform_hint); - - // On Android, window composition is a WindowManager property, not something - // associated with the bufferqueue. It can't be changed from here. - capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - - capabilities->supportedUsageFlags = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - - return VK_SUCCESS; + return result; } VKAPI_ATTR @@ -882,21 +825,7 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // Android users. This includes the ANGLE team (a layered implementation of // OpenGL-ES). - VkResult result = VK_SUCCESS; - if (formats) { - uint32_t transfer_count = all_formats.size(); - if (transfer_count > *count) { - transfer_count = *count; - result = VK_INCOMPLETE; - } - std::copy(all_formats.begin(), all_formats.begin() + transfer_count, - formats); - *count = transfer_count; - } else { - *count = all_formats.size(); - } - - return result; + return CopyWithIncomplete(all_formats, formats, count); } VKAPI_ATTR @@ -906,19 +835,134 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { ATRACE_CALL(); - VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, pSurfaceInfo->surface, - &pSurfaceCapabilities->surfaceCapabilities); + auto surface = pSurfaceInfo->surface; + auto capabilities = &pSurfaceCapabilities->surfaceCapabilities; + + VkSurfacePresentModeEXT const *pPresentMode = nullptr; + for (auto pNext = reinterpret_cast(pSurfaceInfo->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + switch (pNext->sType) { + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: + pPresentMode = reinterpret_cast(pNext); + break; + + default: + break; + } + } - VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities; - while (caps->pNext) { - caps = reinterpret_cast(caps->pNext); + int err; + int width, height; + int transform_hint; + int max_buffer_count; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(physicalDevice); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 0xFFFFFFFF; + height = 0xFFFFFFFF; + transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + capabilities->minImageCount = 0xFFFFFFFF; + capabilities->maxImageCount = 0xFFFFFFFF; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - switch (caps->sType) { + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + if (pPresentMode && IsSharedPresentMode(pPresentMode->presentMode)) { + capabilities->minImageCount = 1; + capabilities->maxImageCount = 1; + } else if (pPresentMode && pPresentMode->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + // TODO: use undequeued buffer requirement for more precise bound + capabilities->minImageCount = std::min(max_buffer_count, 4); + capabilities->maxImageCount = static_cast(max_buffer_count); + } else { + // TODO: if we're able to, provide better bounds on the number of buffers + // for other modes as well. + capabilities->minImageCount = std::min(max_buffer_count, 3); + capabilities->maxImageCount = static_cast(max_buffer_count); + } + } + + capabilities->currentExtent = + VkExtent2D{static_cast(width), static_cast(height)}; + + // TODO(http://b/134182502): Figure out what the max extent should be. + capabilities->minImageExtent = VkExtent2D{1, 1}; + capabilities->maxImageExtent = VkExtent2D{4096, 4096}; + + if (capabilities->maxImageExtent.height < + capabilities->currentExtent.height) { + capabilities->maxImageExtent.height = + capabilities->currentExtent.height; + } + + if (capabilities->maxImageExtent.width < + capabilities->currentExtent.width) { + capabilities->maxImageExtent.width = capabilities->currentExtent.width; + } + + capabilities->maxImageArrayLayers = 1; + + capabilities->supportedTransforms = kSupportedTransforms; + capabilities->currentTransform = + TranslateNativeToVulkanTransform(transform_hint); + + // On Android, window composition is a WindowManager property, not something + // associated with the bufferqueue. It can't be changed from here. + capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + + capabilities->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + for (auto pNext = reinterpret_cast(pSurfaceCapabilities->pNext); + pNext; pNext = reinterpret_cast(pNext->pNext)) { + + switch (pNext->sType) { case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: { VkSharedPresentSurfaceCapabilitiesKHR* shared_caps = - reinterpret_cast( - caps); + reinterpret_cast(pNext); // Claim same set of usage flags are supported for // shared present modes as for other modes. shared_caps->sharedPresentSupportedUsageFlags = @@ -928,17 +972,64 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { VkSurfaceProtectedCapabilitiesKHR* protected_caps = - reinterpret_cast(caps); + reinterpret_cast(pNext); protected_caps->supportsProtected = VK_TRUE; } break; + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { + VkSurfacePresentScalingCapabilitiesEXT* scaling_caps = + reinterpret_cast(pNext); + // By default, Android stretches the buffer to fit the window, + // without preserving aspect ratio. Other modes are technically possible + // but consult with CoGS team before exposing them here! + scaling_caps->supportedPresentScaling = VK_PRESENT_SCALING_STRETCH_BIT_EXT; + + // Since we always scale, we don't support any gravity. + scaling_caps->supportedPresentGravityX = 0; + scaling_caps->supportedPresentGravityY = 0; + + // Scaled image limits are just the basic image limits + scaling_caps->minScaledImageExtent = capabilities->minImageExtent; + scaling_caps->maxScaledImageExtent = capabilities->maxImageExtent; + } break; + + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { + VkSurfacePresentModeCompatibilityEXT* mode_caps = + reinterpret_cast(pNext); + + ALOG_ASSERT(pPresentMode, + "querying VkSurfacePresentModeCompatibilityEXT " + "requires VkSurfacePresentModeEXT to be provided"); + std::vector compatibleModes; + compatibleModes.push_back(pPresentMode->presentMode); + + switch (pPresentMode->presentMode) { + // Shared modes are both compatible with each other. + case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + break; + case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: + compatibleModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR); + break; + default: + // Other modes are only compatible with themselves. + // TODO: consider whether switching between FIFO and MAILBOX is reasonable + break; + } + + // Note: this does not generate VK_INCOMPLETE since we're nested inside + // a larger query and there would be no way to determine exactly where it came from. + CopyWithIncomplete(compatibleModes, mode_caps->pPresentModes, + &mode_caps->presentModeCount); + } break; + default: // Ignore all other extension structs break; } } - return result; + return VK_SUCCESS; } VKAPI_ATTR @@ -1097,18 +1188,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); } - uint32_t num_modes = uint32_t(present_modes.size()); - - VkResult result = VK_SUCCESS; - if (modes) { - if (*count < num_modes) - result = VK_INCOMPLETE; - *count = std::min(*count, num_modes); - std::copy_n(present_modes.data(), *count, modes); - } else { - *count = num_modes; - } - return result; + return CopyWithIncomplete(present_modes, modes, count); } VKAPI_ATTR @@ -1394,8 +1474,7 @@ VkResult CreateSwapchainKHR(VkDevice device, } VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || - create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + if (IsSharedPresentMode(create_info->presentMode)) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; err = native_window_set_shared_buffer_mode(window, true); if (err != android::OK) { @@ -1545,8 +1624,6 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform)); - // -- Dequeue all buffers and create a VkImage for each -- - // Any failures during or after this must cancel the dequeued buffers. VkSwapchainImageCreateInfoANDROID swapchain_image_create = { #pragma clang diagnostic push @@ -1563,13 +1640,18 @@ VkResult CreateSwapchainKHR(VkDevice device, #pragma clang diagnostic pop .pNext = &swapchain_image_create, }; + VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &image_native_buffer, + .pNext = nullptr, .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, - .extent = {0, 0, 1}, + .extent = { + create_info->imageExtent.width, + create_info->imageExtent.height, + 1 + }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -1580,60 +1662,87 @@ VkResult CreateSwapchainKHR(VkDevice device, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; + // Note: don't do deferred allocation for shared present modes. There's only one buffer + // involved so very little benefit. + if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) && + !IsSharedPresentMode(create_info->presentMode)) { + // Don't want to touch the underlying gralloc buffers yet; + // instead just create unbound VkImages which will later be bound to memory inside + // AcquireNextImage. + VkImageSwapchainCreateInfoKHR image_swapchain_create = { + .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .swapchain = HandleFromSwapchain(swapchain), + }; + image_create.pNext = &image_swapchain_create; - ANativeWindowBuffer* buffer; - err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); - if (err != android::OK) { - ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - switch (-err) { - case ENOMEM: - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; - break; - default: - result = VK_ERROR_SURFACE_LOST_KHR; - break; + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + img.buffer = nullptr; + img.dequeued = false; + + result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ for deferred swapchain image failed: %u", result); + break; } - break; } - img.buffer = buffer; - img.dequeued = true; - - image_create.extent = - VkExtent3D{static_cast(img.buffer->width), - static_cast(img.buffer->height), - 1}; - image_native_buffer.handle = img.buffer->handle; - image_native_buffer.stride = img.buffer->stride; - image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = int(img.buffer->usage); - android_convertGralloc0To1Usage(int(img.buffer->usage), - &image_native_buffer.usage2.producer, - &image_native_buffer.usage2.consumer); - image_native_buffer.usage3 = img.buffer->usage; - - ATRACE_BEGIN("CreateImage"); - result = - dispatch.CreateImage(device, &image_create, nullptr, &img.image); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGD("vkCreateImage w/ native buffer failed: %u", result); - break; + } else { + // -- Dequeue all buffers and create a VkImage for each -- + // Any failures during or after this must cancel the dequeued buffers. + + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + + ANativeWindowBuffer* buffer; + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { + ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; + } + break; + } + img.buffer = buffer; + img.dequeued = true; + + image_native_buffer.handle = img.buffer->handle; + image_native_buffer.stride = img.buffer->stride; + image_native_buffer.format = img.buffer->format; + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), + &image_native_buffer.usage2.producer, + &image_native_buffer.usage2.consumer); + image_native_buffer.usage3 = img.buffer->usage; + image_create.pNext = &image_native_buffer; + + ATRACE_BEGIN("CreateImage"); + result = + dispatch.CreateImage(device, &image_create, nullptr, &img.image); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGD("vkCreateImage w/ native buffer failed: %u", result); + break; + } } - } - // -- Cancel all buffers, returning them to the queue -- - // If an error occurred before, also destroy the VkImage and release the - // buffer reference. Otherwise, we retain a strong reference to the buffer. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - if (!swapchain->shared) { - window->cancelBuffer(window, img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; + // -- Cancel all buffers, returning them to the queue -- + // If an error occurred before, also destroy the VkImage and release the + // buffer reference. Otherwise, we retain a strong reference to the buffer. + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; + } } } } @@ -1756,6 +1865,64 @@ VkResult AcquireNextImageKHR(VkDevice device, break; } } + + // If this is a deferred alloc swapchain, this may be the first time we've + // seen a particular buffer. If so, there should be an empty slot. Find it, + // and bind the gralloc buffer to the VkImage for that slot. If there is no + // empty slot, then we dequeued an unexpected buffer. Non-deferred swapchains + // will also take this path, but will never have an empty slot since we + // populated them all upfront. + if (idx == swapchain.num_images) { + for (idx = 0; idx < swapchain.num_images; idx++) { + if (!swapchain.images[idx].buffer) { + // Note: this structure is technically required for + // Vulkan correctness, even though the driver is probably going + // to use everything from the VkNativeBufferANDROID below. + // This is kindof silly, but it's how we did the ANB + // side of VK_KHR_swapchain v69, so we're stuck with it unless + // we want to go tinkering with the ANB spec some more. + VkBindImageMemorySwapchainInfoKHR bimsi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, + .pNext = nullptr, + .swapchain = swapchain_handle, + .imageIndex = idx, + }; + VkNativeBufferANDROID nb = { + .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, + .pNext = &bimsi, + .handle = buffer->handle, + .stride = buffer->stride, + .format = buffer->format, + .usage = int(buffer->usage), + }; + VkBindImageMemoryInfo bimi = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + .pNext = &nb, + .image = swapchain.images[idx].image, + .memory = VK_NULL_HANDLE, + .memoryOffset = 0, + }; + result = GetData(device).driver.BindImageMemory2(device, 1, &bimi); + if (result != VK_SUCCESS) { + // This shouldn't really happen. If it does, something is probably + // unrecoverably wrong with the swapchain and its images. Cancel + // the buffer and declare the swapchain broken. + ALOGE("failed to do deferred gralloc buffer bind"); + window->cancelBuffer(window, buffer, fence_fd); + return VK_ERROR_OUT_OF_DATE_KHR; + } + + swapchain.images[idx].dequeued = true; + swapchain.images[idx].dequeue_fence = fence_fd; + swapchain.images[idx].buffer = buffer; + break; + } + } + } + + // The buffer doesn't match any slot. This shouldn't normally happen, but is + // possible if the bufferqueue is reconfigured behind libvulkan's back. If this + // happens, just declare the swapchain to be broken and the app will recreate it. if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); @@ -1881,12 +2048,32 @@ static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTime } } +// EXT_swapchain_maintenance1 present mode change +static bool SetSwapchainPresentMode(ANativeWindow *window, VkPresentModeKHR mode) { + // There is no dynamic switching between non-shared present modes. + // All we support is switching between demand and continuous refresh. + if (!IsSharedPresentMode(mode)) + return true; + + int err = native_window_set_auto_refresh(window, + mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + if (err != android::OK) { + ALOGE("native_window_set_auto_refresh() failed: %s (%d)", + strerror(-err), err); + return false; + } + + return true; +} + static VkResult PresentOneSwapchain( VkQueue queue, Swapchain& swapchain, uint32_t imageIndex, const VkPresentRegionKHR *pRegion, const VkPresentTimeGOOGLE *pTime, + VkFence presentFence, + const VkPresentModeKHR *pPresentMode, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores) { @@ -1917,12 +2104,33 @@ static VkResult PresentOneSwapchain( ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { + if (presentFence != VK_NULL_HANDLE) { + int fence_copy = fence < 0 ? -1 : dup(fence); + VkImportFenceFdInfoKHR iffi = { + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, + nullptr, + presentFence, + VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + fence_copy, + }; + if (VK_SUCCESS != dispatch.ImportFenceFdKHR(device, &iffi) && fence_copy >= 0) { + // ImportFenceFdKHR takes ownership only if it succeeds + close(fence_copy); + } + } + if (pRegion) { SetSwapchainSurfaceDamage(window, pRegion); } if (pTime) { SetSwapchainFrameTimestamp(swapchain, pTime); } + if (pPresentMode) { + if (!SetSwapchainPresentMode(window, *pPresentMode)) + swapchain_result = WorstPresentResult(swapchain_result, + VK_ERROR_SURFACE_LOST_KHR); + } err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error @@ -2003,6 +2211,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Look at the pNext chain for supported extension structs: const VkPresentRegionsKHR* present_regions = nullptr; const VkPresentTimesInfoGOOGLE* present_times = nullptr; + const VkSwapchainPresentFenceInfoEXT* present_fences = nullptr; + const VkSwapchainPresentModeInfoEXT* present_modes = nullptr; + const VkPresentRegionsKHR* next = reinterpret_cast(present_info->pNext); while (next) { @@ -2014,6 +2225,14 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times = reinterpret_cast(next); break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: + present_fences = + reinterpret_cast(next); + break; + case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: + present_modes = + reinterpret_cast(next); + break; default: ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", next->sType); @@ -2029,6 +2248,15 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_times->swapchainCount != present_info->swapchainCount, "VkPresentTimesInfoGOOGLE::swapchainCount != " "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_fences && + present_fences->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentFenceInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + ALOGV_IF(present_modes && + present_modes->swapchainCount != present_info->swapchainCount, + "VkSwapchainPresentModeInfoEXT::swapchainCount != " + "VkPresentInfo::swapchainCount"); + const VkPresentRegionKHR* regions = (present_regions) ? present_regions->pRegions : nullptr; const VkPresentTimeGOOGLE* times = @@ -2044,6 +2272,8 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info->pImageIndices[sc], (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr, times ? ×[sc] : nullptr, + present_fences ? present_fences->pFences[sc] : VK_NULL_HANDLE, + present_modes ? &present_modes->pPresentModes[sc] : nullptr, present_info->waitSemaphoreCount, present_info->pWaitSemaphores); @@ -2268,5 +2498,35 @@ VkResult BindImageMemory2KHR(VkDevice device, out_bind_infos.empty() ? pBindInfos : out_bind_infos.data()); } +VKAPI_ATTR +VkResult ReleaseSwapchainImagesEXT(VkDevice /*device*/, + const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo) { + ATRACE_CALL(); + + Swapchain& swapchain = *SwapchainFromHandle(pReleaseInfo->swapchain); + ANativeWindow* window = swapchain.surface.window.get(); + + // If in shared present mode, don't actually release the image back to the BQ. + // Both sides share it forever. + if (swapchain.shared) + return VK_SUCCESS; + + for (uint32_t i = 0; i < pReleaseInfo->imageIndexCount; i++) { + Swapchain::Image& img = swapchain.images[pReleaseInfo->pImageIndices[i]]; + window->cancelBuffer(window, img.buffer.get(), img.dequeue_fence); + + // cancelBuffer has taken ownership of the dequeue fence + img.dequeue_fence = -1; + // if we're still holding a release fence, get rid of it now + if (img.release_fence >= 0) { + close(img.release_fence); + img.release_fence = -1; + } + img.dequeued = false; + } + + return VK_SUCCESS; +} + } // namespace driver } // namespace vulkan diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index 4912ef1a33..280fe9b5a3 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -46,6 +46,7 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice ph VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult ReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); // clang-format on } // namespace driver diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index af56764a21..78b550c202 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -35,6 +35,8 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_KHR_surface', 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', + 'VK_EXT_swapchain_maintenance1', + 'VK_EXT_surface_maintenance1', ] # Extensions known to vulkan::driver level. @@ -46,6 +48,7 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 'VK_KHR_external_memory_capabilities', 'VK_KHR_external_semaphore_capabilities', 'VK_KHR_external_fence_capabilities', + 'VK_KHR_external_fence_fd', ] # Functions needed at vulkan::driver level. @@ -112,6 +115,9 @@ _NEEDED_COMMANDS = [ # For promoted VK_KHR_external_fence_capabilities 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalFencePropertiesKHR', + + # VK_KHR_swapchain_maintenance1 requirement + 'vkImportFenceFdKHR', ] # Functions intercepted at vulkan::driver level. -- cgit v1.2.3-59-g8ed1b