Vulkan: Implement Samplers
Until now the Vulkan backend supported a single pre-configured sampler. This PR realizes creation, caching and freeing of samplers based on what is required by the state manager. The implementation is similar to OpenGL or Metal. This fixes many issues including: - Textures in workbench and eevee use the correct extend and filtering - Custom icons render correctly - Depth sampling issues - Removes artifacts using EEVEE world shader, lighting and indirect lighting. Pull Request: https://projects.blender.org/blender/blender/pulls/114827
This commit is contained in:
parent
2020f35981
commit
00f5ae2a8f
|
@ -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
|
||||
|
|
|
@ -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<shader::ShaderCreateInfo::Resource::BindType BindType> class VKBindSpac
|
|||
public:
|
||||
int binding;
|
||||
VKBindableResource *resource;
|
||||
GPUSamplerState sampler_state;
|
||||
};
|
||||
|
||||
Vector<ResourceBinding> bindings_;
|
||||
|
@ -49,15 +56,18 @@ template<shader::ShaderCreateInfo::Resource::BindType BindType> 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<shader::ShaderCreateInfo::Resource::BindType BindType> class VKBindSpac
|
|||
void apply_bindings()
|
||||
{
|
||||
for (ResourceBinding &binding : bindings_) {
|
||||
binding.resource->bind(binding.binding, BindType);
|
||||
binding.resource->bind(binding.binding, BindType, binding.sampler_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
|
|
|
@ -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<typename T> VkObjectType to_vk_object_type(T /*vk_obj*/)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<GPUSamplerExtendMode>(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<GPUSamplerExtendMode>(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
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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<VKShader *>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue