Vulkan: Clearing Storage Buffers #105487
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vk_buffer.hh"
|
#include "vk_buffer.hh"
|
||||||
|
#include "BLI_span.hh"
|
||||||
Jeroen-Bakker marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
namespace blender::gpu {
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ bool VKBuffer::create(VKContext &context,
|
||||||
|
|
||||||
bool VKBuffer::update(VKContext &context, const void *data)
|
bool VKBuffer::update(VKContext &context, const void *data)
|
||||||
{
|
{
|
||||||
|
/* TODO: When size <64Kb we should use vkCmdUpdateBuffer. */
|
||||||
void *mapped_memory;
|
void *mapped_memory;
|
||||||
bool result = map(context, &mapped_memory);
|
bool result = map(context, &mapped_memory);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -84,6 +86,47 @@ bool VKBuffer::update(VKContext &context, const void *data)
|
||||||
return result;
|
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
|
bool VKBuffer::map(VKContext &context, void **r_mapped_memory) const
|
||||||
{
|
{
|
||||||
VmaAllocator allocator = context.mem_allocator_get();
|
VmaAllocator allocator = context.mem_allocator_get();
|
||||||
|
|
|
@ -34,6 +34,10 @@ class VKBuffer {
|
||||||
GPUUsageType usage,
|
GPUUsageType usage,
|
||||||
VkBufferUsageFlagBits buffer_usage);
|
VkBufferUsageFlagBits buffer_usage);
|
||||||
bool update(VKContext &context, const void *data);
|
bool update(VKContext &context, const void *data);
|
||||||
|
void clear(VKContext &context,
|
||||||
|
eGPUTextureFormat internal_format,
|
||||||
|
eGPUDataFormat data_format,
|
||||||
|
void *data);
|
||||||
bool free(VKContext &context);
|
bool free(VKContext &context);
|
||||||
bool map(VKContext &context, void **r_mapped_memory) const;
|
bool map(VKContext &context, void **r_mapped_memory) const;
|
||||||
void unmap(VKContext &context) const;
|
void unmap(VKContext &context) const;
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
#include "vk_storage_buffer.hh"
|
#include "vk_storage_buffer.hh"
|
||||||
|
|
||||||
#include "BLI_span.hh"
|
|
||||||
|
|
||||||
namespace blender::gpu {
|
namespace blender::gpu {
|
||||||
|
|
||||||
void VKStorageBuffer::update(const void *data)
|
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,
|
void VKStorageBuffer::clear(eGPUTextureFormat internal_format,
|
||||||
eGPUDataFormat data_format,
|
eGPUDataFormat data_format,
|
||||||
void *data)
|
void *data)
|
||||||
|
@ -81,17 +55,7 @@ void VKStorageBuffer::clear(eGPUTextureFormat internal_format,
|
||||||
if (!buffer_.is_allocated()) {
|
if (!buffer_.is_allocated()) {
|
||||||
allocate(context);
|
allocate(context);
|
||||||
}
|
}
|
||||||
|
buffer_.clear(context, internal_format, data_format, data);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKStorageBuffer::copy_sub(VertBuf * /*src*/,
|
void VKStorageBuffer::copy_sub(VertBuf * /*src*/,
|
||||||
|
|
Loading…
Reference in New Issue
This include isn't needed