diff --git a/src/vulkan/wrapper/wrapper_device.c b/src/vulkan/wrapper/wrapper_device.c index 430e825..b99530a 100644 --- a/src/vulkan/wrapper/wrapper_device.c +++ b/src/vulkan/wrapper/wrapper_device.c @@ -41,23 +41,29 @@ const struct vk_device_extension_table wrapper_filter_extensions = .EXT_image_compression_control_swapchain = true, }; -static struct wrapper_buffer * -get_wrapper_buffer_from_handle(struct wrapper_device *device, VkBuffer buffer) { - struct wrapper_buffer *wb = NULL; +inline struct wrapper_buffer * +get_wrapper_buffer_from_handle_locked(struct wrapper_device *device, VkBuffer buffer) { + return _mesa_hash_table_u64_search(device->buffer_table, (uint64_t) buffer); +} +struct wrapper_buffer * +get_wrapper_buffer_from_handle(struct wrapper_device *device, VkBuffer buffer) { simple_mtx_lock(&device->resource_mutex); - wb = _mesa_hash_table_u64_search(device->buffer_table, (uint64_t) buffer); + struct wrapper_buffer *wb = get_wrapper_buffer_from_handle_locked(device, buffer); simple_mtx_unlock(&device->resource_mutex); return wb; } +inline struct wrapper_image * +get_wrapper_image_from_handle_locked(struct wrapper_device *device, VkImage image) { + return _mesa_hash_table_u64_search(device->image_table, (uint64_t) image); +} + struct wrapper_image * -get_wrapper_image_from_handle(struct wrapper_device *device, VkImage image) { - struct wrapper_image *wi = NULL; - +get_wrapper_image_from_handle(struct wrapper_device *device, VkImage image) { simple_mtx_lock(&device->resource_mutex); - wi = _mesa_hash_table_u64_search(device->image_table, (uint64_t) image); + struct wrapper_image *wi = get_wrapper_image_from_handle_locked(device, image); simple_mtx_unlock(&device->resource_mutex); return wi; @@ -854,6 +860,7 @@ wrapper_CreateBuffer(VkDevice _device, { VK_FROM_HANDLE(wrapper_device, device, _device); VkResult res; + VkExternalMemoryHandleTypeFlags handle_types = 0; /* When we fake VK_KHR_maintenance5 (base driver lacks it, e.g. Xclipse), * DXVK specifies buffer usage through VkBufferUsageFlags2CreateInfo and may @@ -871,6 +878,12 @@ wrapper_CreateBuffer(VkDevice _device, } } + const VkExternalMemoryBufferCreateInfo *ext_info = + vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_BUFFER_CREATE_INFO); + if (ext_info) { + handle_types = ext_info->handleTypes; + } + res = device->dispatch_table.CreateBuffer(device->dispatch_handle, pCreateInfo, pAllocator, pBuffer); @@ -893,6 +906,7 @@ wrapper_CreateBuffer(VkDevice _device, wb->device = device; wb->size = pCreateInfo->size; wb->dispatch_handle = *pBuffer; + wb->handle_types = handle_types; list_add(&wb->link, &device->buffer_list); _mesa_hash_table_u64_insert(device->buffer_table, (uint64_t)wb->dispatch_handle, wb); @@ -1003,6 +1017,7 @@ wrapper_CreateImage(VkDevice _device, VkImageCreateInfo create_info; bool is_emulated_bgra8 = false; bool is_wsi_image = false; + VkExternalMemoryHandleTypeFlags handle_types = 0; // Wrapper specific extension for B8G8R8A8 AHB img emulation for the swapchain VkBaseInStructure *prev = (VkBaseInStructure *) pCreateInfo; @@ -1016,13 +1031,16 @@ wrapper_CreateImage(VkDevice _device, } // Tag swapchain images using VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA - prev = (VkBaseInStructure *) pCreateInfo; - for (const VkBaseInStructure *s = pCreateInfo->pNext; s; s = s->pNext) { - if (s->sType == VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA) { - is_wsi_image = true; - break; - } - prev = (VkBaseInStructure *) s; + const struct wsi_image_create_info *wsi_info = + vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA); + if (wsi_info) { + is_wsi_image = true; + } + + const VkExternalMemoryImageCreateInfo *ext_info = + vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO); + if (ext_info) { + handle_types = ext_info->handleTypes; } /* Copy after the unlink above: when the emulated-bgra8 struct is the @@ -1073,6 +1091,7 @@ wrapper_CreateImage(VkDevice _device, wi->dispatch_handle = *pImage; wi->is_emulated_bgra8 = is_emulated_bgra8; wi->is_wsi_image = is_wsi_image; + wi->handle_types = handle_types; list_add(&wi->link, &device->image_list); _mesa_hash_table_u64_insert(device->image_table, (uint64_t)wi->dispatch_handle, wi); diff --git a/src/vulkan/wrapper/wrapper_device_memory.c b/src/vulkan/wrapper/wrapper_device_memory.c index fe357ba..f4ef45d 100644 --- a/src/vulkan/wrapper/wrapper_device_memory.c +++ b/src/vulkan/wrapper/wrapper_device_memory.c @@ -202,6 +202,59 @@ wrapper_select_allowed_device_memory_type(struct wrapper_device *device, return UINT32_MAX; } +static inline void +unlink_memory_alloc_info_pnext(VkMemoryAllocateInfo *alloc_info, VkStructureType sType) +{ + const VkBaseInStructure *head = (const VkBaseInStructure *)alloc_info->pNext; + if (head && head->sType == sType) { + alloc_info->pNext = head->pNext; + return; + } + + VkBaseOutStructure *prev = NULL; + vk_foreach_struct(s, (void *)alloc_info->pNext) { + if (s->sType == sType) { + if (prev) { + prev->pNext = s->pNext; // modifies application owned memory, but it should be okay + } + return; + } + prev = s; + } +} + +static VkResult check_dedicated_allocate_info_for(struct wrapper_device *device, + const VkMemoryDedicatedAllocateInfo *memory_dedicated_info, + VkExternalMemoryHandleTypeFlags handle_types) { + if (!memory_dedicated_info) { + return VK_SUCCESS; + } + + if (memory_dedicated_info->image != VK_NULL_HANDLE) { + struct wrapper_image *img = get_wrapper_image_from_handle_locked( + device, memory_dedicated_info->image); + if (img && img->handle_types && !(img->handle_types & handle_types)) { + // Shouldn't happen anymore + WRAPPER_LOG(error, "Dedicated image handle type mismatch (0x%x vs required 0x%x)", + img ? img->handle_types : 0, handle_types); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + } + + if (memory_dedicated_info->buffer != VK_NULL_HANDLE) { + struct wrapper_buffer *buf = get_wrapper_buffer_from_handle_locked( + device, memory_dedicated_info->buffer); + if (buf && buf->handle_types && !(buf->handle_types & handle_types)) { + // Shouldn't happen anymore + WRAPPER_LOG(error, "Dedicated buffer handle type mismatch (0x%x vs required 0x%x)", + buf ? buf->handle_types : 0, handle_types); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + } + + return VK_SUCCESS; +} + static VkResult wrapper_allocate_memory_dmaheap(struct wrapper_device *device, const VkMemoryAllocateInfo* pAllocateInfo, @@ -240,6 +293,14 @@ wrapper_allocate_memory_dmaheap(struct wrapper_device *device, return VK_ERROR_INVALID_EXTERNAL_HANDLE; } + const VkMemoryDedicatedAllocateInfo *memory_dedicated_info = + vk_find_struct_const(pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO); + result = check_dedicated_allocate_info_for( + device, memory_dedicated_info, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); + if (result != VK_SUCCESS) { + return result; + } + import_fd_info = (VkImportMemoryFdInfoKHR) { .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, .pNext = pAllocateInfo->pNext, @@ -272,6 +333,14 @@ wrapper_allocate_memory_opaque_fd(struct wrapper_device *device, VkResult result; VkMemoryAllocateInfo allocate_info; + const VkMemoryDedicatedAllocateInfo *memory_dedicated_info = + vk_find_struct_const(pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO); + result = check_dedicated_allocate_info_for( + device, memory_dedicated_info, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT); + if (result != VK_SUCCESS) { + return result; + } + VkExportMemoryAllocateInfo export_memory_info = { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = NULL, @@ -318,19 +387,22 @@ wrapper_allocate_memory_ahardware_buffer(struct wrapper_device *device, AHardwareBuffer **pAHardwareBuffer) { VkExportMemoryAllocateInfo export_memory_info; VkMemoryAllocateInfo allocate_info; - const VkMemoryDedicatedAllocateInfo *memory_dedicated_info = NULL; VkResult result; - + const VkMemoryDedicatedAllocateInfo *memory_dedicated_info = + vk_find_struct_const(pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO); + result = check_dedicated_allocate_info_for( + device, memory_dedicated_info, VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID); + if (result != VK_SUCCESS) { + return result; + } + export_memory_info = (VkExportMemoryAllocateInfo) { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = pAllocateInfo->pNext, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, }; - - memory_dedicated_info = vk_find_struct_const(pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO); - allocate_info = *pAllocateInfo; allocate_info.pNext = &export_memory_info; @@ -489,38 +561,67 @@ wrapper_AllocateMemory(VkDevice _device, vk_error(device, result); goto out; } + + VkExternalMemoryHandleTypeFlags valid_handle_types = 0; + if (dedicated_allocate_info) { + // Note that buffer/image are mutually exclusive + if (dedicated_allocate_info->image != VK_NULL_HANDLE) { + struct wrapper_image *img = get_wrapper_image_from_handle_locked(device, dedicated_allocate_info->image); + if (img) { + valid_handle_types |= img->handle_types; + } + } + if (dedicated_allocate_info->buffer != VK_NULL_HANDLE) { + struct wrapper_buffer *buf = get_wrapper_buffer_from_handle_locked(device, dedicated_allocate_info->buffer); + if (buf) { + valid_handle_types |= buf->handle_types; + } + } + } + + VkMemoryAllocateInfo memory_allocate_info = *pAllocateInfo; + if (dedicated_allocate_info && valid_handle_types == 0) { + // Driver "bug" on some mobile drivers - providing an empty dedicate memory hint in conjunction with the + // VkImportMemoryFdInfoKHR / VkExportMemoryAllocateInfo could crash the driver + unlink_memory_alloc_info_pnext(&memory_allocate_info, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } if (strstr(device->physical->resource_type, "ahb")) { WRAPPER_LOG(info, "Using AHardwareBuffer memory backend"); result = wrapper_allocate_memory_ahardware_buffer(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->ahardware_buffer); + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->ahardware_buffer); } else if (strstr(device->physical->resource_type, "dmabuf")) { WRAPPER_LOG(info, "Using DMABUF memory backend"); result = wrapper_allocate_memory_dmaheap(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->fd); + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->fd); } else if (strstr(device->physical->resource_type, "opaque")) { WRAPPER_LOG(info, "Using opaque fd memory backend"); result = wrapper_allocate_memory_opaque_fd(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->fd); + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->fd); } else { WRAPPER_LOG(info, "Using auto memory backend"); - result = wrapper_allocate_memory_dmaheap(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->fd); + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; +#define VALID_HANDLE(type) (valid_handle_types == 0 || (type & valid_handle_types) != 0) + if (VALID_HANDLE(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { + result = wrapper_allocate_memory_dmaheap(device, + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->fd); + } - if (result != VK_SUCCESS) { + if (result != VK_SUCCESS && VALID_HANDLE(VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) { wrapper_device_memory_reset(mem); result = wrapper_allocate_memory_ahardware_buffer(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->ahardware_buffer); + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->ahardware_buffer); } - if (result != VK_SUCCESS) { + if (result != VK_SUCCESS && VALID_HANDLE(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)) { wrapper_device_memory_reset(mem); result = wrapper_allocate_memory_opaque_fd(device, - pAllocateInfo, pAllocator, &mem->dispatch_handle, &mem->fd); + &memory_allocate_info, pAllocator, &mem->dispatch_handle, &mem->fd); } +#undef VALID_HANDLE } if (result != VK_SUCCESS) { @@ -531,14 +632,14 @@ wrapper_AllocateMemory(VkDevice _device, /* resource_mutex is already held here and simple_mtx is not * recursive, so search the image table directly instead of * going through get_wrapper_image_from_handle. */ - struct wrapper_image *img = _mesa_hash_table_u64_search( - device->image_table, (uint64_t)dedicated_allocate_info->image); + struct wrapper_image *img = get_wrapper_image_from_handle_locked( + device, dedicated_allocate_info->image); if (img && img->is_wsi_image) { // Fixes failure to blit on ion-heap (< GKI 5.10) Mali devices at the cost of // not being able to mmap these. WRAPPER_LOG(error, "EXT_map_memory_placed emulation failed for swapchain image, bypassing emulation"); simple_mtx_unlock(&device->resource_mutex); - goto fallback; + goto fallback; // TODO: the VkMemoryAllocateInfo may have been unlinked here } } diff --git a/src/vulkan/wrapper/wrapper_private.h b/src/vulkan/wrapper/wrapper_private.h index 3a6ecf0..9ec85ec 100644 --- a/src/vulkan/wrapper/wrapper_private.h +++ b/src/vulkan/wrapper/wrapper_private.h @@ -129,8 +129,15 @@ struct wrapper_buffer { * and bytes to release from the device's in-flight counter when freed. */ VkDescriptorPool desc_pool; VkDeviceSize bcn_inflight; + VkExternalMemoryHandleTypeFlags handle_types; }; +struct wrapper_buffer * +get_wrapper_buffer_from_handle_locked(struct wrapper_device *device, VkBuffer buffer); + +struct wrapper_buffer * +get_wrapper_buffer_from_handle(struct wrapper_device *device, VkBuffer buffer); + #define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EMULATED_B8G8R8A8_CREATE_INFO_EXT 1000701234 typedef struct VkEmulatedB8G8R8A8CreateInfoExt { VkStructureType sType; @@ -147,8 +154,12 @@ struct wrapper_image { bool is_emulated_bgra8; bool is_wsi_image; + VkExternalMemoryHandleTypeFlags handle_types; }; +struct wrapper_image * +get_wrapper_image_from_handle_locked(struct wrapper_device *device, VkImage image); + struct wrapper_image * get_wrapper_image_from_handle(struct wrapper_device *device, VkImage image); diff --git a/src/vulkan/wsi/wsi_common_android.c b/src/vulkan/wsi/wsi_common_android.c index be1ff0b..9f03ea4 100644 --- a/src/vulkan/wsi/wsi_common_android.c +++ b/src/vulkan/wsi/wsi_common_android.c @@ -353,7 +353,20 @@ wsi_configure_ahardware_buffer_image(const struct wsi_swapchain *chain, wsi_destroy_image_info(chain, info); return VK_ERROR_OUT_OF_HOST_MEMORY; } - + + // WARNING: The secondary AHB MUST be declared as AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM + // to allow certain mobile drivers to import it, but X11 treats its memory backing + // as physical [B, G, R, A] (in reverse order). + // + // We CANNOT use vkCmdBlitImage: Vulkan will detect the format mismatch between + // B8G8R8A8 (primary) and R8G8B8A8 (secondary) and perform an automatic channel swizzle + // [B,G,R,A] -> [R,G,B,A], which breaks X11's expected layout. + // + // We MUST use vkCmdCopyImage for a pure bitwise copy, and force the primary image + // to B8G8R8A8 upfront so the rendered memory is already in [B, G, R, A] order. + // + // Similarly, we CANNOT advertise an [R,G,B,A] format for the primary image without + // a design to copy+swizzle the blit from the primary to the secondary. *info->ahardware_buffer_desc = (AHardwareBuffer_Desc) { .width = pCreateInfo->imageExtent.width, .height = pCreateInfo->imageExtent.height, diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index 6145e16..21d3d0c 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -443,12 +443,16 @@ wsi_x11_get_connection(struct wsi_device *wsi_dev, return entry->data; } +// WARNING: this is the primary image format list +// When blitting, we CANNOT advertise R8G8B8A8 as the secondary +// image expects the physical layout order of the primary image +// to ALWAYS be B8G8R8A8_UNORM, regardless of the advertised format. +// Until we can swizzle+copy the image (and we cannot use a vkCmdBlitImage) +// we must always advertise B8G8R8A8_UNORM as the primary image format. static const VkFormat formats[] = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, - VK_FORMAT_R8G8B8A8_SRGB, // Mali only supports rgba8 direct rendering - VK_FORMAT_R8G8B8A8_UNORM, // Mali only supports rgba8 direct rendering VK_FORMAT_A2R10G10B10_UNORM_PACK32, }; @@ -865,26 +869,11 @@ get_sorted_vk_formats(VkIcdSurfaceBase *surface, struct wsi_device *wsi_device, /* use the root window's visual to set the default */ *count = 0; for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) { - // dxvk will prefer an rgba8 framebuffer, but x11 MUST be given - // a bgra8 one. Since we now expose rgba8 as an option for Mali - // bgra8 emulation, we need to filter them out when they're turned - // off or else dxvk buffers will have swapped blue/red channels. - if (!wsi_device->emulate_bgra8 && - (formats[i] == VK_FORMAT_R8G8B8A8_UNORM || - formats[i] == VK_FORMAT_R8G8B8A8_SRGB)) - continue; - if (rgb_component_bits_are_equal(formats[i], rootvis)) sorted_formats[(*count)++] = formats[i]; } for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) { - // See above - if (!wsi_device->emulate_bgra8 && - (formats[i] == VK_FORMAT_R8G8B8A8_UNORM || - formats[i] == VK_FORMAT_R8G8B8A8_SRGB)) - continue; - for (unsigned j = 0; j < *count; j++) if (formats[i] == sorted_formats[j]) goto next_format; @@ -892,15 +881,8 @@ get_sorted_vk_formats(VkIcdSurfaceBase *surface, struct wsi_device *wsi_device, sorted_formats[(*count)++] = formats[i]; next_format:; } - if (wsi_device->emulate_bgra8) { - for (unsigned i = 0; i < *count; i++) { - if (sorted_formats[i] == VK_FORMAT_R8G8B8A8_UNORM) { - sorted_formats[i] = sorted_formats[0]; - sorted_formats[0] = VK_FORMAT_R8G8B8A8_UNORM; - break; - } - } - } else if (wsi_device->force_bgra8_unorm_first) { + + if (wsi_device->force_bgra8_unorm_first) { for (unsigned i = 0; i < *count; i++) { if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) { sorted_formats[i] = sorted_formats[0];