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
38 changes: 38 additions & 0 deletions .github/workflows/build-termux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Termux-Build of Mesa Vulkan Wrapper

on: [push, pull_request]

jobs:
build-aarch64-wrapper:
runs-on: ubuntu-latest

env:
BUILD_DIR: build
IMAGE_TAG: ghcr.io/leegao/mesa-wrapper-ci/wrapper-compiler:latest

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: wrapper-compiler
run: |
docker run --rm -v "${{ github.workspace }}:/workspace" ${{ env.IMAGE_TAG }} ${{ env.BUILD_DIR }}

- name: Upload Stripped libvulkan_wrapper.so
uses: actions/upload-artifact@v4
with:
name: libvulkan_wrapper
path: |
${{ env.BUILD_DIR }}/libvulkan_wrapper.so
if-no-files-found: error

- name: Upload Unstripped libvulkan_wrapper.so
uses: actions/upload-artifact@v4
with:
name: libvulkan_wrapper-unstripped
path: |
${{ env.BUILD_DIR }}/libvulkan_wrapper.so.unstripped
if-no-files-found: error
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Android NDK Build (Wrapper Variant)

on: [push]
on: [workflow_dispatch]

jobs:
build-android-wrapper:
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
meson setup _build \
--cross-file android-cross.toml \
-Dbuildtype=${{ matrix.build-type }} \
-Dplatforms=android,x11 \
-Dplatforms=x11 \
-Dandroid-stub=true \
-Dandroid-libbacktrace=disabled \
-Dplatform-sdk-version=30 \
Expand Down
86 changes: 86 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
FROM ghcr.io/termux/package-builder:latest

USER root

RUN apt-get update && \
apt-get install -y --no-install-recommends ninja-build && \
pip3 install --break-system-packages --ignore-installed --no-cache-dir meson ninja mako pyyaml packaging

RUN mkdir -p /tmp/sysroot && \
cd /tmp/sysroot && \
TERMUX_REPO="https://packages-cf.termux.dev/apt/termux-main" && \
curl -s "${TERMUX_REPO}/dists/stable/main/binary-aarch64/Packages" > Packages && \
PACKAGES="libdrm libandroid-shmem libxcb libx11 libxshmfence libxext libxrandr libxrender xorgproto libxau libxdmcp" && \
for pkg in $PACKAGES; do \
pkg_path=$(awk -v p="Package: $pkg" '$0==p{flag=1} flag && /^Filename:/{print $2; exit}' Packages) && \
curl -L -O "${TERMUX_REPO}/${pkg_path}"; \
done && \
mkdir -p /data/data/com.termux/files/usr && \
for f in *.deb; do dpkg-deb -x "$f" /; done && \
rm -rf /tmp/sysroot

RUN NDK_DIR=$(find /home/builder/lib -maxdepth 2 -name "android-ndk*" 2>/dev/null | head -n 1) && \
NDK_BIN="${NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin" && \
mkdir -p /root/build-config && \
cat << EOF > /root/build-config/cross_file.txt
[binaries]
c = '${NDK_BIN}/aarch64-linux-android30-clang'
cpp = '${NDK_BIN}/aarch64-linux-android30-clang++'
ar = '${NDK_BIN}/llvm-ar'
strip = '${NDK_BIN}/llvm-strip'
pkg-config = 'pkg-config'

[constants]
termux_dir = '/data/data/com.termux/files/usr'

[properties]
pkg_config_libdir = termux_dir + '/lib/pkgconfig:' + termux_dir + '/share/pkgconfig'

[built-in options]
c_args = ['-D__TERMUX__', '-D__USE_GNU', '-U__ANDROID__', '-I' + termux_dir + '/include', '-include', 'fcntl.h', '-include', 'unistd.h']
cpp_args = ['-D__TERMUX__', '-D__USE_GNU', '-U__ANDROID__', '-I' + termux_dir + '/include', '-include', 'fcntl.h', '-include', 'unistd.h']
c_link_args = ['-L' + termux_dir + '/lib', '-landroid-shmem']
cpp_link_args = ['-L' + termux_dir + '/lib', '-landroid-shmem']

[host_machine]
system = 'android'
cpu_family = 'aarch64'
cpu = 'armv8-a'
endian = 'little'
EOF

RUN cat << 'EOF' > /root/build.sh
#!/bin/bash
set -e

BUILD_DIR="${1:-${BUILD_DIR:-build}}"

if [ ! -d "${BUILD_DIR}" ]; then
meson setup "${BUILD_DIR}" --cross-file /root/build-config/cross_file.txt \
-Dcpp_rtti=false \
-Dgbm=disabled \
-Dopengl=false \
-Dllvm=disabled \
-Dshared-llvm=disabled \
-Dplatforms=x11 \
-Dgallium-drivers= \
-Dxmlconfig=disabled \
-Dvulkan-drivers=wrapper
fi

ninja -C "${BUILD_DIR}" src/vulkan/wrapper/libvulkan_wrapper.so

cp "${BUILD_DIR}/src/vulkan/wrapper/libvulkan_wrapper.so" "${BUILD_DIR}/libvulkan_wrapper.so.unstripped"

NDK_DIR=$(find /home/builder/lib -maxdepth 2 -name "android-ndk*" 2>/dev/null | head -n 1)
STRIP="${NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip"
$STRIP --strip-unneeded -o "${BUILD_DIR}/libvulkan_wrapper.so" "${BUILD_DIR}/libvulkan_wrapper.so.unstripped"

echo "Build successful:"
echo " - libvulkan_wrapper.so"
echo " - libvulkan_wrapper.so.unstripped"
EOF
RUN chmod +x /root/build.sh

WORKDIR /workspace
ENTRYPOINT ["/root/build.sh"]
69 changes: 68 additions & 1 deletion src/vulkan/wrapper/wrapper_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ get_wrapper_buffer_from_handle(struct wrapper_device *device, VkBuffer buffer) {
return wb;
}

static struct wrapper_image *
struct wrapper_image *
get_wrapper_image_from_handle(struct wrapper_device *device, VkImage image) {
struct wrapper_image *wi = NULL;

Expand Down Expand Up @@ -1001,6 +1001,29 @@ wrapper_CreateImage(VkDevice _device,
VK_FROM_HANDLE(wrapper_device, device, _device);
VkResult res;
VkImageCreateInfo create_info = *pCreateInfo;
bool is_emulated_bgra8 = false;
bool is_wsi_image = false;

// Wrapper specific extension for B8G8R8A8 AHB img emulation for the swapchain
VkBaseInStructure *prev = (VkBaseInStructure *) pCreateInfo;
for (const VkBaseInStructure *s = pCreateInfo->pNext; s; s = s->pNext) {
if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EMULATED_B8G8R8A8_CREATE_INFO_EXT) {
is_emulated_bgra8 = true;
prev->pNext = s->pNext; // unlink
break;
}
prev = (VkBaseInStructure *) s;
}

// 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;
}

if (is_emulated_bcn(device->physical, pCreateInfo->format)) {
create_info.format = get_format_for_bcn(pCreateInfo->format);
Expand Down Expand Up @@ -1042,6 +1065,8 @@ wrapper_CreateImage(VkDevice _device,
wi->device = device;
wi->info = *pCreateInfo;
wi->dispatch_handle = *pImage;
wi->is_emulated_bgra8 = is_emulated_bgra8;
wi->is_wsi_image = is_wsi_image;

list_add(&wi->link, &device->image_list);
_mesa_hash_table_u64_insert(device->image_table, (uint64_t)wi->dispatch_handle, wi);
Expand Down Expand Up @@ -2695,6 +2720,48 @@ wrapper_CmdCopyBufferToImage2(VkCommandBuffer commandBuffer,
format, pInfo->regionCount, regions);
}

VKAPI_ATTR void VKAPI_CALL
wrapper_CmdBlitImage(
VkCommandBuffer commandBuffer,
VkImage srcImage, VkImageLayout srcImageLayout,
VkImage dstImage, VkImageLayout dstImageLayout,
uint32_t regionCount, const VkImageBlit* pRegions,
VkFilter filter)
{
VK_FROM_HANDLE(wrapper_command_buffer, wcb, commandBuffer);
struct wrapper_device *device = wcb->device;
struct wrapper_image *dst_img = get_wrapper_image_from_handle(device, dstImage);
const VkImageBlit *regions = (const VkImageBlit *)pRegions;

if (dst_img && dst_img->is_emulated_bgra8) {
WRAPPER_LOG(error, "vkCmdBlitImage with is_emulated_bgra8 image");
}

device->dispatch_table.CmdBlitImage(
wcb->dispatch_handle,
srcImage, srcImageLayout,
dstImage, dstImageLayout,
regionCount, regions, filter);
}

VKAPI_ATTR void VKAPI_CALL
wrapper_CmdBlitImage2(
VkCommandBuffer commandBuffer,
const VkBlitImageInfo2 *pBlitImageInfo)
{
VK_FROM_HANDLE(wrapper_command_buffer, wcb, commandBuffer);
struct wrapper_device *device = wcb->device;
struct wrapper_image *dst_img = get_wrapper_image_from_handle(device, pBlitImageInfo->dstImage);

if (dst_img && dst_img->is_emulated_bgra8) {
WRAPPER_LOG(error, "vkCmdBlitImage2 with is_emulated_bgra8 image");
}

if (device->dispatch_table.CmdBlitImage2) {
device->dispatch_table.CmdBlitImage2(wcb->dispatch_handle, pBlitImageInfo);
}
}

VKAPI_ATTR void VKAPI_CALL
wrapper_FreeCommandBuffers(VkDevice _device,
VkCommandPool commandPool,
Expand Down
71 changes: 62 additions & 9 deletions src/vulkan/wrapper/wrapper_device_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ ion_heap_alloc(int heap_fd, size_t size) {
int saved_errno = errno;
struct ion_handle_data_1 free_data = { .handle = alloc_data.handle };
safe_ioctl(heap_fd, ION_IOC_FREE_1, &free_data);
WRAPPER_LOG("error", "Failed to share handle, errno=%d", alloc_data.handle, saved_errno);
WRAPPER_LOG("error", "Failed to share handle, errno=%d", saved_errno);
errno = saved_errno;
return -1;
}
Expand All @@ -167,7 +167,6 @@ wrapper_dmabuf_alloc(struct wrapper_device *device, size_t size)
return fd;
}


uint32_t
wrapper_select_device_memory_type(struct wrapper_device *device,
VkMemoryPropertyFlags flags) {
Expand All @@ -183,6 +182,26 @@ wrapper_select_device_memory_type(struct wrapper_device *device,
return idx < props->memoryTypeCount ? idx : UINT32_MAX;
}

static uint32_t
wrapper_select_allowed_device_memory_type(struct wrapper_device *device,
uint32_t allowed_type_bits,
VkMemoryPropertyFlags flags) {
VkPhysicalDeviceMemoryProperties *props =
&device->physical->memory_properties;
int idx;

for (idx = 0; idx < props->memoryTypeCount; idx++) {
if (!(allowed_type_bits & (1U << idx))) {
continue;
}

if (props->memoryTypes[idx].propertyFlags & flags) {
return idx;
}
}
return UINT32_MAX;
}

static VkResult
wrapper_allocate_memory_dmaheap(struct wrapper_device *device,
const VkMemoryAllocateInfo* pAllocateInfo,
Expand All @@ -209,6 +228,17 @@ wrapper_allocate_memory_dmaheap(struct wrapper_device *device,
WRAPPER_LOG(error, "Failed to get memory fd properties, res %d", result);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}

int memory_type_index = wrapper_select_allowed_device_memory_type(device,
memory_fd_props.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

if (memory_type_index == UINT32_MAX) {
WRAPPER_LOG(error, "No compatible memory type found for fd %d", *out_fd);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}

import_fd_info = (VkImportMemoryFdInfoKHR) {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
Expand All @@ -218,12 +248,7 @@ wrapper_allocate_memory_dmaheap(struct wrapper_device *device,
};
allocate_info = *pAllocateInfo;
allocate_info.pNext = &import_fd_info;
allocate_info.memoryTypeIndex =
wrapper_select_device_memory_type(device,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
memory_fd_props.memoryTypeBits);
allocate_info.memoryTypeIndex = memory_type_index;

result = device->dispatch_table.AllocateMemory(
device->dispatch_handle, &allocate_info,
Expand Down Expand Up @@ -439,6 +464,22 @@ wrapper_AllocateMemory(VkDevice _device,
if (vk_find_struct_const(pAllocateInfo, EXPORT_MEMORY_ALLOCATE_INFO))
goto fallback;

const VkMemoryDedicatedAllocateInfo *dedicated_allocate_info =
vk_find_struct_const((void*) pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO);

static int bypass_swapchains = -1;
if (bypass_swapchains == -1)
bypass_swapchains = getenv("WRAPPER_BYPASS_SWAPCHAIN_PLACED") ?
atoi(getenv("WRAPPER_BYPASS_SWAPCHAIN_PLACED")) : 0; // TODO: turn on by default if safe

if (bypass_swapchains && dedicated_allocate_info && dedicated_allocate_info->image != VK_NULL_HANDLE) {
struct wrapper_image *img = get_wrapper_image_from_handle(device, dedicated_allocate_info->image);
if (img && img->is_wsi_image) {
WRAPPER_LOG(info, "Bypassing EXT_map_memory_placed emulation for swapchain image");
goto fallback;
}
}

WRAPPER_LOG(info, "Emulating vkAllocateMemory");

simple_mtx_lock(&device->resource_mutex);
Expand Down Expand Up @@ -485,13 +526,25 @@ wrapper_AllocateMemory(VkDevice _device,
if (result != VK_SUCCESS) {
WRAPPER_LOG(error, "Failed to allocate memory, res %d", result);
wrapper_device_memory_destroy(mem);

if (dedicated_allocate_info && dedicated_allocate_info->image != VK_NULL_HANDLE) {
struct wrapper_image *img = get_wrapper_image_from_handle(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_lock(&device->resource_mutex);
goto fallback;
}
}

vk_error(device, result);
} else {
*pMemory = mem->dispatch_handle;
}

out:
simple_mtx_unlock(&mem->device->resource_mutex);
simple_mtx_unlock(&device->resource_mutex);
return result;

fallback:
Expand Down
1 change: 1 addition & 0 deletions src/vulkan/wrapper/wrapper_instance.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "vk_common_entrypoints.h"
#include "vk_dispatch_table.h"
#include "vk_extensions.h"
#include "adrenotools/driver.h"

const struct vk_instance_extension_table wrapper_instance_extensions = {
.KHR_get_surface_capabilities2 = true,
Expand Down
Loading
Loading