Fix: Vulkan: Validation error on Qualcomm

!146956 introduced buffer streaming and is used to improve the
performance of text rendering. However the solution didn't check the
minimum allowed offset for storage buffers.

This PR will use the correct offset. This was only visible on Qualcomm
devices as other systems don't limit this offset.

Detected when looking into: #147023

Pull Request: https://projects.blender.org/blender/blender/pulls/147192
This commit is contained in:
Jeroen Bakker
2025-10-02 12:47:24 +02:00
parent 0547d2970f
commit b2eaf812b1
5 changed files with 22 additions and 9 deletions

View File

@@ -470,7 +470,8 @@ void VKContext::specialization_constants_set(
shader::SpecializationConstants{};
}
std::unique_ptr<VKStreamingBuffer> &VKContext::get_or_create_streaming_buffer(VKBuffer &buffer)
std::unique_ptr<VKStreamingBuffer> &VKContext::get_or_create_streaming_buffer(
VKBuffer &buffer, VkDeviceSize min_offset_alignment)
{
for (std::unique_ptr<VKStreamingBuffer> &streaming_buffer : streaming_buffers_) {
if (streaming_buffer->vk_buffer_dst() == buffer.vk_handle()) {
@@ -478,7 +479,7 @@ std::unique_ptr<VKStreamingBuffer> &VKContext::get_or_create_streaming_buffer(VK
}
}
streaming_buffers_.append(std::make_unique<VKStreamingBuffer>(buffer));
streaming_buffers_.append(std::make_unique<VKStreamingBuffer>(buffer, min_offset_alignment));
return streaming_buffers_.last();
}

View File

@@ -158,7 +158,8 @@ class VKContext : public Context, NonCopyable {
void specialization_constants_set(const shader::SpecializationConstants *constants_state);
std::unique_ptr<VKStreamingBuffer> &get_or_create_streaming_buffer(VKBuffer &buffer);
std::unique_ptr<VKStreamingBuffer> &get_or_create_streaming_buffer(
VKBuffer &buffer, VkDeviceSize min_offset_alignment);
private:
void swap_buffer_draw_handler(const GHOST_VulkanSwapChainData &data);

View File

@@ -38,8 +38,9 @@ void VKStorageBuffer::update(const void *data)
ensure_allocated();
if (usage_ == GPU_USAGE_STREAM) {
VKContext &context = *VKContext::get();
VKStreamingBuffer &streaming_buffer = *context.get_or_create_streaming_buffer(buffer_);
const VKDevice &device = VKBackend::get().device;
VKStreamingBuffer &streaming_buffer = *context.get_or_create_streaming_buffer(
buffer_, device.physical_device_properties_get().limits.minStorageBufferOffsetAlignment);
offset_ = streaming_buffer.update(context, data, usage_size_in_bytes_);
return;
}

View File

@@ -11,9 +11,10 @@
#include "vk_context.hh"
namespace blender::gpu {
VKStreamingBuffer::VKStreamingBuffer(VKBuffer &buffer)
: vk_buffer_dst_(buffer.vk_handle()), vk_buffer_size_(buffer.size_in_bytes())
VKStreamingBuffer::VKStreamingBuffer(VKBuffer &buffer, VkDeviceSize min_offset_alignment)
: min_offset_alignment_(min_offset_alignment),
vk_buffer_dst_(buffer.vk_handle()),
vk_buffer_size_(buffer.size_in_bytes())
{
}
@@ -47,7 +48,13 @@ VkDeviceSize VKStreamingBuffer::update(VKContext &context, const void *data, siz
VKBuffer &host_buffer = *host_buffer_.value().get();
VkDeviceSize start_offset = offset_;
/* Advance the offset to the next possible offset considering the minimum allowed offset
* alignment. */
offset_ += data_size;
if (min_offset_alignment_ > 1) {
offset_ = ceil_to_multiple_ul(offset_, min_offset_alignment_);
}
memcpy(
static_cast<void *>(static_cast<uint8_t *>(host_buffer.mapped_memory_get()) + start_offset),
data,

View File

@@ -26,6 +26,9 @@ class VKContext;
class VKStreamingBuffer {
/** Current host buffer storing the data to be uploaded. */
std::optional<std::unique_ptr<VKBuffer>> host_buffer_;
/** Minimum alignment for streaming. Needs to be set to
* `VkPhysicalDeviceLimits.min*OffsetAlignment` */
VkDeviceSize min_offset_alignment_;
/** Device buffer that is being updated. */
VkBuffer vk_buffer_dst_;
/** Size of 'vk_buffer_dst_' */
@@ -39,7 +42,7 @@ class VKStreamingBuffer {
render_graph::NodeHandle copy_buffer_handle_ = 0;
public:
VKStreamingBuffer(VKBuffer &buffer);
VKStreamingBuffer(VKBuffer &buffer, VkDeviceSize min_offset_alligment);
~VKStreamingBuffer();
/**