Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d3b1450e authored by Jesse Hall's avatar Jesse Hall
Browse files

vknulldrv: Use a default allocator when none provided

The loader used to always provide an allocator, even if the app
didn't. It no longer does that, so the null driver must be prepared to
provide its own default allocator.

Fixes bug 28303142

Change-Id: I6ab946913dc4edaf2a0b07ab9ae8c43be69b3ed6
parent 151cc4a9
Loading
Loading
Loading
Loading
+55 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <algorithm>
#include <array>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>

#include <log/log.h>
@@ -186,6 +187,58 @@ Handle AllocHandle(VkDevice device, HandleType::Enum type) {
        AllocHandle(type, &device->next_handle[type]));
}

VKAPI_ATTR void* DefaultAllocate(void*,
                                 size_t size,
                                 size_t alignment,
                                 VkSystemAllocationScope) {
    void* ptr = nullptr;
    // Vulkan requires 'alignment' to be a power of two, but posix_memalign
    // additionally requires that it be at least sizeof(void*).
    int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
    return ret == 0 ? ptr : nullptr;
}

VKAPI_ATTR void* DefaultReallocate(void*,
                                   void* ptr,
                                   size_t size,
                                   size_t alignment,
                                   VkSystemAllocationScope) {
    if (size == 0) {
        free(ptr);
        return nullptr;
    }

    // TODO(jessehall): Right now we never shrink allocations; if the new
    // request is smaller than the existing chunk, we just continue using it.
    // The null driver never reallocs, so this doesn't matter. If that changes,
    // or if this code is copied into some other project, this should probably
    // have a heuristic to allocate-copy-free when doing so will save "enough"
    // space.
    size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
    if (size <= old_size)
        return ptr;

    void* new_ptr = nullptr;
    if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
        return nullptr;
    if (ptr) {
        memcpy(new_ptr, ptr, std::min(old_size, size));
        free(ptr);
    }
    return new_ptr;
}

VKAPI_ATTR void DefaultFree(void*, void* ptr) {
    free(ptr);
}

const VkAllocationCallbacks kDefaultAllocCallbacks = {
    .pUserData = nullptr,
    .pfnAllocation = DefaultAllocate,
    .pfnReallocation = DefaultReallocate,
    .pfnFree = DefaultFree,
};

}  // namespace

namespace null_driver {
@@ -239,10 +292,8 @@ VKAPI_ATTR
VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
                        const VkAllocationCallbacks* allocator,
                        VkInstance* out_instance) {
    // Assume the loader provided alloc callbacks even if the app didn't.
    ALOG_ASSERT(
        allocator,
        "Missing alloc callbacks, loader or app should have provided them");
    if (!allocator)
        allocator = &kDefaultAllocCallbacks;

    VkInstance_T* instance =
        static_cast<VkInstance_T*>(allocator->pfnAllocation(