diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 8c89c28a628..0455e2ab9d6 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -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 &headers, - Vector &commands) +void DrawCommandBuf::finalize_commands(Vector &headers, + Vector &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 &headers, + Vector &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(); diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh index 760531899f4..45a7ff417ac 100644 --- a/source/blender/draw/intern/draw_command.hh +++ b/source/blender/draw/intern/draw_command.hh @@ -21,6 +21,12 @@ #include "draw_state.h" #include "draw_view.hh" +/* Forward declarations. */ +namespace blender::draw::detail { +template class SubPassVector; +template class PassBase; +} // namespace blender::draw::detail + namespace blender::draw::command { class DrawCommandBuf; @@ -411,6 +417,7 @@ class DrawCommandBuf { private: using ResourceIdBuf = StorageArrayBuffer; + using SubPassVector = detail::SubPassVector, 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 &headers, Vector &commands); + void bind(RecordingState &state, + Vector &headers, + Vector &commands, + SubPassVector &sub_passes); + + private: + static void finalize_commands(Vector &headers, + Vector &commands, + SubPassVector &sub_passes, + uint &resource_id_count, + ResourceIdBuf &resource_id_buf); }; /** \} */ diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index 37ed1de1dfe..7bf83872344 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -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; } diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index 0a865179cee..51d5c841711 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -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 matrix_buf; + SwapChain bounds_buf; + SwapChain 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 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. */ diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index 8523b9ae5e6..6244218f3ff 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -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;