Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions src/vulkan/wrapper/wrapper_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
135 changes: 118 additions & 17 deletions src/vulkan/wrapper/wrapper_device_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/vulkan/wrapper/wrapper_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
15 changes: 14 additions & 1 deletion src/vulkan/wsi/wsi_common_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading