diff --git a/CMakeLists.txt b/CMakeLists.txt index 1445b0a87e2..c6de0fb001d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -625,8 +625,10 @@ mark_as_advanced( # Vulkan option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF) +option(WITH_VULKAN_GUARDEDALLOC "Use guardedalloc for host allocations done inside Vulkan (development option)" OFF) mark_as_advanced( WITH_VULKAN_BACKEND + WITH_VULKAN_GUARDEDALLOC ) # Metal diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 4967d8984c5..623dd899717 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -195,6 +195,7 @@ set(VULKAN_SRC vulkan/vk_fence.cc vulkan/vk_framebuffer.cc vulkan/vk_index_buffer.cc + vulkan/vk_memory.cc vulkan/vk_pixel_buffer.cc vulkan/vk_query.cc vulkan/vk_shader.cc @@ -211,6 +212,7 @@ set(VULKAN_SRC vulkan/vk_fence.hh vulkan/vk_framebuffer.hh vulkan/vk_index_buffer.hh + vulkan/vk_memory.hh vulkan/vk_pixel_buffer.hh vulkan/vk_query.hh vulkan/vk_shader.hh @@ -303,6 +305,10 @@ if(WITH_VULKAN_BACKEND) add_definitions(-DWITH_VULKAN_BACKEND) endif() +if(WITH_VULKAN_GUARDEDALLOC) + add_definitions(-DWITH_VULKAN_GUARDEDALLOC) +endif() + set(MSL_SRC shaders/metal/mtl_shader_defines.msl shaders/metal/mtl_shader_common.msl diff --git a/source/blender/gpu/vulkan/vk_memory.cc b/source/blender/gpu/vulkan/vk_memory.cc new file mode 100644 index 00000000000..e02ca0b014f --- /dev/null +++ b/source/blender/gpu/vulkan/vk_memory.cc @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_memory.hh" + +#include "MEM_guardedalloc.h" + +namespace blender::gpu { + +#ifdef WITH_VULKAN_GUARDEDALLOC + +void *vk_memory_allocation(void *user_data, + size_t size, + size_t alignment, + VkSystemAllocationScope /*scope*/) +{ + const char *name = static_cast(const_cast(user_data)); + if (alignment) { + return MEM_mallocN_aligned(size, alignment, name); + } + return MEM_mallocN(size, name); +} + +void *vk_memory_reallocation(void *user_data, + void *original, + size_t size, + size_t /*alignment*/, + VkSystemAllocationScope /*scope*/) +{ + const char *name = static_cast(const_cast(user_data)); + return MEM_reallocN_id(original, size, name); +} + +void vk_memory_free(void * /*user_data*/, void *memory) +{ + MEM_freeN(memory); +} + +#endif + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory.hh b/source/blender/gpu/vulkan/vk_memory.hh new file mode 100644 index 00000000000..91802cb8193 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_memory.hh @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#ifdef __APPLE__ +# include +#else +# include +#endif + +namespace blender::gpu { + +/** + * `VK_ALLOCATION_CALLBACKS` initializes allocation callbacks for host allocations. + * The macro creates a local static variable with the name `vk_allocation_callbacks` + * that can be passed to vulkan API functions that expect + * `const VkAllocationCallbacks *pAllocator`. + * + * When Blender is compiled with `WITH_VULKAN_GUARDEDALLOC` this will use + * `MEM_guardedalloc` for host allocations that the driver does on behalf + * of blender. More internal allocations are still being allocated via the + * implemention inside the vulkan device driver. + * + * When `WITH_VULKAN_GUARDEDALLOC=Off` the memory allocation implemented + * in the vulkan device driver is used for both internal and application + * focussed memory operations. + */ + +#ifdef WITH_VULKAN_GUARDEDALLOC +void *vk_memory_allocation(void *user_data, + size_t size, + size_t alignment, + VkSystemAllocationScope scope); +void *vk_memory_reallocation( + void *user_data, void *original, size_t size, size_t alignment, VkSystemAllocationScope scope); +void vk_memory_free(void *user_data, void *memory); + +constexpr VkAllocationCallbacks vk_allocation_callbacks_init(const char *name) +{ + VkAllocationCallbacks callbacks = {}; + callbacks.pUserData = const_cast(name); + callbacks.pfnAllocation = vk_memory_allocation; + callbacks.pfnReallocation = vk_memory_reallocation; + callbacks.pfnFree = vk_memory_free; + callbacks.pfnInternalAllocation = nullptr; + callbacks.pfnInternalFree = nullptr; + return callbacks; +} + +# define VK_ALLOCATION_CALLBACKS \ + static constexpr const VkAllocationCallbacks vk_allocation_callbacks_ = \ + vk_allocation_callbacks_init(__func__); \ + static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = &vk_allocation_callbacks_; +#else +# define VK_ALLOCATION_CALLBACKS \ + static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = nullptr; +#endif + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 17c06fb42e6..3f145bd4763 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -8,6 +8,7 @@ #include "vk_shader.hh" #include "vk_backend.hh" +#include "vk_memory.hh" #include "vk_shader_log.hh" #include "BLI_string_utils.h" @@ -559,6 +560,8 @@ Vector VKShader::compile_glsl_to_spirv(Span sources, void VKShader::build_shader_module(Span spirv_module, VkShaderModule *r_shader_module) { + VK_ALLOCATION_CALLBACKS; + VkShaderModuleCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; create_info.codeSize = spirv_module.size() * sizeof(uint32_t); @@ -567,7 +570,7 @@ void VKShader::build_shader_module(Span spirv_module, VkShaderModule * VKContext &context = *static_cast(VKContext::get()); VkResult result = vkCreateShaderModule( - context.device_get(), &create_info, nullptr, r_shader_module); + context.device_get(), &create_info, vk_allocation_callbacks, r_shader_module); if (result != VK_SUCCESS) { compilation_failed_ = true; *r_shader_module = VK_NULL_HANDLE; @@ -581,21 +584,23 @@ VKShader::VKShader(const char *name) : Shader(name) VKShader::~VKShader() { + VK_ALLOCATION_CALLBACKS + VkDevice device = context_->device_get(); if (vertex_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device, vertex_module_, nullptr); + vkDestroyShaderModule(device, vertex_module_, vk_allocation_callbacks); vertex_module_ = VK_NULL_HANDLE; } if (geometry_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device, geometry_module_, nullptr); + vkDestroyShaderModule(device, geometry_module_, vk_allocation_callbacks); geometry_module_ = VK_NULL_HANDLE; } if (fragment_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device, fragment_module_, nullptr); + vkDestroyShaderModule(device, fragment_module_, vk_allocation_callbacks); fragment_module_ = VK_NULL_HANDLE; } if (compute_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device, compute_module_, nullptr); + vkDestroyShaderModule(device, compute_module_, vk_allocation_callbacks); compute_module_ = VK_NULL_HANDLE; } }