lavapipe: Add android platform integration

Allow lavapipe to be loaded by the Android vulkan loader. Also provides
window system integration through the `VK_ANDROID_native_buffer`
extension.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344>
This commit is contained in:
Lucas Fryzek 2024-05-16 15:47:58 +01:00 committed by Marge Bot
parent cfd897bae0
commit 0dce939e6d
6 changed files with 249 additions and 5 deletions

View file

@ -0,0 +1,177 @@
/*
* Copyright © 2024, Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <lvp_private.h>
#include <hardware/gralloc.h>
#if ANDROID_API_LEVEL >= 26
#include <hardware/gralloc1.h>
#endif
#include <hardware/hardware.h>
#include <hardware/hwvulkan.h>
#include "util/libsync.h"
#include "util/os_file.h"
#include "util/libsync.h"
#include "vk_fence.h"
#include "vk_semaphore.h"
static int
lvp_hal_open(const struct hw_module_t *mod,
const char *id,
struct hw_device_t **dev);
static int
lvp_hal_close(struct hw_device_t *dev);
static_assert(HWVULKAN_DISPATCH_MAGIC == ICD_LOADER_MAGIC, "");
struct hw_module_methods_t HAL_MODULE_METHODS = {
.open = lvp_hal_open,
};
PUBLIC struct hwvulkan_module_t HAL_MODULE_INFO_SYM = {
.common =
{
.tag = HARDWARE_MODULE_TAG,
.module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_MAKE_API_VERSION(1, 0),
.id = HWVULKAN_HARDWARE_MODULE_ID,
.name = "Lavapipe Vulkan HAL",
.author = "Mesa3D",
.methods = &HAL_MODULE_METHODS,
},
};
static int
lvp_hal_open(const struct hw_module_t *mod,
const char *id,
struct hw_device_t **dev)
{
assert(mod == &HAL_MODULE_INFO_SYM.common);
assert(strcmp(id, HWVULKAN_DEVICE_0) == 0);
hwvulkan_device_t *hal_dev = (hwvulkan_device_t *) malloc(sizeof(*hal_dev));
if (!hal_dev)
return -1;
*hal_dev = (hwvulkan_device_t){
.common =
{
.tag = HARDWARE_DEVICE_TAG,
.version = HWVULKAN_DEVICE_API_VERSION_0_1,
.module = &HAL_MODULE_INFO_SYM.common,
.close = lvp_hal_close,
},
.EnumerateInstanceExtensionProperties =
lvp_EnumerateInstanceExtensionProperties,
.CreateInstance = lvp_CreateInstance,
.GetInstanceProcAddr = lvp_GetInstanceProcAddr,
};
*dev = &hal_dev->common;
return 0;
}
static int
lvp_hal_close(struct hw_device_t *dev)
{
/* hwvulkan.h claims that hw_device_t::close() is never called. */
return -1;
}
VKAPI_ATTR VkResult VKAPI_CALL
lvp_GetSwapchainGrallocUsageANDROID(VkDevice device_h,
VkFormat format,
VkImageUsageFlags imageUsage,
int *grallocUsage)
{
*grallocUsage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
return VK_SUCCESS;
}
#if ANDROID_API_LEVEL >= 26
VKAPI_ATTR VkResult VKAPI_CALL
lvp_GetSwapchainGrallocUsage2ANDROID(VkDevice device_h,
VkFormat format,
VkImageUsageFlags imageUsage,
VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
uint64_t *grallocConsumerUsage,
uint64_t *grallocProducerUsage)
{
*grallocConsumerUsage = 0;
*grallocProducerUsage = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
return VK_SUCCESS;
}
#endif
VKAPI_ATTR VkResult VKAPI_CALL
lvp_AcquireImageANDROID(VkDevice _device,
VkImage image,
int nativeFenceFd,
VkSemaphore semaphore,
VkFence fence)
{
VK_FROM_HANDLE(vk_device, vk_device, _device);
VkResult result = VK_SUCCESS;
if(nativeFenceFd >= 0)
{
sync_wait(nativeFenceFd, -1);
close(nativeFenceFd);
}
if(fence != VK_NULL_HANDLE)
{
VK_FROM_HANDLE(vk_fence, vk_fence, fence);
result = vk_sync_signal(vk_device, &vk_fence->permanent, 0);
}
if(result == VK_SUCCESS && semaphore != VK_NULL_HANDLE)
{
VK_FROM_HANDLE(vk_semaphore, vk_semaphore, semaphore);
result = vk_sync_signal(vk_device, &vk_semaphore->permanent, 0);
}
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
lvp_QueueSignalReleaseImageANDROID(VkQueue _queue,
uint32_t waitSemaphoreCount,
const VkSemaphore *pWaitSemaphores,
VkImage image,
int *pNativeFenceFd)
{
VK_FROM_HANDLE(vk_queue, queue, _queue);
struct vk_device *device = queue->base.device;
device->dispatch_table.QueueWaitIdle(_queue);
*pNativeFenceFd = -1;
return VK_SUCCESS;
}

View file

@ -50,6 +50,10 @@
#include <sys/resource.h>
#endif
#if DETECT_OS_ANDROID
#include "vk_android.h"
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
defined(VK_USE_PLATFORM_WIN32_KHR) || \
defined(VK_USE_PLATFORM_XCB_KHR) || \
@ -249,6 +253,9 @@ static const struct vk_device_extension_table lvp_device_extensions_supported =
.EXT_line_rasterization = true,
.EXT_robustness2 = true,
.AMDX_shader_enqueue = true,
#if DETECT_OS_ANDROID
.ANDROID_native_buffer = true,
#endif
.GOOGLE_decorate_string = true,
.GOOGLE_hlsl_functionality1 = true,
.NV_device_generated_commands = true,
@ -1271,12 +1278,14 @@ lvp_physical_device_init(struct lvp_physical_device *device,
lvp_get_features(device, &device->vk.supported_features);
lvp_get_properties(device, &device->vk.properties);
#ifdef LVP_USE_WSI_PLATFORM
result = lvp_init_wsi(device);
if (result != VK_SUCCESS) {
vk_physical_device_finish(&device->vk);
vk_error(instance, result);
goto fail;
}
#endif
return VK_SUCCESS;
fail:
@ -1286,7 +1295,9 @@ lvp_physical_device_init(struct lvp_physical_device *device,
static void VKAPI_CALL
lvp_physical_device_finish(struct lvp_physical_device *device)
{
#ifdef LVP_USE_WSI_PLATFORM
lvp_finish_wsi(device);
#endif
device->pscreen->destroy(device->pscreen);
vk_physical_device_finish(&device->vk);
}
@ -1342,6 +1353,10 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateInstance(
// VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
#if DETECT_OS_ANDROID
vk_android_init_ugralloc();
#endif
*pInstance = lvp_instance_to_handle(instance);
return VK_SUCCESS;
@ -1356,6 +1371,10 @@ VKAPI_ATTR void VKAPI_CALL lvp_DestroyInstance(
if (!instance)
return;
#if DETECT_OS_ANDROID
vk_android_destroy_ugralloc();
#endif
pipe_loader_release(&instance->devs, instance->num_devices);
vk_instance_finish(&instance->vk);
@ -2231,6 +2250,11 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_BindImageMemory2(VkDevice _device,
VkBindMemoryStatusKHR *status = (void*)vk_find_struct_const(&pBindInfos[i], BIND_MEMORY_STATUS_KHR);
bool did_bind = false;
if (!mem) {
continue;
}
#ifdef LVP_USE_WSI_PLATFORM
vk_foreach_struct_const(s, bind_info->pNext) {
switch (s->sType) {
case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR: {
@ -2256,6 +2280,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_BindImageMemory2(VkDevice _device,
break;
}
}
#endif
if (!did_bind) {
uint64_t offset_B = 0;

View file

@ -467,7 +467,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_GetPhysicalDeviceImageFormatProperties2(
}
}
if (external_info && external_info->handleType != 0) {
if (external_info && external_info->handleType != 0 && external_props) {
VkExternalMemoryFeatureFlagBits flags = 0;
VkExternalMemoryHandleTypeFlags export_flags = 0;
VkExternalMemoryHandleTypeFlags compat_flags = 0;

View file

@ -27,6 +27,7 @@
#include "util/u_surface.h"
#include "pipe/p_state.h"
#include "frontend/winsys_handle.h"
#include "vk_android.h"
static VkResult
lvp_image_create(VkDevice _device,
@ -36,12 +37,14 @@ lvp_image_create(VkDevice _device,
{
LVP_FROM_HANDLE(lvp_device, device, _device);
struct lvp_image *image;
VkResult result = VK_SUCCESS;
bool android_surface = false;
const VkSubresourceLayout *layouts = NULL;
uint64_t modifier;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
#ifdef HAVE_LIBDRM
unsigned num_layouts = 1;
const VkSubresourceLayout *layouts = NULL;
enum pipe_format pipe_format = lvp_vk_format_to_pipe_format(pCreateInfo->format);
const VkImageDrmFormatModifierExplicitCreateInfoEXT *modinfo = (void*)vk_find_struct_const(pCreateInfo->pNext,
IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
@ -59,6 +62,8 @@ lvp_image_create(VkDevice _device,
mesa_loge("lavapipe: planar drm formats are not supported");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
modifier = DRM_FORMAT_MOD_LINEAR;
#endif
image = vk_image_create(&device->vk, pCreateInfo, alloc, sizeof(*image));
@ -73,6 +78,20 @@ lvp_image_create(VkDevice _device,
image->disjoint = image->plane_count > 1 &&
(pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT);
/* This section is removed by the optimizer for non-ANDROID builds */
VkImageDrmFormatModifierExplicitCreateInfoEXT eci;
VkSubresourceLayout a_plane_layouts[LVP_MAX_PLANE_COUNT];
if (vk_image_is_android_native_buffer(&image->vk)) {
result = vk_android_get_anb_layout(
pCreateInfo, &eci, a_plane_layouts, LVP_MAX_PLANE_COUNT);
if (result != VK_SUCCESS)
goto fail;
modifier = eci.drmFormatModifier;
layouts = a_plane_layouts;
android_surface = true;
}
const struct vk_format_ycbcr_info *ycbcr_info =
vk_format_get_ycbcr_info(pCreateInfo->format);
for (unsigned p = 0; p < image->plane_count; p++) {
@ -141,7 +160,7 @@ lvp_image_create(VkDevice _device,
template.nr_storage_samples = pCreateInfo->samples;
#ifdef HAVE_LIBDRM
if (modinfo && pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
if (android_surface || (modinfo && pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)) {
struct winsys_handle whandle;
whandle.type = WINSYS_HANDLE_TYPE_UNBACKED;
whandle.layer = 0;
@ -152,7 +171,7 @@ lvp_image_create(VkDevice _device,
whandle.image_stride = layouts[p].depthPitch;
image->offset = layouts[p].offset;
whandle.format = pCreateInfo->format;
whandle.modifier = DRM_FORMAT_MOD_LINEAR;
whandle.modifier = modifier;
image->planes[p].bo = device->pscreen->resource_from_handle(device->pscreen,
&template,
&whandle,
@ -172,9 +191,23 @@ lvp_image_create(VkDevice _device,
image->size += image->planes[p].size;
}
/* This section is removed by the optimizer for non-ANDROID builds */
if (vk_image_is_android_native_buffer(&image->vk)) {
result = vk_android_import_anb(&device->vk, pCreateInfo, alloc,
&image->vk);
if (result != VK_SUCCESS) {
mesa_logw("Failed to import memory");
goto fail;
}
}
*pImage = lvp_image_to_handle(image);
return VK_SUCCESS;
fail:
vk_image_destroy(&device->vk, alloc, &image->vk);
return result;
}
struct lvp_image *
@ -216,11 +249,13 @@ lvp_CreateImage(VkDevice device,
const VkAllocationCallbacks *pAllocator,
VkImage *pImage)
{
#if !DETECT_OS_ANDROID
const VkImageSwapchainCreateInfoKHR *swapchain_info =
vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR);
if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE)
return lvp_image_from_swapchain(device, pCreateInfo, swapchain_info,
pAllocator, pImage);
#endif
return lvp_image_create(device, pCreateInfo, pAllocator,
pImage);
}

View file

@ -100,6 +100,8 @@ extern "C" {
#define MAX_PER_STAGE_DESCRIPTOR_UNIFORM_BLOCKS 8
#define MAX_DGC_STREAMS 16
#define MAX_DGC_TOKENS 16
/* Currently lavapipe does not support more than 1 image plane */
#define LVP_MAX_PLANE_COUNT 1
#ifdef _WIN32
#define lvp_printflike(a, b)
@ -775,6 +777,7 @@ bool
lvp_nir_lower_sparse_residency(struct nir_shader *shader);
enum vk_cmd_type
lvp_nv_dgc_token_to_cmd_type(const VkIndirectCommandsLayoutTokenNV *token);
#ifdef __cplusplus
}
#endif

View file

@ -37,6 +37,10 @@ liblvp_files = files(
'lvp_ray_tracing_pipeline.c',
'lvp_wsi.c')
if with_platform_android
liblvp_files += 'lvp_android.c'
endif
lvp_deps = []
lvp_flags = []