diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index e6c3d1d1b31..b67eefcc71b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -223,6 +223,7 @@ set(VULKAN_SRC vulkan/vk_query.cc vulkan/vk_resource_tracker.cc vulkan/vk_sampler.cc + vulkan/vk_samplers.cc vulkan/vk_shader.cc vulkan/vk_shader_interface.cc vulkan/vk_shader_log.cc @@ -261,6 +262,7 @@ set(VULKAN_SRC vulkan/vk_query.hh vulkan/vk_resource_tracker.hh vulkan/vk_sampler.hh + vulkan/vk_samplers.hh vulkan/vk_shader.hh vulkan/vk_shader_interface.hh vulkan/vk_shader_log.hh diff --git a/source/blender/gpu/vulkan/vk_bindable_resource.hh b/source/blender/gpu/vulkan/vk_bindable_resource.hh index a75f5d79423..713691f772d 100644 --- a/source/blender/gpu/vulkan/vk_bindable_resource.hh +++ b/source/blender/gpu/vulkan/vk_bindable_resource.hh @@ -23,7 +23,13 @@ class VKBindableResource { /** * Bind the resource to the shader. */ - virtual void bind(int binding, shader::ShaderCreateInfo::Resource::BindType bind_type) = 0; + virtual void bind(int binding, + shader::ShaderCreateInfo::Resource::BindType bind_type, + const GPUSamplerState /*sampler_state*/) + { + bind(binding, bind_type); + }; + virtual void bind(int /*binding*/, shader::ShaderCreateInfo::Resource::BindType /*bind_type*/){}; protected: void unbind_from_active_context(); @@ -41,6 +47,7 @@ template class VKBindSpac public: int binding; VKBindableResource *resource; + GPUSamplerState sampler_state; }; Vector bindings_; @@ -49,15 +56,18 @@ template class VKBindSpac /** * Register a binding to this namespace. */ - void bind(int binding, VKBindableResource &resource) + void bind(int binding, + VKBindableResource &resource, + const GPUSamplerState sampler_state = GPUSamplerState::default_sampler()) { for (ResourceBinding &bind : bindings_) { if (bind.binding == binding) { bind.resource = &resource; + bind.sampler_state = sampler_state; return; } } - ResourceBinding bind = {binding, &resource}; + ResourceBinding bind = {binding, &resource, sampler_state}; bindings_.append(bind); } @@ -67,7 +77,7 @@ template class VKBindSpac void apply_bindings() { for (ResourceBinding &binding : bindings_) { - binding.resource->bind(binding.binding, BindType); + binding.resource->bind(binding.binding, BindType, binding.sampler_state); } } diff --git a/source/blender/gpu/vulkan/vk_common.cc b/source/blender/gpu/vulkan/vk_common.cc index b75a62c1631..d835897a1e0 100644 --- a/source/blender/gpu/vulkan/vk_common.cc +++ b/source/blender/gpu/vulkan/vk_common.cc @@ -853,6 +853,23 @@ VkCullModeFlags to_vk_cull_mode_flags(const eGPUFaceCullTest cull_test) return VK_CULL_MODE_NONE; } +VkSamplerAddressMode to_vk_sampler_address_mode(const GPUSamplerExtendMode extend_mode) +{ + switch (extend_mode) { + case GPU_SAMPLER_EXTEND_MODE_EXTEND: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case GPU_SAMPLER_EXTEND_MODE_REPEAT: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + + BLI_assert_unreachable(); + return VK_SAMPLER_ADDRESS_MODE_REPEAT; +} + const char *to_string(VkObjectType type) { diff --git a/source/blender/gpu/vulkan/vk_common.hh b/source/blender/gpu/vulkan/vk_common.hh index 93c3b73a47b..f6499d27a1d 100644 --- a/source/blender/gpu/vulkan/vk_common.hh +++ b/source/blender/gpu/vulkan/vk_common.hh @@ -54,6 +54,7 @@ VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const voi VkIndexType to_vk_index_type(const GPUIndexBufType index_type); VkPrimitiveTopology to_vk_primitive_topology(const GPUPrimType prim_type); VkCullModeFlags to_vk_cull_mode_flags(const eGPUFaceCullTest cull_test); +VkSamplerAddressMode to_vk_sampler_address_mode(const GPUSamplerExtendMode extend_mode); const char *to_string(VkObjectType type); template VkObjectType to_vk_object_type(T /*vk_obj*/) diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index e5bf2951d68..cef1c35621c 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -23,6 +23,9 @@ namespace blender::gpu { void VKDevice::deinit() { + if (!is_initialized()) { + return; + } VK_ALLOCATION_CALLBACKS; vkDestroyCommandPool(vk_device_, vk_command_pool_, vk_allocation_callbacks); @@ -31,7 +34,7 @@ void VKDevice::deinit() delete &(*dummy_color_attachment_).get(); dummy_color_attachment_.reset(); } - sampler_.free(); + samplers_.free(); destroy_discarded_resources(); vmaDestroyAllocator(mem_allocator_); mem_allocator_ = VK_NULL_HANDLE; @@ -69,7 +72,7 @@ void VKDevice::init(void *ghost_context) init_command_pools(); init_descriptor_pools(); - sampler_.create(); + samplers_.init(); debug::object_label(device_get(), "LogicalDevice"); debug::object_label(queue_get(), "GenericQueue"); diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index fece612808d..e01217212a4 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -15,7 +15,7 @@ #include "vk_common.hh" #include "vk_debug.hh" #include "vk_descriptor_pools.hh" -#include "vk_sampler.hh" +#include "vk_samplers.hh" namespace blender::gpu { class VKBackend; @@ -60,8 +60,7 @@ class VKDevice : public NonCopyable { VkQueue vk_queue_ = VK_NULL_HANDLE; VkCommandPool vk_command_pool_ = VK_NULL_HANDLE; - /* Dummy sampler for now. */ - VKSampler sampler_; + VKSamplers samplers_; /** * Available Contexts for this device. @@ -167,9 +166,9 @@ class VKDevice : public NonCopyable { return debugging_tools_; } - const VKSampler &sampler_get() const + VKSamplers &samplers() { - return sampler_; + return samplers_; } const VkCommandPool vk_command_pool_get() const diff --git a/source/blender/gpu/vulkan/vk_sampler.cc b/source/blender/gpu/vulkan/vk_sampler.cc index 6cb4bc04dde..f89e72d405c 100644 --- a/source/blender/gpu/vulkan/vk_sampler.cc +++ b/source/blender/gpu/vulkan/vk_sampler.cc @@ -11,30 +11,71 @@ #include "vk_context.hh" #include "vk_memory.hh" +#include "DNA_userdef_types.h" + namespace blender::gpu { VKSampler::~VKSampler() { free(); } -void VKSampler::create() +void VKSampler::create(const GPUSamplerState &sampler_state) { + BLI_assert(sampler_state.type != GPU_SAMPLER_STATE_TYPE_INTERNAL); BLI_assert(vk_sampler_ == VK_NULL_HANDLE); - VK_ALLOCATION_CALLBACKS - VkSamplerCreateInfo sampler_info = {}; sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + + if (sampler_state.type == GPU_SAMPLER_STATE_TYPE_PARAMETERS) { + /* Apply filtering. */ + if (sampler_state.filtering & GPU_SAMPLER_FILTERING_LINEAR) { + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + } + if (sampler_state.filtering & GPU_SAMPLER_FILTERING_MIPMAP) { + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + } + if (sampler_state.filtering & GPU_SAMPLER_FILTERING_ANISOTROPIC) { + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = min_ff(1.0f, U.anisotropic_filter); + } + + /* Extend */ + sampler_info.addressModeU = to_vk_sampler_address_mode(sampler_state.extend_x); + sampler_info.addressModeV = sampler_info.addressModeW = to_vk_sampler_address_mode( + sampler_state.extend_yz); + } + else if (sampler_state.type == GPU_SAMPLER_STATE_TYPE_CUSTOM) { + if (sampler_state.custom_type == GPU_SAMPLER_CUSTOM_ICON) { + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + sampler_info.minLod = 0; + sampler_info.maxLod = 1; + } + else if (sampler_state.custom_type == GPU_SAMPLER_CUSTOM_COMPARE) { + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.compareEnable = VK_TRUE; + sampler_info.compareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + sampler_info.minLod = -1000; + sampler_info.maxLod = 1000; + } + } + + VK_ALLOCATION_CALLBACKS const VKDevice &device = VKBackend::get().device_get(); vkCreateSampler(device.device_get(), &sampler_info, vk_allocation_callbacks, &vk_sampler_); - debug::object_label(vk_sampler_, "DummySampler"); + debug::object_label(vk_sampler_, sampler_state.to_string().c_str()); } void VKSampler::free() { - VK_ALLOCATION_CALLBACKS if (vk_sampler_ != VK_NULL_HANDLE) { + VK_ALLOCATION_CALLBACKS + const VKDevice &device = VKBackend::get().device_get(); if (device.device_get() != VK_NULL_HANDLE) { vkDestroySampler(device.device_get(), vk_sampler_, vk_allocation_callbacks); diff --git a/source/blender/gpu/vulkan/vk_sampler.hh b/source/blender/gpu/vulkan/vk_sampler.hh index 9b350eef0df..fccf448a533 100644 --- a/source/blender/gpu/vulkan/vk_sampler.hh +++ b/source/blender/gpu/vulkan/vk_sampler.hh @@ -22,7 +22,7 @@ class VKSampler : public NonCopyable { public: virtual ~VKSampler(); - void create(); + void create(const GPUSamplerState &sampler_state); void free(); VkSampler vk_handle() const @@ -30,6 +30,11 @@ class VKSampler : public NonCopyable { BLI_assert(vk_sampler_ != VK_NULL_HANDLE); return vk_sampler_; } + + bool is_initialized() const + { + return vk_sampler_ != VK_NULL_HANDLE; + } }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_samplers.cc b/source/blender/gpu/vulkan/vk_samplers.cc new file mode 100644 index 00000000000..5f725993551 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_samplers.cc @@ -0,0 +1,58 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#include "vk_samplers.hh" + +namespace blender::gpu { + +void VKSamplers::init() +{ + if (custom_sampler_cache_[0].is_initialized()) { + return; + } + custom_sampler_cache_[GPU_SAMPLER_CUSTOM_COMPARE].create(GPUSamplerState::compare_sampler()); + custom_sampler_cache_[GPU_SAMPLER_CUSTOM_ICON].create(GPUSamplerState::icon_sampler()); + + GPUSamplerState state = {}; + for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) { + state.extend_yz = static_cast(extend_yz_i); + for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) { + state.extend_x = static_cast(extend_x_i); + for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) { + state.filtering = GPUSamplerFiltering(filtering_i); + sampler_cache_[extend_yz_i][extend_x_i][filtering_i].create(state); + } + } + } +} + +void VKSamplers::free() +{ + custom_sampler_cache_[GPU_SAMPLER_CUSTOM_COMPARE].free(); + custom_sampler_cache_[GPU_SAMPLER_CUSTOM_ICON].free(); + + for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) { + for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) { + for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) { + sampler_cache_[extend_yz_i][extend_x_i][filtering_i].free(); + } + } + } +} + +const VKSampler &VKSamplers::get(const GPUSamplerState &sampler_state) +{ + BLI_assert(sampler_state.type != GPU_SAMPLER_STATE_TYPE_INTERNAL); + + if (sampler_state.type == GPU_SAMPLER_STATE_TYPE_CUSTOM) { + return custom_sampler_cache_[sampler_state.custom_type]; + } + return sampler_cache_[sampler_state.extend_yz][sampler_state.extend_x][sampler_state.filtering]; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_samplers.hh b/source/blender/gpu/vulkan/vk_samplers.hh new file mode 100644 index 00000000000..38a3db1937b --- /dev/null +++ b/source/blender/gpu/vulkan/vk_samplers.hh @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "vk_sampler.hh" +#include "vk_samplers.hh" + +#include "BLI_map.hh" + +namespace blender::gpu { + +/** + * Collection of samplers. + * + * Samplers are device owned and can be shared between contexts. + */ +class VKSamplers : NonCopyable { + VKSampler sampler_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT][GPU_SAMPLER_EXTEND_MODES_COUNT] + [GPU_SAMPLER_FILTERING_TYPES_COUNT]; + VKSampler custom_sampler_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT]; + + public: + void init(); + void free(); + + const VKSampler &get(const GPUSamplerState &sampler_state); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_state_manager.cc b/source/blender/gpu/vulkan/vk_state_manager.cc index 1234dff12f1..85aaf86d9dc 100644 --- a/source/blender/gpu/vulkan/vk_state_manager.cc +++ b/source/blender/gpu/vulkan/vk_state_manager.cc @@ -57,10 +57,10 @@ void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/) context.flush(); } -void VKStateManager::texture_bind(Texture *tex, GPUSamplerState /*sampler*/, int unit) +void VKStateManager::texture_bind(Texture *tex, GPUSamplerState sampler, int unit) { VKTexture *texture = unwrap(tex); - textures_.bind(unit, *texture); + textures_.bind(unit, *texture, sampler); } void VKStateManager::texture_unbind(Texture *tex) diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 31a0fbb1e1b..eff9be5f969 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -514,7 +514,9 @@ bool VKTexture::allocate() return result == VK_SUCCESS; } -void VKTexture::bind(int binding, shader::ShaderCreateInfo::Resource::BindType bind_type) +void VKTexture::bind(int binding, + shader::ShaderCreateInfo::Resource::BindType bind_type, + const GPUSamplerState sampler_state) { VKContext &context = *VKContext::get(); VKShader *shader = static_cast(context.shader); @@ -527,8 +529,9 @@ void VKTexture::bind(int binding, shader::ShaderCreateInfo::Resource::BindType b descriptor_set.image_bind(*this, *location); } else { - const VKDevice &device = VKBackend::get().device_get(); - descriptor_set.bind(*this, *location, device.sampler_get()); + VKDevice &device = VKBackend::get().device_get(); + const VKSampler &sampler = device.samplers().get(sampler_state); + descriptor_set.bind(*this, *location, sampler); } } } diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh index 1e7d78d882a..c109daf9c41 100644 --- a/source/blender/gpu/vulkan/vk_texture.hh +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -84,7 +84,9 @@ class VKTexture : public Texture, public VKBindableResource { /* TODO(fclem): Legacy. Should be removed at some point. */ uint gl_bindcode_get() const override; - void bind(int location, shader::ShaderCreateInfo::Resource::BindType bind_type) override; + void bind(int location, + shader::ShaderCreateInfo::Resource::BindType bind_type, + const GPUSamplerState sampler_state) override; VkImage vk_image_handle() const {