DRW: Add double buffering of objects matrices, bounds, and infos
This allows easy delta calculation and access to last known position of deleted objects.
This commit is contained in:
parent
efe51f0220
commit
9c54f2655d
@ -11,6 +11,7 @@
|
||||
#include "GPU_debug.h"
|
||||
|
||||
#include "draw_command.hh"
|
||||
#include "draw_pass.hh"
|
||||
#include "draw_shader.h"
|
||||
#include "draw_view.hh"
|
||||
|
||||
@ -530,15 +531,20 @@ std::string StencilSet::serialize() const
|
||||
/** \name Commands buffers binding / command / resource ID generation
|
||||
* \{ */
|
||||
|
||||
void DrawCommandBuf::bind(RecordingState &state,
|
||||
Vector<Header, 0> &headers,
|
||||
Vector<Undetermined, 0> &commands)
|
||||
void DrawCommandBuf::finalize_commands(Vector<Header, 0> &headers,
|
||||
Vector<Undetermined, 0> &commands,
|
||||
SubPassVector &sub_passes,
|
||||
uint &resource_id_count,
|
||||
ResourceIdBuf &resource_id_buf)
|
||||
{
|
||||
UNUSED_VARS(headers, commands);
|
||||
|
||||
resource_id_count_ = 0;
|
||||
|
||||
for (const Header &header : headers) {
|
||||
if (header.type == Type::SubPass) {
|
||||
/** WARNING: Recursive. */
|
||||
auto &sub = sub_passes[int64_t(header.index)];
|
||||
finalize_commands(
|
||||
sub.headers_, sub.commands_, sub_passes, resource_id_count, resource_id_buf);
|
||||
}
|
||||
|
||||
if (header.type != Type::Draw) {
|
||||
continue;
|
||||
}
|
||||
@ -559,18 +565,28 @@ void DrawCommandBuf::bind(RecordingState &state,
|
||||
|
||||
if (cmd.handle.raw > 0) {
|
||||
/* Save correct offset to start of resource_id buffer region for this draw. */
|
||||
uint instance_first = resource_id_count_;
|
||||
resource_id_count_ += cmd.instance_len;
|
||||
uint instance_first = resource_id_count;
|
||||
resource_id_count += cmd.instance_len;
|
||||
/* Ensure the buffer is big enough. */
|
||||
resource_id_buf_.get_or_resize(resource_id_count_ - 1);
|
||||
resource_id_buf.get_or_resize(resource_id_count - 1);
|
||||
|
||||
/* Copy the resource id for all instances. */
|
||||
uint index = cmd.handle.resource_index();
|
||||
for (int i = instance_first; i < (instance_first + cmd.instance_len); i++) {
|
||||
resource_id_buf_[i] = index;
|
||||
resource_id_buf[i] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCommandBuf::bind(RecordingState &state,
|
||||
Vector<Header, 0> &headers,
|
||||
Vector<Undetermined, 0> &commands,
|
||||
SubPassVector &sub_passes)
|
||||
{
|
||||
resource_id_count_ = 0;
|
||||
|
||||
finalize_commands(headers, commands, sub_passes, resource_id_count_, resource_id_buf_);
|
||||
|
||||
resource_id_buf_.push_update();
|
||||
|
||||
|
@ -21,6 +21,12 @@
|
||||
#include "draw_state.h"
|
||||
#include "draw_view.hh"
|
||||
|
||||
/* Forward declarations. */
|
||||
namespace blender::draw::detail {
|
||||
template<typename T, int64_t block_size> class SubPassVector;
|
||||
template<typename DrawCommandBufType> class PassBase;
|
||||
} // namespace blender::draw::detail
|
||||
|
||||
namespace blender::draw::command {
|
||||
|
||||
class DrawCommandBuf;
|
||||
@ -411,6 +417,7 @@ class DrawCommandBuf {
|
||||
|
||||
private:
|
||||
using ResourceIdBuf = StorageArrayBuffer<uint, 128, false>;
|
||||
using SubPassVector = detail::SubPassVector<detail::PassBase<DrawCommandBuf>, 16>;
|
||||
|
||||
/** Array of resource id. One per instance. Generated on GPU and send to GPU. */
|
||||
ResourceIdBuf resource_id_buf_;
|
||||
@ -436,7 +443,17 @@ class DrawCommandBuf {
|
||||
commands[index].draw = {batch, instance_len, vertex_len, vertex_first, handle};
|
||||
}
|
||||
|
||||
void bind(RecordingState &state, Vector<Header, 0> &headers, Vector<Undetermined, 0> &commands);
|
||||
void bind(RecordingState &state,
|
||||
Vector<Header, 0> &headers,
|
||||
Vector<Undetermined, 0> &commands,
|
||||
SubPassVector &sub_passes);
|
||||
|
||||
private:
|
||||
static void finalize_commands(Vector<Header, 0> &headers,
|
||||
Vector<Undetermined, 0> &commands,
|
||||
SubPassVector &sub_passes,
|
||||
uint &resource_id_count,
|
||||
ResourceIdBuf &resource_id_buf);
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
@ -27,6 +27,10 @@ Manager::~Manager()
|
||||
|
||||
void Manager::begin_sync()
|
||||
{
|
||||
matrix_buf.swap();
|
||||
bounds_buf.swap();
|
||||
infos_buf.swap();
|
||||
|
||||
/* TODO: This means the reference is kept until further redraw or manager tear-down. Instead,
|
||||
* they should be released after each draw loop. But for now, mimics old DRW behavior. */
|
||||
for (GPUTexture *texture : acquired_textures) {
|
||||
@ -39,9 +43,9 @@ void Manager::begin_sync()
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Detect uninitialized data. */
|
||||
memset(matrix_buf.data(), 0xF0, resource_len_ * sizeof(*matrix_buf.data()));
|
||||
memset(bounds_buf.data(), 0xF0, resource_len_ * sizeof(*bounds_buf.data()));
|
||||
memset(infos_buf.data(), 0xF0, resource_len_ * sizeof(*infos_buf.data()));
|
||||
memset(matrix_buf.current().data(), 0xF0, resource_len_ * sizeof(*matrix_buf.current().data()));
|
||||
memset(bounds_buf.current().data(), 0xF0, resource_len_ * sizeof(*bounds_buf.current().data()));
|
||||
memset(infos_buf.current().data(), 0xF0, resource_len_ * sizeof(*infos_buf.current().data()));
|
||||
#endif
|
||||
resource_len_ = 0;
|
||||
attribute_len_ = 0;
|
||||
@ -88,9 +92,9 @@ void Manager::end_sync()
|
||||
|
||||
sync_layer_attributes();
|
||||
|
||||
matrix_buf.push_update();
|
||||
bounds_buf.push_update();
|
||||
infos_buf.push_update();
|
||||
matrix_buf.current().push_update();
|
||||
bounds_buf.current().push_update();
|
||||
infos_buf.current().push_update();
|
||||
attributes_buf.push_update();
|
||||
layer_attributes_buf.push_update();
|
||||
attributes_buf_legacy.push_update();
|
||||
@ -104,9 +108,9 @@ void Manager::end_sync()
|
||||
GPUShader *shader = DRW_shader_draw_resource_finalize_get();
|
||||
GPU_shader_bind(shader);
|
||||
GPU_shader_uniform_1i(shader, "resource_len", resource_len_);
|
||||
GPU_storagebuf_bind(matrix_buf, GPU_shader_get_ssbo(shader, "matrix_buf"));
|
||||
GPU_storagebuf_bind(bounds_buf, GPU_shader_get_ssbo(shader, "bounds_buf"));
|
||||
GPU_storagebuf_bind(infos_buf, GPU_shader_get_ssbo(shader, "infos_buf"));
|
||||
GPU_storagebuf_bind(matrix_buf.current(), GPU_shader_get_ssbo(shader, "matrix_buf"));
|
||||
GPU_storagebuf_bind(bounds_buf.current(), GPU_shader_get_ssbo(shader, "bounds_buf"));
|
||||
GPU_storagebuf_bind(infos_buf.current(), GPU_shader_get_ssbo(shader, "infos_buf"));
|
||||
GPU_compute_dispatch(shader, thread_groups, 1, 1);
|
||||
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
|
||||
@ -130,8 +134,8 @@ void Manager::debug_bind()
|
||||
|
||||
void Manager::resource_bind()
|
||||
{
|
||||
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
|
||||
GPU_storagebuf_bind(matrix_buf.current(), DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf.current(), DRW_OBJ_INFOS_SLOT);
|
||||
GPU_storagebuf_bind(attributes_buf, DRW_OBJ_ATTR_SLOT);
|
||||
GPU_uniformbuf_bind(layer_attributes_buf, DRW_LAYER_ATTR_UBO_SLOT);
|
||||
/* 2 is the hardcoded location of the uniform attr UBO. */
|
||||
@ -148,7 +152,7 @@ void Manager::submit(PassSimple &pass, View &view)
|
||||
command::RecordingState state;
|
||||
state.inverted_view = view.is_inverted();
|
||||
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_);
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_, pass.sub_passes_);
|
||||
|
||||
resource_bind();
|
||||
|
||||
@ -166,7 +170,7 @@ void Manager::submit(PassMain &pass, View &view)
|
||||
bool freeze_culling = (U.experimental.use_viewport_debug && DST.draw_ctx.v3d &&
|
||||
(DST.draw_ctx.v3d->debug_flag & V3D_DEBUG_FREEZE_CULLING) != 0);
|
||||
|
||||
view.compute_visibility(bounds_buf, resource_len_, freeze_culling);
|
||||
view.compute_visibility(bounds_buf.current(), resource_len_, freeze_culling);
|
||||
|
||||
command::RecordingState state;
|
||||
state.inverted_view = view.is_inverted();
|
||||
@ -198,7 +202,7 @@ void Manager::submit(PassSimple &pass)
|
||||
|
||||
command::RecordingState state;
|
||||
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_);
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_, pass.sub_passes_);
|
||||
|
||||
resource_bind();
|
||||
|
||||
@ -239,14 +243,14 @@ Manager::SubmitDebugOutput Manager::submit_debug(PassMain &pass, View &view)
|
||||
|
||||
Manager::DataDebugOutput Manager::data_debug()
|
||||
{
|
||||
matrix_buf.read();
|
||||
bounds_buf.read();
|
||||
infos_buf.read();
|
||||
matrix_buf.current().read();
|
||||
bounds_buf.current().read();
|
||||
infos_buf.current().read();
|
||||
|
||||
Manager::DataDebugOutput output;
|
||||
output.matrices = {matrix_buf.data(), resource_len_};
|
||||
output.bounds = {bounds_buf.data(), resource_len_};
|
||||
output.infos = {infos_buf.data(), resource_len_};
|
||||
output.matrices = {matrix_buf.current().data(), resource_len_};
|
||||
output.bounds = {bounds_buf.current().data(), resource_len_};
|
||||
output.infos = {infos_buf.current().data(), resource_len_};
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -72,9 +72,9 @@ class Manager {
|
||||
* Buffers containing all object data. Referenced by resource index.
|
||||
* Exposed as public members for shader access after sync.
|
||||
*/
|
||||
ObjectMatricesBuf matrix_buf;
|
||||
ObjectBoundsBuf bounds_buf;
|
||||
ObjectInfosBuf infos_buf;
|
||||
SwapChain<ObjectMatricesBuf, 2> matrix_buf;
|
||||
SwapChain<ObjectBoundsBuf, 2> bounds_buf;
|
||||
SwapChain<ObjectInfosBuf, 2> infos_buf;
|
||||
|
||||
/**
|
||||
* Object Attributes are reference by indirection data inside ObjectInfos.
|
||||
@ -193,17 +193,17 @@ class Manager {
|
||||
inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
|
||||
{
|
||||
bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
|
||||
matrix_buf.get_or_resize(resource_len_).sync(*ref.object);
|
||||
bounds_buf.get_or_resize(resource_len_).sync(*ref.object);
|
||||
infos_buf.get_or_resize(resource_len_).sync(ref, is_active_object);
|
||||
matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
|
||||
bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
|
||||
infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object);
|
||||
return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
|
||||
}
|
||||
|
||||
inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix)
|
||||
{
|
||||
matrix_buf.get_or_resize(resource_len_).sync(model_matrix);
|
||||
bounds_buf.get_or_resize(resource_len_).sync();
|
||||
infos_buf.get_or_resize(resource_len_).sync();
|
||||
matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
|
||||
bounds_buf.current().get_or_resize(resource_len_).sync();
|
||||
infos_buf.current().get_or_resize(resource_len_).sync();
|
||||
return ResourceHandle(resource_len_++, false);
|
||||
}
|
||||
|
||||
@ -211,9 +211,9 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix,
|
||||
const float3 &bounds_center,
|
||||
const float3 &bounds_half_extent)
|
||||
{
|
||||
matrix_buf.get_or_resize(resource_len_).sync(model_matrix);
|
||||
bounds_buf.get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
|
||||
infos_buf.get_or_resize(resource_len_).sync();
|
||||
matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
|
||||
bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
|
||||
infos_buf.current().get_or_resize(resource_len_).sync();
|
||||
return ResourceHandle(resource_len_++, false);
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ inline void Manager::extract_object_attributes(ResourceHandle handle,
|
||||
const ObjectRef &ref,
|
||||
Span<GPUMaterial *> materials)
|
||||
{
|
||||
ObjectInfos &infos = infos_buf.get_or_resize(handle.resource_index());
|
||||
ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
|
||||
infos.object_attrs_offset = attribute_len_;
|
||||
|
||||
/* Simple cache solution to avoid duplicates. */
|
||||
|
@ -55,12 +55,15 @@
|
||||
#include "intern/gpu_codegen.h"
|
||||
|
||||
namespace blender::draw {
|
||||
|
||||
using namespace blender::draw;
|
||||
using namespace blender::draw::command;
|
||||
|
||||
class Manager;
|
||||
|
||||
namespace command {
|
||||
class DrawCommandBuf;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Pass API
|
||||
* \{ */
|
||||
@ -112,6 +115,7 @@ template<
|
||||
typename DrawCommandBufType>
|
||||
class PassBase {
|
||||
friend Manager;
|
||||
friend DrawCommandBuf;
|
||||
|
||||
/** Will use texture own sampler state. */
|
||||
static constexpr eGPUSamplerState sampler_auto = GPU_SAMPLER_MAX;
|
||||
|
Loading…
Reference in New Issue
Block a user