WIP: Vulkan: Clearing Storage Buffers #105299
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
|
@ -75,6 +76,7 @@ bool VKBuffer::create(VKContext &context,
|
|||
|
||||
bool VKBuffer::update(VKContext &context, const void *data)
|
||||
{
|
||||
/* TODO: When size <64Kb we should use vkCmdUpdateBuffer. */
|
||||
void *mapped_memory;
|
||||
bool result = map(context, &mapped_memory);
|
||||
if (result) {
|
||||
|
@ -84,6 +86,47 @@ bool VKBuffer::update(VKContext &context, const void *data)
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool is_uniform(Span<uint32_t> data)
|
||||
{
|
||||
BLI_assert(!data.is_empty());
|
||||
uint32_t expected_value = data[0];
|
||||
for (uint32_t value : data) {
|
||||
if (value != expected_value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool can_use_fill_command(eGPUTextureFormat internal_format,
|
||||
eGPUDataFormat data_format,
|
||||
void *data)
|
||||
{
|
||||
/* TODO: See `validate_data_format` what we should support. */
|
||||
BLI_assert(ELEM(data_format, GPU_DATA_INT, GPU_DATA_UINT, GPU_DATA_FLOAT));
|
||||
UNUSED_VARS_NDEBUG(data_format);
|
||||
const uint32_t element_size = to_bytesize(internal_format);
|
||||
const uint32_t num_components = element_size / sizeof(uint32_t);
|
||||
return is_uniform(Span<uint32_t>(static_cast<uint32_t *>(data), num_components));
|
||||
}
|
||||
|
||||
void VKBuffer::clear(VKContext &context,
|
||||
eGPUTextureFormat internal_format,
|
||||
eGPUDataFormat data_format,
|
||||
void *data)
|
||||
{
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
if (can_use_fill_command(internal_format, data_format, data)) {
|
||||
command_buffer.fill(*this, *static_cast<uint32_t *>(data));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Use a compute shader to clear the buffer. This is performance wise not recommended, and
|
||||
* should be avoided. There are some cases where we don't have a choice. Especially when using
|
||||
* compute shaders.*/
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
bool VKBuffer::map(VKContext &context, void **r_mapped_memory) const
|
||||
{
|
||||
VmaAllocator allocator = context.mem_allocator_get();
|
||||
|
|
|
@ -34,6 +34,10 @@ class VKBuffer {
|
|||
GPUUsageType usage,
|
||||
VkBufferUsageFlagBits buffer_usage);
|
||||
bool update(VKContext &context, const void *data);
|
||||
void clear(VKContext &context,
|
||||
eGPUTextureFormat internal_format,
|
||||
eGPUDataFormat data_format,
|
||||
void *data);
|
||||
bool free(VKContext &context);
|
||||
bool map(VKContext &context, void **r_mapped_memory) const;
|
||||
void unmap(VKContext &context) const;
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
#include "vk_storage_buffer.hh"
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
void VKStorageBuffer::update(const void *data)
|
||||
|
@ -49,30 +47,6 @@ void VKStorageBuffer::unbind()
|
|||
{
|
||||
}
|
||||
|
||||
static bool is_uniform(Span<uint32_t> data)
|
||||
{
|
||||
BLI_assert(!data.is_empty());
|
||||
uint32_t expected_value = data[0];
|
||||
for (uint32_t value : data) {
|
||||
if (value != expected_value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool can_use_fill_command(eGPUTextureFormat internal_format,
|
||||
eGPUDataFormat /*data_format*/,
|
||||
void *data)
|
||||
{
|
||||
int element_size = to_bytesize(internal_format);
|
||||
int num_components = element_size / 4;
|
||||
if (is_uniform(Span<uint32_t>(static_cast<uint32_t *>(data), num_components))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VKStorageBuffer::clear(eGPUTextureFormat internal_format,
|
||||
eGPUDataFormat data_format,
|
||||
void *data)
|
||||
|
@ -81,17 +55,7 @@ void VKStorageBuffer::clear(eGPUTextureFormat internal_format,
|
|||
if (!buffer_.is_allocated()) {
|
||||
allocate(context);
|
||||
}
|
||||
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
if (can_use_fill_command(internal_format, data_format, data)) {
|
||||
/* When the data format is 4 bytes we can use vkCmdFillBuffer.
|
||||
* Common case when using GPU_storagebuf_clear_to_zero. */
|
||||
command_buffer.fill(buffer_, *static_cast<uint32_t *>(data));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Use a compute shader to clear the buffer. */
|
||||
BLI_assert_unreachable();
|
||||
buffer_.clear(context, internal_format, data_format, data);
|
||||
}
|
||||
|
||||
void VKStorageBuffer::copy_sub(VertBuf * /*src*/,
|
||||
|
|
Loading…
Reference in New Issue