rendering_device: new generic method for buffer CRUD

This commit is contained in:
ChristopheClaustre 2021-10-16 20:33:04 +02:00
parent 5f7848e5f9
commit 6bdb28ff36
5 changed files with 180 additions and 18 deletions

View file

@ -27,6 +27,18 @@
<return type="PackedByteArray" />
<argument index="0" name="buffer" type="RID" />
<description>
Fetch the data from the buffer as a [PackedByteArray].
The size of the new array will be of buffer's size.
</description>
</method>
<method name="buffer_get_data_generic">
<return type="Variant" />
<argument index="0" name="buffer" type="RID" />
<argument index="1" name="type" type="int" enum="Variant.Type" />
<description>
Fetch the data from the buffer as an array of type [code]type[/code].
The size of the new array will be of buffer's size (divided by the size of each element).
Valid [code]type[/code] are [PackedByteArray],[PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], [PackedFloat64Array], [PackedVector2Array] and [PackedColorArray].
</description>
</method>
<method name="buffer_update">
@ -37,6 +49,21 @@
<argument index="3" name="data" type="PackedByteArray" />
<argument index="4" name="post_barrier" type="int" default="7" />
<description>
Update the data in the buffer from position [code]offset[/code] to position [code]offset + size_bytes[/code] (excluded).
[code]data.size()[/code] must be &gt;= to [code]size_bytes[/code].
</description>
</method>
<method name="buffer_update_generic">
<return type="int" enum="Error" />
<argument index="0" name="buffer" type="RID" />
<argument index="1" name="index" type="int" />
<argument index="2" name="size" type="int" />
<argument index="3" name="data" type="Variant" />
<argument index="4" name="post_barrier" type="int" default="7" />
<description>
Update the data in the buffer from position [code]index[/code] to position [code]index + size[/code] (excluded).
[code]data.size()[/code] must be &gt;= to [code]size[/code].
Valid [code]data[/code] are of type [PackedByteArray],[PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], [PackedFloat64Array], [PackedVector2Array] and [PackedColorArray].
</description>
</method>
<method name="capture_timestamp">
@ -492,6 +519,17 @@
<argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
<argument index="2" name="usage" type="int" default="0" />
<description>
Create a storage buffer of size [code]size_bytes[/code].
If [code]data[/code] is not empty it must be of size [code]size_bytes[/code].
</description>
</method>
<method name="storage_buffer_create_generic">
<return type="RID" />
<argument index="0" name="data" type="Variant" />
<argument index="1" name="usage" type="int" default="0" />
<description>
Create a storage buffer initialized with values in [code]data[/code].
Valid [code]data[/code] are of type [PackedByteArray],[PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], [PackedFloat64Array], [PackedVector2Array] and [PackedColorArray].
</description>
</method>
<method name="submit">
@ -612,6 +650,16 @@
<argument index="0" name="size_bytes" type="int" />
<argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
<description>
Create a uniform buffer of size [code]size_bytes[/code].
If [code]data[/code] is not empty it must be of size [code]size_bytes[/code].
</description>
</method>
<method name="uniform_buffer_create_generic">
<return type="RID" />
<argument index="0" name="data" type="Variant" />
<description>
Create a uniform buffer initialized with values in [code]data[/code].
Valid [code]data[/code] are of type [PackedByteArray],[PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], [PackedFloat64Array], [PackedVector2Array] and [PackedColorArray].
</description>
</method>
<method name="uniform_set_create">

View file

@ -5983,7 +5983,7 @@ void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_
us->invalidated_callback_userdata = p_userdata;
}
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) {
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, const void *p_data, uint32_t p_post_barrier) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
@ -6003,13 +6003,13 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
}
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
ERR_FAIL_COND_V_MSG(p_offset + p_size_bytes > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size_bytes) - buffer->size) + " bytes) past the end.");
// no barrier should be needed here
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true);
Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier);
Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size_bytes, p_post_barrier);
if (err) {
return err;
}
@ -6022,17 +6022,17 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
}
if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
_buffer_memory_barrier(buffer->buffer, p_offset, p_size_bytes, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
}
#endif
return err;
}
Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier) {
Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, uint32_t p_post_barrier) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
ERR_FAIL_COND_V_MSG((p_size_bytes % 4) != 0, ERR_INVALID_PARAMETER,
"Size must be a multiple of four");
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
"Updating buffers in is forbidden during creation of a draw list");
@ -6052,13 +6052,13 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
}
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
ERR_FAIL_COND_V_MSG(p_offset + p_size_bytes > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size_bytes) - buffer->size) + " bytes) past the end.");
// should not be needed
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, p_post_barrier);
vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0);
vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size_bytes, 0);
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
@ -6067,7 +6067,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, dst_stage_mask);
_buffer_memory_barrier(buffer->buffer, p_offset, p_size_bytes, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, dst_stage_mask);
#endif
return OK;

View file

@ -1108,8 +1108,8 @@ public:
virtual bool uniform_set_is_valid(RID p_uniform_set);
virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata);
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL);
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, uint32_t p_post_barrier = BARRIER_MASK_ALL);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer);
/*************************/

View file

@ -32,6 +32,43 @@
#include "rendering_device_binds.h"
namespace {
Vector<uint8_t> getPackedArrayData(const Variant &p_variant, size_t &p_size_elem) {
Variant::Type dataType = p_variant.get_type();
p_size_elem = 0;
switch (dataType) {
case Variant::Type::PACKED_BYTE_ARRAY:
p_size_elem = sizeof(uint8_t);
return static_cast<const Vector<uint8_t> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_INT32_ARRAY:
p_size_elem = sizeof(uint32_t);
return static_cast<const Vector<int32_t> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_INT64_ARRAY:
p_size_elem = sizeof(uint64_t);
return static_cast<const Vector<int64_t> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_FLOAT32_ARRAY:
p_size_elem = sizeof(float);
return static_cast<const Vector<float> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_FLOAT64_ARRAY:
p_size_elem = sizeof(double);
return static_cast<const Vector<double> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_VECTOR2_ARRAY:
p_size_elem = sizeof(Vector2);
return static_cast<const Vector<Vector2> &>(p_variant).to_byte_array();
case Variant::Type::PACKED_VECTOR3_ARRAY:
// Alignment is not possible with Vector3.
break;
case Variant::Type::PACKED_COLOR_ARRAY:
p_size_elem = sizeof(Color);
return static_cast<const Vector<Color> &>(p_variant).to_byte_array();
default:
break;
}
return Vector<uint8_t>();
}
} // namespace
RenderingDevice *RenderingDevice::singleton = nullptr;
RenderingDevice *RenderingDevice::get_singleton() {
@ -231,6 +268,22 @@ RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv
return shader_create_from_spirv(stage_data);
}
RID RenderingDevice::uniform_buffer_create_generic(const Variant &p_data) {
size_t elem_size;
Vector<uint8_t> data = getPackedArrayData(p_data, elem_size);
ERR_FAIL_COND_V_MSG(data.is_empty(), RID(), "Can't create uniform buffer with data of type " + Variant::get_type_name(p_data.get_type()) + ".");
return uniform_buffer_create(data.size(), data);
}
RID RenderingDevice::storage_buffer_create_generic(const Variant &p_data, uint32_t p_usage) {
size_t elem_size;
Vector<uint8_t> data = getPackedArrayData(p_data, elem_size);
ERR_FAIL_COND_V_MSG(data.is_empty(), RID(), "Can't create storage buffer with data of type " + Variant::get_type_name(p_data.get_type()) + ".");
return storage_buffer_create(data.size(), data, p_usage);
}
RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set) {
Vector<Uniform> uniforms;
uniforms.resize(p_uniforms.size());
@ -242,8 +295,56 @@ RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader,
return uniform_set_create(uniforms, p_shader, p_shader_set);
}
Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) {
return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) {
return buffer_update(p_buffer, p_offset, p_size_bytes, p_data.ptr(), p_post_barrier);
}
Error RenderingDevice::buffer_update_generic(RID p_buffer, uint32_t p_index, uint32_t p_size, const Variant &p_data, uint32_t p_post_barrier) {
size_t elem_size;
Vector<uint8_t> data = getPackedArrayData(p_data, elem_size);
ERR_FAIL_COND_V_MSG(data.is_empty(), Error::ERR_INVALID_PARAMETER, "Can't update buffer with data of type " + Variant::get_type_name(p_data.get_type()) + ".");
return buffer_update(p_buffer, p_index * elem_size, p_size * elem_size, data.ptr(), p_post_barrier);
}
template <typename T>
Vector<T> RenderingDevice::_buffer_get_data(RID p_buffer) {
Vector<uint8_t> byte_data = buffer_get_data(p_buffer);
uint64_t size = byte_data.size();
const uint8_t *r = byte_data.ptr();
Vector<T> data;
data.resize(size / sizeof(T));
memcpy(data.ptrw(), r, size);
return data;
}
Variant RenderingDevice::buffer_get_data_generic(RID p_buffer, Variant::Type p_type) {
switch (p_type) {
case Variant::Type::PACKED_BYTE_ARRAY:
return buffer_get_data(p_buffer);
case Variant::Type::PACKED_INT32_ARRAY:
return _buffer_get_data<int32_t>(p_buffer);
case Variant::Type::PACKED_INT64_ARRAY:
return _buffer_get_data<int64_t>(p_buffer);
case Variant::Type::PACKED_FLOAT32_ARRAY:
return _buffer_get_data<float>(p_buffer);
case Variant::Type::PACKED_FLOAT64_ARRAY:
return _buffer_get_data<double>(p_buffer);
case Variant::Type::PACKED_VECTOR2_ARRAY:
return _buffer_get_data<Vector2>(p_buffer);
case Variant::Type::PACKED_VECTOR3_ARRAY:
// Alignment is not possible with Vector3.
break;
case Variant::Type::PACKED_COLOR_ARRAY:
return _buffer_get_data<Color>(p_buffer);
default:
break;
}
ERR_FAIL_V_MSG(Variant(), "Can't get buffer data with type " + Variant::get_type_name(p_type) + ".");
return Variant();
}
static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
@ -397,6 +498,8 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::shader_create_from_bytecode);
ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask);
ClassDB::bind_method(D_METHOD("uniform_buffer_create_generic", "data"), &RenderingDevice::uniform_buffer_create_generic);
ClassDB::bind_method(D_METHOD("storage_buffer_create_generic", "data", "usage"), &RenderingDevice::storage_buffer_create_generic, DEFVAL(0));
ClassDB::bind_method(D_METHOD("uniform_buffer_create", "size_bytes", "data"), &RenderingDevice::uniform_buffer_create, DEFVAL(Vector<uint8_t>()));
ClassDB::bind_method(D_METHOD("storage_buffer_create", "size_bytes", "data", "usage"), &RenderingDevice::storage_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("texture_buffer_create", "size_bytes", "format", "data"), &RenderingDevice::texture_buffer_create, DEFVAL(Vector<uint8_t>()));
@ -404,8 +507,12 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create);
ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid);
ClassDB::bind_method(D_METHOD("buffer_update_generic", "buffer", "index", "size", "data", "post_barrier"), &RenderingDevice::buffer_update_generic, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("buffer_get_data_generic", "buffer", "type"), &RenderingDevice::buffer_get_data_generic);
ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data);
ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));

View file

@ -716,7 +716,9 @@ public:
};
virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0) = 0;
RID uniform_buffer_create_generic(const Variant &p_data);
virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0) = 0;
RID storage_buffer_create_generic(const Variant &p_data, uint32_t p_usage = 0);
virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
struct Uniform {
@ -741,9 +743,12 @@ public:
typedef void (*UniformSetInvalidatedCallback)(const RID &, void *);
virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size_bytes, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
Error buffer_update_generic(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Variant &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving
Variant buffer_get_data_generic(RID p_buffer, Variant::Type p_type);
/******************************************/
/**** PIPELINE SPECIALIZATION CONSTANT ****/
@ -1226,6 +1231,8 @@ protected:
RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set);
Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
template <typename T>
Vector<T> _buffer_get_data(RID p_buffer);
RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);