Vulkan: Add support for descriptor buffers

Descriptor sets/pools are known to be troublesome as it doesn't match
how GPUs work, or how application want to work, adding more complexity
than needed. This results is quite an overhead allocating and
deallocating descriptor sets.

This PR will use descriptor buffers when they are available. Most platforms
support descriptor buffers. When not available descriptor pools/sets
will be used.

Although this is a feature I would like to land it in 4.5 due to the API changes.
This makes it easier to fix issues when 4.5 is released.
The feature can easily be disabled by setting the feature to false if it has
to many problems.

Pull Request: https://projects.blender.org/blender/blender/pulls/138266
This commit is contained in:
Jeroen Bakker
2025-06-06 10:20:36 +02:00
parent 12ee7eb18e
commit 66d361bd29
25 changed files with 730 additions and 131 deletions

View File

@@ -306,6 +306,7 @@ class GHOST_DeviceVK {
vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
vulkan_12_features.shaderOutputLayer = features_12.shaderOutputLayer;
vulkan_12_features.shaderOutputViewportIndex = features_12.shaderOutputViewportIndex;
vulkan_12_features.bufferDeviceAddress = features_12.bufferDeviceAddress;
vulkan_12_features.timelineSemaphore = VK_TRUE;
feature_struct_ptr.push_back(&vulkan_12_features);
@@ -365,6 +366,18 @@ class GHOST_DeviceVK {
use_vk_ext_swapchain_maintenance_1 = true;
}
/* Descriptor buffers */
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
nullptr,
VK_TRUE,
VK_FALSE,
VK_FALSE,
VK_FALSE};
if (extension_requested(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) {
feature_struct_ptr.push_back(&descriptor_buffer);
}
/* Query and enable Fragment Shader Barycentrics. */
VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR fragment_shader_barycentric = {};
fragment_shader_barycentric.sType =
@@ -1220,6 +1233,8 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
optional_device_extensions.push_back(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
optional_device_extensions.push_back(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
optional_device_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
optional_device_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
optional_device_extensions.push_back(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
VkInstance instance = VK_NULL_HANDLE;
if (!vulkan_device.has_value()) {

View File

@@ -55,6 +55,40 @@ void vk_pipeline_data_build_commands(VKCommandBufferInterface &command_buffer,
nullptr);
}
if (assign_if_different(r_bound_pipeline.descriptor_buffer_device_address,
pipeline_data.descriptor_buffer_device_address) &&
r_bound_pipeline.descriptor_buffer_device_address != 0)
{
r_bound_pipeline.descriptor_buffer_offset = pipeline_data.descriptor_buffer_offset;
VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT,
nullptr,
r_bound_pipeline.descriptor_buffer_device_address,
VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT |
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT};
command_buffer.bind_descriptor_buffers(1, &descriptor_buffer_binding_info);
uint32_t buffer_index = 0;
command_buffer.set_descriptor_buffer_offsets(vk_pipeline_bind_point,
pipeline_data.vk_pipeline_layout,
0,
1,
&buffer_index,
&r_bound_pipeline.descriptor_buffer_offset);
}
else if (assign_if_different(r_bound_pipeline.descriptor_buffer_offset,
pipeline_data.descriptor_buffer_offset) &&
r_bound_pipeline.descriptor_buffer_device_address != 0)
{
uint32_t buffer_index = 0;
command_buffer.set_descriptor_buffer_offsets(vk_pipeline_bind_point,
pipeline_data.vk_pipeline_layout,
0,
1,
&buffer_index,
&r_bound_pipeline.descriptor_buffer_offset);
}
if (pipeline_data.push_constants_size) {
command_buffer.push_constants(pipeline_data.vk_pipeline_layout,
vk_shader_stage_flags,

View File

@@ -24,6 +24,10 @@ struct VKPipelineData {
VkPipeline vk_pipeline;
VkPipelineLayout vk_pipeline_layout;
VkDescriptorSet vk_descriptor_set;
/* VK_EXT_descriptor_buffer */
VkDeviceAddress descriptor_buffer_device_address;
VkDeviceSize descriptor_buffer_offset;
uint32_t push_constants_size;
const void *push_constants_data;
};
@@ -65,6 +69,8 @@ struct VKViewportData {
struct VKBoundPipeline {
VkPipeline vk_pipeline;
VkDescriptorSet vk_descriptor_set;
VkDeviceAddress descriptor_buffer_device_address;
VkDeviceSize descriptor_buffer_offset;
};
struct VKIndexBufferBinding {

View File

@@ -476,6 +476,21 @@ class CommandBufferLog : public VKCommandBufferInterface {
void begin_debug_utils_label(const VkDebugUtilsLabelEXT * /*vk_debug_utils_label*/) override {}
void end_debug_utils_label() override {}
/* VK_EXT_descriptor_buffer */
void bind_descriptor_buffers(
uint32_t /*buffer_count*/,
const VkDescriptorBufferBindingInfoEXT * /*p_binding_infos*/) override
{
}
void set_descriptor_buffer_offsets(VkPipelineBindPoint /*pipeline_bind_point*/,
VkPipelineLayout /*layout*/,
uint32_t /*first_set*/,
uint32_t /*set_count*/,
const uint32_t * /*p_buffer_indices*/,
const VkDeviceSize * /*p_offsets*/) override
{
}
};
class VKRenderGraphTest : public ::testing::Test {

View File

@@ -326,4 +326,28 @@ void VKCommandBufferWrapper::end_debug_utils_label()
}
}
/* VK_EXT_descriptor_buffer */
void VKCommandBufferWrapper::bind_descriptor_buffers(
uint32_t buffer_count, const VkDescriptorBufferBindingInfoEXT *p_binding_infos)
{
const VKDevice &device = VKBackend::get().device;
device.functions.vkCmdBindDescriptorBuffers(vk_command_buffer_, buffer_count, p_binding_infos);
}
void VKCommandBufferWrapper::set_descriptor_buffer_offsets(VkPipelineBindPoint pipeline_bind_point,
VkPipelineLayout layout,
uint32_t first_set,
uint32_t set_count,
const uint32_t *p_buffer_indices,
const VkDeviceSize *p_offsets)
{
const VKDevice &device = VKBackend::get().device;
device.functions.vkCmdSetDescriptorBufferOffsets(vk_command_buffer_,
pipeline_bind_point,
layout,
first_set,
set_count,
p_buffer_indices,
p_offsets);
}
} // namespace blender::gpu::render_graph

View File

@@ -141,6 +141,16 @@ class VKCommandBufferInterface {
/* VK_EXT_debug_utils */
virtual void begin_debug_utils_label(const VkDebugUtilsLabelEXT *vk_debug_utils_label) = 0;
virtual void end_debug_utils_label() = 0;
/* VK_EXT_descriptor_buffer */
virtual void bind_descriptor_buffers(
uint32_t buffer_count, const VkDescriptorBufferBindingInfoEXT *p_binding_infos) = 0;
virtual void set_descriptor_buffer_offsets(VkPipelineBindPoint pipeline_bind_point,
VkPipelineLayout layout,
uint32_t first_set,
uint32_t set_count,
const uint32_t *p_buffer_indices,
const VkDeviceSize *p_offsets) = 0;
};
class VKCommandBufferWrapper : public VKCommandBufferInterface {
@@ -261,6 +271,16 @@ class VKCommandBufferWrapper : public VKCommandBufferInterface {
void end_rendering() override;
void begin_debug_utils_label(const VkDebugUtilsLabelEXT *vk_debug_utils_label) override;
void end_debug_utils_label() override;
/* VK_EXT_descriptor_buffer */
void bind_descriptor_buffers(uint32_t buffer_count,
const VkDescriptorBufferBindingInfoEXT *p_binding_infos) override;
void set_descriptor_buffer_offsets(VkPipelineBindPoint pipeline_bind_point,
VkPipelineLayout layout,
uint32_t first_set,
uint32_t set_count,
const uint32_t *p_buffer_indices,
const VkDeviceSize *p_offsets) override;
};
} // namespace blender::gpu::render_graph

View File

@@ -327,7 +327,7 @@ struct VKRenderGraphNode {
}
};
BLI_STATIC_ASSERT(sizeof(VKRenderGraphNode) <= 64,
BLI_STATIC_ASSERT(sizeof(VKRenderGraphNode) <= 96,
"VKRenderGraphNode should be kept small. Consider moving data to the "
"VKRenderGraphStorage class.");

View File

@@ -137,6 +137,9 @@ static Vector<StringRefNull> missing_capabilities_get(VkPhysicalDevice vk_physic
if (features_12.timelineSemaphore == VK_FALSE) {
missing_capabilities.append("timeline semaphores");
}
if (features_12.bufferDeviceAddress == VK_FALSE) {
missing_capabilities.append("buffer device address");
}
/* Check device extensions. */
uint32_t vk_extension_count;
@@ -385,6 +388,7 @@ void VKBackend::detect_workarounds(VKDevice &device)
extensions.dynamic_rendering = false;
extensions.dynamic_rendering_local_read = false;
extensions.dynamic_rendering_unused_attachments = false;
extensions.descriptor_buffer = false;
GCaps.render_pass_workaround = true;
@@ -414,6 +418,8 @@ void VKBackend::detect_workarounds(VKDevice &device)
#else
extensions.external_memory = false;
#endif
extensions.descriptor_buffer = device.supports_extension(
VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
/* AMD GPUs don't support texture formats that use are aligned to 24 or 48 bits. */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) ||

View File

@@ -77,6 +77,11 @@ bool VKBuffer::create(size_t size_in_bytes,
vma_create_info.pool = device.vma_pools.external_memory;
}
const bool use_descriptor_buffer = device.extensions_get().descriptor_buffer;
if (use_descriptor_buffer) {
create_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
}
VkResult result = vmaCreateBuffer(
allocator, &create_info, &vma_create_info, &vk_buffer_, &allocation_, nullptr);
if (result != VK_SUCCESS) {
@@ -88,11 +93,18 @@ bool VKBuffer::create(size_t size_in_bytes,
device.resources.add_buffer(vk_buffer_);
vmaGetAllocationMemoryProperties(allocator, allocation_, &vk_memory_property_flags_);
if (use_descriptor_buffer) {
VkBufferDeviceAddressInfo vk_buffer_device_address_info = {
VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, vk_buffer_};
vk_device_address = vkGetBufferDeviceAddress(device.vk_handle(),
&vk_buffer_device_address_info);
}
vmaGetAllocationMemoryProperties(allocator, allocation_, &vk_memory_property_flags_);
if (vk_memory_property_flags_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
return map();
}
return true;
}

View File

@@ -33,8 +33,11 @@ class VKBuffer : public NonCopyable {
/* Pointer to the virtually mapped memory. */
void *mapped_memory_ = nullptr;
VkDeviceAddress vk_device_address = 0;
public:
VKBuffer() = default;
VKBuffer(VKBuffer &&other) = default;
virtual ~VKBuffer();
/** Has this buffer been allocated? */
@@ -108,6 +111,11 @@ class VKBuffer : public NonCopyable {
*/
void *mapped_memory_get() const;
VkDeviceAddress device_address_get() const
{
return vk_device_address;
}
/**
* Is this buffer mapped (visible on host)
*/

View File

@@ -157,9 +157,11 @@ TimelineValue VKContext::flush_render_graph(RenderGraphFlushFlags flags,
framebuffer.rendering_end(*this);
}
}
descriptor_set_get().upload_descriptor_sets();
descriptor_pools_get().discard(*this);
VKDevice &device = VKBackend::get().device;
descriptor_set_get().upload_descriptor_sets();
if (!device.extensions_get().descriptor_buffer) {
descriptor_pools_get().discard(*this);
}
TimelineValue timeline = device.render_graph_submit(
&render_graph_.value().get(),
discard_pool,
@@ -317,8 +319,7 @@ void VKContext::update_pipeline_data(VKShader &vk_shader,
r_pipeline_data.vk_descriptor_set = VK_NULL_HANDLE;
if (vk_shader.has_descriptor_set()) {
VKDescriptorSetTracker &descriptor_set = descriptor_set_get();
descriptor_set.update_descriptor_set(*this, access_info_);
r_pipeline_data.vk_descriptor_set = descriptor_set.vk_descriptor_set;
descriptor_set.update_descriptor_set(*this, access_info_, r_pipeline_data);
}
}

View File

@@ -17,61 +17,49 @@
namespace blender::gpu {
void VKDescriptorSetTracker::bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer vk_buffer,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location)
void VKDescriptorSetTracker::update_descriptor_set(VKContext &context,
render_graph::VKResourceAccessInfo &access_info,
render_graph::VKPipelineData &r_pipeline_data)
{
vk_descriptor_buffer_infos_.append({vk_buffer, buffer_offset, size_in_bytes});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
vk_descriptor_type,
nullptr,
nullptr,
nullptr});
VKShader &shader = *unwrap(context.shader);
VKStateManager &state_manager = context.state_manager_get();
/* Can we reuse previous descriptor set. */
if (!state_manager.is_dirty &&
!assign_if_different(vk_descriptor_set_layout_, shader.vk_descriptor_set_layout_get()) &&
shader.push_constants.layout_get().storage_type_get() !=
VKPushConstants::StorageType::UNIFORM_BUFFER)
{
return;
}
state_manager.is_dirty = false;
VKDevice &device = VKBackend::get().device;
VkDescriptorSetLayout vk_descriptor_set_layout = shader.vk_descriptor_set_layout_get();
VKDescriptorSetUpdator *updator = &descriptor_sets;
if (device.extensions_get().descriptor_buffer) {
updator = &descriptor_buffers;
}
updator->allocate_new_descriptor_set(
device, context, shader, vk_descriptor_set_layout, r_pipeline_data);
updator->bind_shader_resources(device, state_manager, shader, access_info);
}
void VKDescriptorSetTracker::bind_texel_buffer(VkBufferView vk_buffer_view,
const VKDescriptorSet::Location location)
void VKDescriptorSetTracker::upload_descriptor_sets()
{
vk_buffer_views_.append(vk_buffer_view);
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
nullptr,
nullptr,
nullptr});
VKDevice &device = VKBackend::get().device;
VKDescriptorSetUpdator &updator = descriptor_sets;
if (device.extensions_get().descriptor_buffer) {
updator = descriptor_buffers;
}
updator.upload_descriptor_sets();
}
void VKDescriptorSetTracker::bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location)
{
vk_descriptor_image_infos_.append({vk_sampler, vk_image_view, vk_image_layout});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
vk_descriptor_type,
nullptr,
nullptr,
nullptr});
}
/* -------------------------------------------------------------------- */
/** \name VKDescriptorSetUpdator
* \{ */
void VKDescriptorSetTracker::bind_image_resource(const VKStateManager &state_manager,
void VKDescriptorSetUpdator::bind_image_resource(const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info)
{
@@ -97,7 +85,7 @@ void VKDescriptorSetTracker::bind_image_resource(const VKStateManager &state_man
layer_count});
}
void VKDescriptorSetTracker::bind_texture_resource(const VKDevice &device,
void VKDescriptorSetUpdator::bind_texture_resource(const VKDevice &device,
const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info)
@@ -105,11 +93,10 @@ void VKDescriptorSetTracker::bind_texture_resource(const VKDevice &device,
const BindSpaceTextures::Elem &elem = state_manager.textures_.get(resource_binding.binding);
switch (elem.resource_type) {
case BindSpaceTextures::Type::VertexBuffer: {
VKVertexBuffer *vertex_buffer = static_cast<VKVertexBuffer *>(elem.resource);
vertex_buffer->ensure_updated();
vertex_buffer->ensure_buffer_view();
bind_texel_buffer(vertex_buffer->vk_buffer_view_get(), resource_binding.location);
access_info.buffers.append({vertex_buffer->vk_handle(), resource_binding.access_mask});
VKVertexBuffer &vertex_buffer = *static_cast<VKVertexBuffer *>(elem.resource);
vertex_buffer.ensure_updated();
bind_texel_buffer(vertex_buffer, resource_binding.location);
access_info.buffers.append({vertex_buffer.vk_handle(), resource_binding.access_mask});
break;
}
case BindSpaceTextures::Type::Texture: {
@@ -118,11 +105,10 @@ void VKDescriptorSetTracker::bind_texture_resource(const VKDevice &device,
/* Texture buffers are no textures, but wrap around vertex buffers and need to be
* bound as texel buffers. */
/* TODO: Investigate if this can be improved in the API. */
VKVertexBuffer *vertex_buffer = texture->source_buffer_;
vertex_buffer->ensure_updated();
vertex_buffer->ensure_buffer_view();
bind_texel_buffer(vertex_buffer->vk_buffer_view_get(), resource_binding.location);
access_info.buffers.append({vertex_buffer->vk_handle(), resource_binding.access_mask});
VKVertexBuffer &vertex_buffer = *texture->source_buffer_;
vertex_buffer.ensure_updated();
bind_texel_buffer(vertex_buffer, resource_binding.location);
access_info.buffers.append({vertex_buffer.vk_handle(), resource_binding.access_mask});
}
else {
const VKSampler &sampler = device.samplers().get(elem.sampler);
@@ -146,7 +132,7 @@ void VKDescriptorSetTracker::bind_texture_resource(const VKDevice &device,
}
}
void VKDescriptorSetTracker::bind_input_attachment_resource(
void VKDescriptorSetUpdator::bind_input_attachment_resource(
const VKDevice &device,
const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
@@ -215,7 +201,7 @@ void VKDescriptorSetTracker::bind_input_attachment_resource(
}
}
void VKDescriptorSetTracker::bind_storage_buffer_resource(
void VKDescriptorSetUpdator::bind_storage_buffer_resource(
const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info)
@@ -224,12 +210,14 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
resource_binding.binding);
VkBuffer vk_buffer = VK_NULL_HANDLE;
VkDeviceSize vk_device_size = 0;
VkDeviceAddress vk_device_address = 0;
switch (elem.resource_type) {
case BindSpaceStorageBuffers::Type::IndexBuffer: {
VKIndexBuffer *index_buffer = static_cast<VKIndexBuffer *>(elem.resource);
index_buffer->ensure_updated();
vk_buffer = index_buffer->vk_handle();
vk_device_size = index_buffer->size_get();
vk_device_address = index_buffer->device_address_get();
break;
}
case BindSpaceStorageBuffers::Type::VertexBuffer: {
@@ -237,6 +225,7 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
vertex_buffer->ensure_updated();
vk_buffer = vertex_buffer->vk_handle();
vk_device_size = vertex_buffer->size_used_get();
vk_device_address = vertex_buffer->device_address_get();
break;
}
case BindSpaceStorageBuffers::Type::UniformBuffer: {
@@ -244,6 +233,7 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
uniform_buffer->ensure_updated();
vk_buffer = uniform_buffer->vk_handle();
vk_device_size = uniform_buffer->size_in_bytes();
vk_device_address = uniform_buffer->device_address_get();
break;
}
case BindSpaceStorageBuffers::Type::StorageBuffer: {
@@ -251,12 +241,14 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
storage_buffer->ensure_allocated();
vk_buffer = storage_buffer->vk_handle();
vk_device_size = storage_buffer->size_in_bytes();
vk_device_address = storage_buffer->device_address_get();
break;
}
case BindSpaceStorageBuffers::Type::Buffer: {
VKBuffer *buffer = static_cast<VKBuffer *>(elem.resource);
vk_buffer = buffer->vk_handle();
vk_device_size = buffer->size_in_bytes();
vk_device_address = buffer->device_address_get();
break;
}
case BindSpaceStorageBuffers::Type::Unused: {
@@ -266,6 +258,7 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
bind_buffer(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
vk_buffer,
vk_device_address,
elem.offset,
vk_device_size - elem.offset,
resource_binding.location);
@@ -274,7 +267,7 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
}
}
void VKDescriptorSetTracker::bind_uniform_buffer_resource(
void VKDescriptorSetUpdator::bind_uniform_buffer_resource(
const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info)
@@ -283,13 +276,14 @@ void VKDescriptorSetTracker::bind_uniform_buffer_resource(
uniform_buffer.ensure_updated();
bind_buffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
uniform_buffer.vk_handle(),
uniform_buffer.device_address_get(),
0,
uniform_buffer.size_in_bytes(),
resource_binding.location);
access_info.buffers.append({uniform_buffer.vk_handle(), resource_binding.access_mask});
}
void VKDescriptorSetTracker::bind_push_constants(VKPushConstants &push_constants,
void VKDescriptorSetUpdator::bind_push_constants(VKPushConstants &push_constants,
render_graph::VKResourceAccessInfo &access_info)
{
if (push_constants.layout_get().storage_type_get() !=
@@ -301,13 +295,14 @@ void VKDescriptorSetTracker::bind_push_constants(VKPushConstants &push_constants
const VKUniformBuffer &uniform_buffer = *push_constants.uniform_buffer_get().get();
bind_buffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
uniform_buffer.vk_handle(),
uniform_buffer.device_address_get(),
0,
uniform_buffer.size_in_bytes(),
push_constants.layout_get().descriptor_set_location_get());
access_info.buffers.append({uniform_buffer.vk_handle(), VK_ACCESS_UNIFORM_READ_BIT});
}
void VKDescriptorSetTracker::bind_shader_resources(const VKDevice &device,
void VKDescriptorSetUpdator::bind_shader_resources(const VKDevice &device,
const VKStateManager &state_manager,
VKShader &shader,
render_graph::VKResourceAccessInfo &access_info)
@@ -345,32 +340,83 @@ void VKDescriptorSetTracker::bind_shader_resources(const VKDevice &device,
bind_push_constants(shader.push_constants, access_info);
}
void VKDescriptorSetTracker::update_descriptor_set(VKContext &context,
render_graph::VKResourceAccessInfo &access_info)
/** \} */
/* -------------------------------------------------------------------- */
/** \name VKDescriptorSetPoolUpdator
* \{ */
void VKDescriptorSetPoolUpdator::allocate_new_descriptor_set(
VKDevice & /*device*/,
VKContext &context,
VKShader &shader,
VkDescriptorSetLayout vk_descriptor_set_layout,
render_graph::VKPipelineData &r_pipeline_data)
{
VKShader &shader = *unwrap(context.shader);
VKStateManager &state_manager = context.state_manager_get();
/* Can we reuse previous descriptor set. */
if (!state_manager.is_dirty &&
!assign_if_different(vk_descriptor_set_layout_, shader.vk_descriptor_set_layout_get()) &&
shader.push_constants.layout_get().storage_type_get() !=
VKPushConstants::StorageType::UNIFORM_BUFFER)
{
return;
}
state_manager.is_dirty = false;
/* Allocate a new descriptor set. */
VkDescriptorSetLayout vk_descriptor_set_layout = shader.vk_descriptor_set_layout_get();
/* Use descriptor pools/sets. */
vk_descriptor_set = context.descriptor_pools_get().allocate(vk_descriptor_set_layout);
BLI_assert(vk_descriptor_set != VK_NULL_HANDLE);
debug::object_label(vk_descriptor_set, shader.name_get());
const VKDevice &device = VKBackend::get().device;
bind_shader_resources(device, state_manager, shader, access_info);
r_pipeline_data.vk_descriptor_set = vk_descriptor_set;
}
void VKDescriptorSetTracker::upload_descriptor_sets()
void VKDescriptorSetPoolUpdator::bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer vk_buffer,
VkDeviceAddress /*vk_device_address*/,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location)
{
vk_descriptor_buffer_infos_.append({vk_buffer, buffer_offset, size_in_bytes});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
vk_descriptor_type,
nullptr,
nullptr,
nullptr});
}
void VKDescriptorSetPoolUpdator::bind_texel_buffer(VKVertexBuffer &vertex_buffer,
const VKDescriptorSet::Location location)
{
vertex_buffer.ensure_buffer_view();
vk_buffer_views_.append(vertex_buffer.vk_buffer_view_get());
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
nullptr,
nullptr,
nullptr});
}
void VKDescriptorSetPoolUpdator::bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location)
{
vk_descriptor_image_infos_.append({vk_sampler, vk_image_view, vk_image_layout});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
location,
0,
1,
vk_descriptor_type,
nullptr,
nullptr,
nullptr});
}
void VKDescriptorSetPoolUpdator::upload_descriptor_sets()
{
if (vk_write_descriptor_sets_.is_empty()) {
return;
@@ -464,4 +510,164 @@ void VKDescriptorSetTracker::upload_descriptor_sets()
vk_write_descriptor_sets_.clear();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name VKDescriptorBufferUpdator
* \{ */
void VKDescriptorBufferUpdator::allocate_new_descriptor_set(
VKDevice &device,
VKContext & /*context*/,
VKShader & /*shader*/,
VkDescriptorSetLayout vk_descriptor_set_layout,
render_graph::VKPipelineData &r_pipeline_data)
{
/* Use descriptor buffer. */
descriptor_set_head = descriptor_set_tail;
layout = device.descriptor_set_layouts_get().descriptor_buffer_layout_get(
vk_descriptor_set_layout);
/* Ensure if there is still place left in the current buffer. */
if (buffers.is_empty() || layout.size > buffers.last().size_in_bytes() - descriptor_set_head) {
const VkDeviceSize default_buffer_size = 8 * 1024 * 1024;
buffers.append({});
VKBuffer &buffer = buffers.last();
buffer.create(default_buffer_size,
VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT |
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
0,
VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
debug::object_label(buffer.vk_handle(), "DescriptorBuffer");
descriptor_buffer_data = static_cast<uint8_t *>(buffer.mapped_memory_get());
descriptor_buffer_device_address = buffer.device_address_get();
descriptor_buffer_offset = 0;
descriptor_set_head = 0;
descriptor_set_tail = 0;
}
descriptor_set_tail = descriptor_set_head + layout.size;
/* Update the current descriptor buffer and its offset to point to the active descriptor set. */
descriptor_buffer_offset = descriptor_set_head;
r_pipeline_data.descriptor_buffer_device_address = descriptor_buffer_device_address;
r_pipeline_data.descriptor_buffer_offset = descriptor_buffer_offset;
}
void VKDescriptorBufferUpdator::bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer /*vk_buffer*/,
VkDeviceAddress vk_device_address,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location)
{
BLI_assert(vk_device_address != 0);
VKDevice &device = VKBackend::get().device;
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &vk_descriptor_buffer_properties =
device.physical_device_descriptor_buffer_properties_get();
VkDescriptorAddressInfoEXT descriptor_address_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT,
nullptr,
vk_device_address + buffer_offset,
size_in_bytes};
VkDescriptorGetInfoEXT vk_descriptor_get_info{
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, nullptr, vk_descriptor_type};
VkDeviceSize descriptor_size = 0;
switch (vk_descriptor_type) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
vk_descriptor_get_info.data.pUniformBuffer = &descriptor_address_info;
descriptor_size = vk_descriptor_buffer_properties.uniformBufferDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
vk_descriptor_get_info.data.pStorageBuffer = &descriptor_address_info;
descriptor_size = vk_descriptor_buffer_properties.storageBufferDescriptorSize;
break;
default:
BLI_assert_unreachable();
}
uint8_t *descriptor_ptr = get_descriptor_binding_ptr(location);
device.functions.vkGetDescriptor(
device.vk_handle(), &vk_descriptor_get_info, descriptor_size, descriptor_ptr);
}
void VKDescriptorBufferUpdator::bind_texel_buffer(VKVertexBuffer &vertex_buffer,
const VKDescriptorSet::Location location)
{
VkDeviceAddress vk_device_address = vertex_buffer.device_address_get();
BLI_assert(vk_device_address != 0);
VKDevice &device = VKBackend::get().device;
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &vk_descriptor_buffer_properties =
device.physical_device_descriptor_buffer_properties_get();
VkDescriptorAddressInfoEXT descriptor_address_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT,
nullptr,
vk_device_address,
vertex_buffer.size_used_get(),
vertex_buffer.to_vk_format()};
VkDescriptorGetInfoEXT vk_descriptor_get_info{
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, nullptr, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER};
vk_descriptor_get_info.data.pUniformTexelBuffer = &descriptor_address_info;
VkDeviceSize descriptor_size = vk_descriptor_buffer_properties.uniformTexelBufferDescriptorSize;
uint8_t *descriptor_ptr = get_descriptor_binding_ptr(location);
device.functions.vkGetDescriptor(
device.vk_handle(), &vk_descriptor_get_info, descriptor_size, descriptor_ptr);
}
void VKDescriptorBufferUpdator::bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location)
{
VKDevice &device = VKBackend::get().device;
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &vk_descriptor_buffer_properties =
device.physical_device_descriptor_buffer_properties_get();
VkDescriptorImageInfo vk_descriptor_image_info = {vk_sampler, vk_image_view, vk_image_layout};
VkDescriptorGetInfoEXT vk_descriptor_get_info{
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, nullptr, vk_descriptor_type};
VkDeviceSize descriptor_size = 0;
switch (vk_descriptor_type) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
vk_descriptor_get_info.data.pCombinedImageSampler = &vk_descriptor_image_info;
descriptor_size = vk_descriptor_buffer_properties.combinedImageSamplerDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
vk_descriptor_get_info.data.pStorageImage = &vk_descriptor_image_info;
descriptor_size = vk_descriptor_buffer_properties.storageImageDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
vk_descriptor_get_info.data.pInputAttachmentImage = &vk_descriptor_image_info;
descriptor_size = vk_descriptor_buffer_properties.inputAttachmentDescriptorSize;
break;
default:
BLI_assert_unreachable();
}
uint8_t *descriptor_ptr = get_descriptor_binding_ptr(location);
device.functions.vkGetDescriptor(
device.vk_handle(), &vk_descriptor_get_info, descriptor_size, descriptor_ptr);
}
void VKDescriptorBufferUpdator::upload_descriptor_sets()
{
/* Buffers have already been updated. only need to discard the buffers. */
buffers.clear();
descriptor_buffer_data = nullptr;
descriptor_buffer_device_address = 0;
descriptor_buffer_offset = 0;
}
/** \} */
} // namespace blender::gpu

View File

@@ -13,9 +13,11 @@
#include "gpu_shader_private.hh"
#include "render_graph/nodes/vk_pipeline_data.hh"
#include "render_graph/vk_resource_access_info.hh"
#include "vk_buffer.hh"
#include "vk_common.hh"
#include "vk_descriptor_set_layouts.hh"
#include "vk_resource_tracker.hh"
#include "vk_uniform_buffer.hh"
@@ -25,6 +27,8 @@ class VKStateManager;
class VKDevice;
class VKPushConstants;
class VKShader;
class VKDescriptorSetTracker;
class VKVertexBuffer;
/**
* In vulkan shader resources (images and buffers) are grouped in descriptor sets.
@@ -76,42 +80,22 @@ class VKDescriptorSet : NonCopyable {
};
};
class VKDescriptorSetTracker {
friend class VKDescriptorSet;
Vector<VkBufferView> vk_buffer_views_;
Vector<VkDescriptorBufferInfo> vk_descriptor_buffer_infos_;
Vector<VkDescriptorImageInfo> vk_descriptor_image_infos_;
Vector<VkWriteDescriptorSet> vk_write_descriptor_sets_;
/* Last used layout to identify changes. */
VkDescriptorSetLayout vk_descriptor_set_layout_ = VK_NULL_HANDLE;
class VKDescriptorSetUpdator {
public:
VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE;
virtual ~VKDescriptorSetUpdator(){};
VKDescriptorSetTracker() {}
/**
* Update the descriptor set. Reuses previous descriptor set when no changes are detected. This
* improves performance when working with large grease pencil scenes.
*/
void update_descriptor_set(VKContext &context,
render_graph::VKResourceAccessInfo &resource_access_info);
/**
* Upload all descriptor sets to the device.
*
* NOTE: Caller should discard the associated descriptor pools. (VKDescriptorPools::discard)
*/
void upload_descriptor_sets();
private:
virtual void allocate_new_descriptor_set(VKDevice &device,
VKContext &context,
VKShader &shader,
VkDescriptorSetLayout vk_descriptor_set_layout,
render_graph::VKPipelineData &r_pipeline_data) = 0;
void bind_shader_resources(const VKDevice &device,
const VKStateManager &state_manager,
VKShader &shader,
render_graph::VKResourceAccessInfo &access_info);
virtual void upload_descriptor_sets() = 0;
private:
void bind_image_resource(const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info);
@@ -129,21 +113,134 @@ class VKDescriptorSetTracker {
const VKStateManager &state_manager,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info);
void bind_push_constants(VKPushConstants &push_constants,
void bind_push_constants(VKPushConstants &push_constants,
render_graph::VKResourceAccessInfo &access_info);
void bind_texel_buffer(VkBufferView vk_buffer_view, VKDescriptorSet::Location location);
protected:
virtual void bind_texel_buffer(VKVertexBuffer &vertex_buffer,
VKDescriptorSet::Location location) = 0;
virtual void bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer vk_buffer,
VkDeviceAddress vk_device_address,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location) = 0;
virtual void bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location) = 0;
};
class VKDescriptorSetPoolUpdator : public VKDescriptorSetUpdator {
public:
VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE;
void allocate_new_descriptor_set(VKDevice &device,
VKContext &context,
VKShader &shader,
VkDescriptorSetLayout vk_descriptor_set_layout,
render_graph::VKPipelineData &r_pipeline_data) override;
void upload_descriptor_sets() override;
protected:
void bind_texel_buffer(VKVertexBuffer &vertex_buffer,
VKDescriptorSet::Location location) override;
void bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer vk_buffer,
VkDeviceAddress vk_device_address,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location);
VKDescriptorSet::Location location) override;
void bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location);
VKDescriptorSet::Location location) override;
private:
Vector<VkBufferView> vk_buffer_views_;
Vector<VkDescriptorBufferInfo> vk_descriptor_buffer_infos_;
Vector<VkDescriptorImageInfo> vk_descriptor_image_infos_;
Vector<VkWriteDescriptorSet> vk_write_descriptor_sets_;
};
class VKDescriptorBufferUpdator : public VKDescriptorSetUpdator {
public:
/* Offset to the beginning of the current descriptor set. */
VkDeviceSize descriptor_set_head = 0;
/* Offset to the end (+1) of the current descriptor set. */
VkDeviceSize descriptor_set_tail = 0;
/* Current layout of the descriptor set being filled. */
VKDescriptorBufferLayout layout;
/* Descriptor buffers */
Vector<VKBuffer> buffers;
/* Current descriptor buffer handle and offset. */
VkDeviceAddress descriptor_buffer_device_address = 0;
uint8_t *descriptor_buffer_data = nullptr;
VkDeviceSize descriptor_buffer_offset = 0;
void allocate_new_descriptor_set(VKDevice &device,
VKContext &context,
VKShader &shader,
VkDescriptorSetLayout vk_descriptor_set_layout,
render_graph::VKPipelineData &r_pipeline_data) override;
void upload_descriptor_sets() override;
protected:
void bind_texel_buffer(VKVertexBuffer &vertex_buffer,
VKDescriptorSet::Location location) override;
void bind_buffer(VkDescriptorType vk_descriptor_type,
VkBuffer vk_buffer,
VkDeviceAddress vk_device_address,
VkDeviceSize buffer_offset,
VkDeviceSize size_in_bytes,
VKDescriptorSet::Location location) override;
void bind_image(VkDescriptorType vk_descriptor_type,
VkSampler vk_sampler,
VkImageView vk_image_view,
VkImageLayout vk_image_layout,
VKDescriptorSet::Location location) override;
private:
inline uint8_t *get_descriptor_binding_ptr(uint32_t binding) const
{
return descriptor_buffer_data + descriptor_buffer_offset + layout.binding_offsets[binding];
}
};
class VKDescriptorSetTracker {
friend class VKDescriptorSet;
/* Last used layout to identify changes. */
VkDescriptorSetLayout vk_descriptor_set_layout_ = VK_NULL_HANDLE;
public:
class VKDescriptorBufferUpdator descriptor_buffers;
class VKDescriptorSetPoolUpdator descriptor_sets;
VKDescriptorSetTracker() {}
/**
* Update the descriptor set. Reuses previous descriptor set when no changes are detected. This
* improves performance when working with large grease pencil scenes.
*/
void update_descriptor_set(VKContext &context,
render_graph::VKResourceAccessInfo &resource_access_info,
render_graph::VKPipelineData &r_pipeline_data);
/**
* Upload all descriptor sets to the device.
*
* NOTE: Caller should discard the associated descriptor pools. (VKDescriptorPools::discard)
*/
void upload_descriptor_sets();
private:
};
} // namespace blender::gpu

View File

@@ -40,11 +40,16 @@ VkDescriptorSetLayout VKDescriptorSetLayouts::get_or_create(const VKDescriptorSe
}
update_layout_bindings(info);
const VKDevice &device = VKBackend::get().device;
const bool use_descriptor_buffer = device.extensions_get().descriptor_buffer;
vk_descriptor_set_layout_create_info_.bindingCount = vk_descriptor_set_layout_bindings_.size();
vk_descriptor_set_layout_create_info_.pBindings = vk_descriptor_set_layout_bindings_.data();
if (use_descriptor_buffer) {
vk_descriptor_set_layout_create_info_.flags =
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
}
const VKDevice &device = VKBackend::get().device;
VkDescriptorSetLayout vk_descriptor_set_layout = VK_NULL_HANDLE;
vkCreateDescriptorSetLayout(device.vk_handle(),
&vk_descriptor_set_layout_create_info_,
@@ -58,6 +63,12 @@ VkDescriptorSetLayout VKDescriptorSetLayouts::get_or_create(const VKDescriptorSe
vk_descriptor_set_layouts_.add(info, vk_descriptor_set_layout);
r_created = true;
if (use_descriptor_buffer) {
descriptor_buffer_layouts_.add(
vk_descriptor_set_layout,
create_descriptor_buffer_layout(device, info, vk_descriptor_set_layout));
}
return vk_descriptor_set_layout;
}
@@ -90,4 +101,32 @@ void VKDescriptorSetLayouts::deinit()
vk_descriptor_set_layouts_.clear();
}
static void align_size(VkDeviceSize &r_size, VkDeviceSize alignment)
{
if (alignment > 1) {
r_size = (r_size + alignment - 1) & ~(alignment - 1);
}
}
VKDescriptorBufferLayout VKDescriptorSetLayouts::create_descriptor_buffer_layout(
const VKDevice &device,
const VKDescriptorSetLayoutInfo &info,
VkDescriptorSetLayout vk_descriptor_set_layout) const
{
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &properties =
device.physical_device_descriptor_buffer_properties_get();
VKDescriptorBufferLayout result = {};
device.functions.vkGetDescriptorSetLayoutSize(
device.vk_handle(), vk_descriptor_set_layout, &result.size);
align_size(result.size, properties.descriptorBufferOffsetAlignment);
result.binding_offsets.resize(info.bindings.size());
for (uint32_t binding : IndexRange(info.bindings.size())) {
device.functions.vkGetDescriptorSetLayoutBindingOffset(
device.vk_handle(), vk_descriptor_set_layout, binding, &result.binding_offsets[binding]);
}
return result;
}
} // namespace blender::gpu

View File

@@ -25,6 +25,9 @@
#include "vk_common.hh"
namespace blender::gpu {
class VKDevice;
/**
* Key of descriptor set layout
*
@@ -63,6 +66,25 @@ template<> struct DefaultHash<gpu::VKDescriptorSetLayoutInfo> {
} // namespace blender
namespace blender::gpu {
struct VKDescriptorBufferLayout {
/**
* Total size of the descriptor buffer.
*
* Size is aligned to
* VkPhysicalDeviceDescriptorBufferProperties.descriptorBufferOffsetAlignment.
*/
VkDeviceSize size;
/**
* Offsets of each binding inside the buffer.
*
* Offsets are aligned to
* VkPhysicalDeviceDescriptorBufferProperties.descriptorBufferOffsetAlignment.
*/
Vector<VkDeviceSize> binding_offsets;
};
/**
* Registries of descriptor set layouts.
*/
@@ -74,6 +96,7 @@ class VKDescriptorSetLayouts : NonCopyable {
* Map containing all created descriptor set layouts.
*/
Map<VKDescriptorSetLayoutInfo, VkDescriptorSetLayout> vk_descriptor_set_layouts_;
Map<VkDescriptorSetLayout, VKDescriptorBufferLayout> descriptor_buffer_layouts_;
/**
* Reusable descriptor set layout create info.
@@ -96,6 +119,23 @@ class VKDescriptorSetLayouts : NonCopyable {
bool &r_created,
bool &r_needed);
/**
* Return the descriptor buffer layout offsets and alignment for the given
* vk_descriptor_set_layout handle.
*
* A copy of the buffer layout is returned due to other threads can alter the location of the
* items.
*
* This function has undefined behavior when descriptor buffers extension isn't enabled on the
* VKDevice.
*/
VKDescriptorBufferLayout descriptor_buffer_layout_get(
VkDescriptorSetLayout vk_descriptor_set_layout)
{
std::scoped_lock lock(mutex_);
return descriptor_buffer_layouts_.lookup(vk_descriptor_set_layout);
}
/**
* Free all descriptor set layouts.
*
@@ -113,6 +153,10 @@ class VKDescriptorSetLayouts : NonCopyable {
private:
void update_layout_bindings(const VKDescriptorSetLayoutInfo &info);
VKDescriptorBufferLayout create_descriptor_buffer_layout(
const VKDevice &device,
const VKDescriptorSetLayoutInfo &info,
VkDescriptorSetLayout vk_descriptor_set_layout) const;
};
} // namespace blender::gpu

View File

@@ -39,6 +39,7 @@ void VKExtensions::log() const
" - [%c] shader output layer\n"
" - [%c] fragment shader barycentric\n"
"Device extensions\n"
" - [%c] descriptor buffer\n"
" - [%c] dynamic rendering\n"
" - [%c] dynamic rendering local read\n"
" - [%c] dynamic rendering unused attachments\n"
@@ -47,6 +48,7 @@ void VKExtensions::log() const
shader_output_viewport_index ? 'X' : ' ',
shader_output_layer ? 'X' : ' ',
fragment_shader_barycentric ? 'X' : ' ',
descriptor_buffer ? 'X' : ' ',
dynamic_rendering ? 'X' : ' ',
dynamic_rendering_local_read ? 'X' : ' ',
dynamic_rendering_unused_attachments ? 'X' : ' ',
@@ -126,10 +128,10 @@ void VKDevice::init(void *ghost_context)
vk_queue_ = handles.queue;
queue_mutex_ = static_cast<std::mutex *>(handles.queue_mutex);
init_physical_device_extensions();
init_physical_device_properties();
init_physical_device_memory_properties();
init_physical_device_features();
init_physical_device_extensions();
VKBackend::platform_init(*this);
VKBackend::capabilities_init(*this);
init_functions();
@@ -177,6 +179,14 @@ void VKDevice::init_functions()
#endif
}
/* VK_EXT_descriptor_buffer */
functions.vkGetDescriptorSetLayoutSize = LOAD_FUNCTION(vkGetDescriptorSetLayoutSizeEXT);
functions.vkGetDescriptorSetLayoutBindingOffset = LOAD_FUNCTION(
vkGetDescriptorSetLayoutBindingOffsetEXT);
functions.vkGetDescriptor = LOAD_FUNCTION(vkGetDescriptorEXT);
functions.vkCmdBindDescriptorBuffers = LOAD_FUNCTION(vkCmdBindDescriptorBuffersEXT);
functions.vkCmdSetDescriptorBufferOffsets = LOAD_FUNCTION(vkCmdSetDescriptorBufferOffsetsEXT);
#undef LOAD_FUNCTION
}
@@ -197,6 +207,15 @@ void VKDevice::init_physical_device_properties()
vk_physical_device_properties.pNext = &vk_physical_device_driver_properties_;
vk_physical_device_driver_properties_.pNext = &vk_physical_device_id_properties_;
if (supports_extension(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) {
vk_physical_device_descriptor_buffer_properties_ = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT};
vk_physical_device_descriptor_buffer_properties_.pNext =
vk_physical_device_driver_properties_.pNext;
vk_physical_device_driver_properties_.pNext =
&vk_physical_device_descriptor_buffer_properties_;
}
vkGetPhysicalDeviceProperties2(vk_physical_device_, &vk_physical_device_properties);
vk_physical_device_properties_ = vk_physical_device_properties.properties;
}
@@ -251,6 +270,9 @@ void VKDevice::init_memory_allocator()
info.physicalDevice = vk_physical_device_;
info.device = vk_device_;
info.instance = vk_instance_;
if (extensions_.descriptor_buffer) {
info.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
}
vmaCreateAllocator(&info, &mem_allocator_);
if (!extensions_.external_memory) {

View File

@@ -59,6 +59,11 @@ struct VKExtensions {
*/
bool external_memory = false;
/**
* Does the device support VK_EXT_descriptor_buffer.
*/
bool descriptor_buffer = false;
/**
* Does the device support logic ops.
*/
@@ -208,6 +213,8 @@ class VKDevice : public NonCopyable {
VkPhysicalDeviceDriverProperties vk_physical_device_driver_properties_ = {};
VkPhysicalDeviceIDProperties vk_physical_device_id_properties_ = {};
VkPhysicalDeviceMemoryProperties vk_physical_device_memory_properties_ = {};
VkPhysicalDeviceDescriptorBufferPropertiesEXT vk_physical_device_descriptor_buffer_properties_ =
{};
/** Features support. */
VkPhysicalDeviceFeatures vk_physical_device_features_ = {};
VkPhysicalDeviceVulkan11Features vk_physical_device_vulkan_11_features_ = {};
@@ -258,6 +265,14 @@ class VKDevice : public NonCopyable {
/* Extension: VK_KHR_external_memory_win32 */
PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32Handle = nullptr;
#endif
/* Extension: VK_EXT_descriptor_buffer */
PFN_vkGetDescriptorSetLayoutSizeEXT vkGetDescriptorSetLayoutSize = nullptr;
PFN_vkGetDescriptorSetLayoutBindingOffsetEXT vkGetDescriptorSetLayoutBindingOffset = nullptr;
PFN_vkGetDescriptorEXT vkGetDescriptor = nullptr;
PFN_vkCmdBindDescriptorBuffersEXT vkCmdBindDescriptorBuffers = nullptr;
PFN_vkCmdSetDescriptorBufferOffsetsEXT vkCmdSetDescriptorBufferOffsets = nullptr;
} functions;
struct {
@@ -288,6 +303,12 @@ class VKDevice : public NonCopyable {
return vk_physical_device_id_properties_;
}
inline const VkPhysicalDeviceDescriptorBufferPropertiesEXT &
physical_device_descriptor_buffer_properties_get() const
{
return vk_physical_device_descriptor_buffer_properties_;
}
const VkPhysicalDeviceFeatures &physical_device_features_get() const
{
return vk_physical_device_features_;
@@ -365,7 +386,7 @@ class VKDevice : public NonCopyable {
{
return workarounds_;
}
const VKExtensions &extensions_get() const
inline const VKExtensions &extensions_get() const
{
return extensions_;
}

View File

@@ -31,6 +31,10 @@ class VKIndexBuffer : public IndexBuf {
{
return buffer_get().vk_handle();
}
inline VkDeviceAddress device_address_get() const
{
return buffer_get().device_address_get();
}
VkIndexType vk_index_type() const
{
return to_vk_index_type(index_type_);

View File

@@ -202,6 +202,9 @@ VkPipeline VKPipelinePool::get_or_create_compute_pipeline(VKComputeInfo &compute
/* Build pipeline. */
VKBackend &backend = VKBackend::get();
VKDevice &device = backend.device;
if (device.extensions_get().descriptor_buffer) {
vk_compute_pipeline_create_info_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
}
VkPipeline pipeline = VK_NULL_HANDLE;
vkCreateComputePipelines(device.vk_handle(),
@@ -214,6 +217,7 @@ VkPipeline VKPipelinePool::get_or_create_compute_pipeline(VKComputeInfo &compute
compute_pipelines_.add(compute_info, pipeline);
/* Reset values to initial value. */
vk_compute_pipeline_create_info_.flags = 0;
vk_compute_pipeline_create_info_.layout = VK_NULL_HANDLE;
vk_compute_pipeline_create_info_.stage.module = VK_NULL_HANDLE;
vk_compute_pipeline_create_info_.stage.pSpecializationInfo = nullptr;
@@ -586,6 +590,9 @@ VkPipeline VKPipelinePool::get_or_create_graphics_pipeline(VKGraphicsInfo &graph
/* Build pipeline. */
VKBackend &backend = VKBackend::get();
VKDevice &device = backend.device;
if (device.extensions_get().descriptor_buffer) {
vk_graphics_pipeline_create_info_.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
}
VkPipeline pipeline = VK_NULL_HANDLE;
vkCreateGraphicsPipelines(device.vk_handle(),
@@ -599,6 +606,7 @@ VkPipeline VKPipelinePool::get_or_create_graphics_pipeline(VKGraphicsInfo &graph
/* Reset values to initial value. */
specialization_info_reset();
vk_graphics_pipeline_create_info_.flags = 0;
vk_graphics_pipeline_create_info_.stageCount = 0;
vk_graphics_pipeline_create_info_.layout = VK_NULL_HANDLE;
vk_graphics_pipeline_create_info_.basePipelineHandle = VK_NULL_HANDLE;

View File

@@ -204,7 +204,7 @@ class BindSpaceTextures {
};
class VKStateManager : public StateManager {
friend class VKDescriptorSetTracker;
friend class VKDescriptorSetUpdator;
uint texture_unpack_row_length_ = 0;

View File

@@ -43,6 +43,10 @@ class VKStorageBuffer : public StorageBuf {
{
return buffer_.vk_handle();
}
inline VkDeviceAddress device_address_get() const
{
return buffer_.device_address_get();
}
int64_t size_in_bytes() const
{

View File

@@ -29,7 +29,7 @@ enum class VKImageViewFlags {
ENUM_OPERATORS(VKImageViewFlags, VKImageViewFlags::NO_SWIZZLING)
class VKTexture : public Texture {
friend class VKDescriptorSetTracker;
friend class VKDescriptorSetUpdator;
/**
* Texture format how the texture is stored on the device.

View File

@@ -42,6 +42,10 @@ class VKUniformBuffer : public UniformBuf, NonCopyable {
{
return buffer_.vk_handle();
}
inline VkDeviceAddress device_address_get() const
{
return buffer_.device_address_get();
}
size_t size_in_bytes() const
{

View File

@@ -48,11 +48,9 @@ void VKVertexBuffer::ensure_buffer_view()
}
VkBufferViewCreateInfo buffer_view_info = {};
eGPUTextureFormat texture_format = to_texture_format(&format);
buffer_view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
buffer_view_info.buffer = buffer_.vk_handle();
buffer_view_info.format = to_vk_format(texture_format);
buffer_view_info.format = to_vk_format();
buffer_view_info.range = buffer_.size_in_bytes();
const VKDevice &device = VKBackend::get().device;

View File

@@ -11,6 +11,7 @@
#include "GPU_vertex_buffer.hh"
#include "vk_buffer.hh"
#include "vk_common.hh"
#include "vk_data_conversion.hh"
namespace blender::gpu {
@@ -38,6 +39,11 @@ class VKVertexBuffer : public VertBuf {
return buffer_.vk_handle();
}
inline VkDeviceAddress device_address_get() const
{
return buffer_.device_address_get();
}
VkBufferView vk_buffer_view_get() const
{
BLI_assert(vk_buffer_view_ != VK_NULL_HANDLE);
@@ -47,6 +53,11 @@ class VKVertexBuffer : public VertBuf {
void ensure_updated();
void ensure_buffer_view();
inline VkFormat to_vk_format()
{
return blender::gpu::to_vk_format(to_texture_format(&format));
}
protected:
void acquire_data() override;
void resize_data() override;