diff --git a/src/vulkan/wrapper/wrapper_device_memory.c b/src/vulkan/wrapper/wrapper_device_memory.c index f4ef45d9..649d2060 100644 --- a/src/vulkan/wrapper/wrapper_device_memory.c +++ b/src/vulkan/wrapper/wrapper_device_memory.c @@ -561,6 +561,7 @@ wrapper_AllocateMemory(VkDevice _device, vk_error(device, result); goto out; } + mem->alloc_size = pAllocateInfo->allocationSize; VkExternalMemoryHandleTypeFlags valid_handle_types = 0; if (dedicated_allocate_info) { diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index cbcec139..869bc320 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -120,6 +120,11 @@ wsi_device_init(struct wsi_device *wsi, }; GetPhysicalDeviceProperties2(pdevice, &wsi->properties2); + wsi->enable_ahb_ownership_release = + debug_get_bool_option("WRAPPER_AHB_OWNERSHIP_RELEASE", + pddp.driverID == + VK_DRIVER_ID_NVIDIA_PROPRIETARY); + const char *wine_preload_reserve = getenv("WINEPRELOADRESERVE"); // e.g. 000400000-0008b4000 or 140000000-1400a8000 bool is_win32 = false; @@ -888,6 +893,20 @@ wsi_destroy_image(const struct wsi_swapchain *chain, vk_free(&chain->alloc, image->blit.cmd_buffers); } +#ifdef __TERMUX__ + if (image->ahb_release_cmd_buffers) { + for (uint32_t i = 0; i < wsi->queue_family_count; i++) { + if (!chain->cmd_pools[i] || + image->ahb_release_cmd_buffers[i] == VK_NULL_HANDLE) + continue; + wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i], + 1, &image->ahb_release_cmd_buffers[i]); + } + vk_free(&chain->alloc, image->ahb_release_cmd_buffers); + image->ahb_release_cmd_buffers = NULL; + } +#endif + wsi->FreeMemory(chain->device, image->memory, &chain->alloc); wsi->DestroyImage(chain->device, image->image, &chain->alloc); wsi->DestroyImage(chain->device, image->blit.image, &chain->alloc); @@ -1598,6 +1617,18 @@ wsi_common_queue_present(const struct wsi_device *wsi, submit_info.pWaitDstStageMask = stage_flags; } } +#ifdef __TERMUX__ + else if (image->ahb_release_cmd_buffers && + image->ahb_release_cmd_buffers[queue_family_index] != VK_NULL_HANDLE) { + /* No blit: an external consumer reads this AHardwareBuffer directly, + * so hand the image over explicitly. The release transfer makes the + * contents available outside this device; see + * wsi_create_ahb_release_cmd_buffers. */ + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = + &image->ahb_release_cmd_buffers[queue_family_index]; + } +#endif VkFence fence = swapchain->fences[image_index]; diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index eb9d5546..19ed2278 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -184,6 +184,7 @@ struct wsi_device { bool needs_blit; bool emulate_bgra8; + bool enable_ahb_ownership_release; /* Set to true if the implementation is ok with linear WSI images. */ bool wants_linear; diff --git a/src/vulkan/wsi/wsi_common_android.c b/src/vulkan/wsi/wsi_common_android.c index 9f03ea4a..51b0f138 100644 --- a/src/vulkan/wsi/wsi_common_android.c +++ b/src/vulkan/wsi/wsi_common_android.c @@ -189,6 +189,107 @@ wsi_create_ahardware_buffer_image_mem(const struct wsi_swapchain *chain, return VK_SUCCESS; } +/* Release the image to an external consumer. + * + * The direct AHardwareBuffer path exports an image that another Vulkan device + * may read. Vulkan models that handoff as a queue-family ownership transfer. + * The producing device must perform the release so driver-private image state + * is made available to the importer. + */ +static VkResult +wsi_create_ahb_release_cmd_buffers(const struct wsi_swapchain *chain, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + const uint32_t count = wsi->queue_family_count; + image->ahb_release_cmd_buffers = + vk_zalloc(&chain->alloc, sizeof(VkCommandBuffer) * count, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!image->ahb_release_cmd_buffers) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + for (uint32_t i = 0; i < count; i++) { + if (!chain->cmd_pools[i]) + continue; + + const VkCommandBufferAllocateInfo cmd_buffer_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = chain->cmd_pools[i], + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info, + &image->ahb_release_cmd_buffers[i]); + if (result != VK_SUCCESS) { + WRAPPER_LOG(error, "Failed to allocate ahb release cmd buffer, res %d", + result); + return result; + } + + const VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + }; + result = wsi->BeginCommandBuffer(image->ahb_release_cmd_buffers[i], + &begin_info); + if (result != VK_SUCCESS) { + WRAPPER_LOG(error, "Failed to begin ahb release cmd buffer, res %d", + result); + return result; + } + + const VkImageMemoryBarrier release = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + /* The WSI does not know how the application produced the image. + * Cover every write rather than assuming color-attachment or blit + * presentation. */ + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + /* Ignored for a release operation. */ + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + /* The importer has to begin its acquire from the layout this release + * ends in, and it cannot name PRESENT_SRC_KHR for an image that does + * not belong to its own swapchain. GENERAL is valid on both sides and, + * unlike UNDEFINED, keeps the contents -- which is the whole point of + * handing the image over. */ + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = i, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT, + .image = image->image, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + wsi->CmdPipelineBarrier(image->ahb_release_cmd_buffers[i], + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, NULL, 0, NULL, 1, &release); + + result = wsi->EndCommandBuffer(image->ahb_release_cmd_buffers[i]); + if (result != VK_SUCCESS) { + WRAPPER_LOG(error, "Failed to record ahb release barrier, res %d", + result); + return result; + } + } + + mesa_logd("Recorded AHB ownership release barriers"); + return VK_SUCCESS; +} + +static VkResult +wsi_finish_create_ahardware_buffer_image(const struct wsi_swapchain *chain, + const struct wsi_image_info *info, + struct wsi_image *image) +{ + return wsi_create_ahb_release_cmd_buffers(chain, image); +} + static VkResult wsi_create_ahardware_buffer_blit_context(const struct wsi_swapchain *chain, const struct wsi_image_info *info, @@ -408,6 +509,15 @@ wsi_configure_android_image( info->create_mem = wsi_create_ahardware_buffer_blit_context; } else { info->create_mem = wsi_create_ahardware_buffer_image_mem; + /* Legacy VkImageMemoryBarrier only permits FOREIGN_EXT ownership + * transfers for exclusive images. Preserve the existing concurrent + * path instead of recording an invalid barrier for it. */ + if (info->create.sharingMode == VK_SHARING_MODE_EXCLUSIVE && + chain->wsi->enable_ahb_ownership_release) { + WRAPPER_LOG(info, + "Enabling AHB ownership release for direct exclusive swapchain"); + info->finish_create = wsi_finish_create_ahardware_buffer_image; + } } return VK_SUCCESS; diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index 54ade681..4905fdbe 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -174,6 +174,10 @@ struct wsi_image { void *cpu_map; #ifdef __TERMUX__ struct AHardwareBuffer *ahardware_buffer; + /* Command buffers, one per queue family, holding the queue-family ownership + * release into VK_QUEUE_FAMILY_FOREIGN_EXT. Submitted before the image is + * handed to an external consumer. See wsi_create_ahb_release_cmd_buffers. */ + VkCommandBuffer *ahb_release_cmd_buffers; #endif };