diff --git a/source/blender/draw/engines/eevee/eevee_light.cc b/source/blender/draw/engines/eevee/eevee_light.cc index 5ad66846dff..c9ffc007eb9 100644 --- a/source/blender/draw/engines/eevee/eevee_light.cc +++ b/source/blender/draw/engines/eevee/eevee_light.cc @@ -322,11 +322,9 @@ float Light::point_radiance_get() void Light::debug_draw() { -#ifndef NDEBUG drw_debug_sphere(transform_location(this->object_to_world), local.influence_radius_max, float4(0.8f, 0.3f, 0.0f, 1.0f)); -#endif } /** \} */ diff --git a/source/blender/draw/engines/eevee/eevee_shadow.cc b/source/blender/draw/engines/eevee/eevee_shadow.cc index 8bac57d8897..7cec6e1d558 100644 --- a/source/blender/draw/engines/eevee/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee/eevee_shadow.cc @@ -120,7 +120,6 @@ void ShadowTileMap::sync_cubeface(eLightType light_type_, void ShadowTileMap::debug_draw() const { -#ifdef WITH_DRAW_DEBUG /** Used for debug drawing. */ const float4 debug_color[6] = { {1.0f, 0.1f, 0.1f, 1.0f}, @@ -135,7 +134,6 @@ void ShadowTileMap::debug_draw() const float4x4 persinv = winmat * viewmat; drw_debug_matrix_as_bbox(math::invert(persinv), color); -#endif } /** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.cc b/source/blender/draw/engines/overlay/overlay_next_instance.cc index 9034cd27e1a..cb31cd71738 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_next_instance.cc @@ -13,6 +13,7 @@ #include "BKE_paint.hh" +#include "draw_debug.hh" #include "overlay_next_instance.hh" namespace blender::draw::overlay { @@ -732,6 +733,8 @@ void Instance::draw(Manager &manager) resources.acquire(DRW_context_get(), this->state); + DRW_submission_start(); + /* TODO(fclem): Would be better to have a v2d overlay class instead of these conditions. */ switch (state.space_type) { case SPACE_NODE: @@ -747,6 +750,8 @@ void Instance::draw(Manager &manager) BLI_assert_unreachable(); } + DRW_submission_end(); + resources.release(); resources.read_result(); @@ -857,6 +862,10 @@ void Instance::draw_v3d(Manager &manager, View &view) } } + if (BLI_thread_is_main() && !state.hide_overlays) { + DebugDraw::get().display_to_view(view); + } + regular.prepass.draw_line(resources.overlay_line_fb, manager, view); /* TODO(fclem): Split overlay and rename draw functions. */ diff --git a/source/blender/draw/intern/draw_context.cc b/source/blender/draw/intern/draw_context.cc index 23de911bdcc..a6d59127969 100644 --- a/source/blender/draw/intern/draw_context.cc +++ b/source/blender/draw/intern/draw_context.cc @@ -978,8 +978,6 @@ static void drw_callbacks_post_scene(DRWContext &draw_ctx) GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } - drw_debug_draw(); - GPU_depth_test(GPU_DEPTH_NONE); /* Apply state for callbacks. */ GPU_apply_state(); @@ -1194,7 +1192,6 @@ static void drw_draw_render_loop_3d(DRWContext &draw_ctx, RenderEngineType *engi draw_ctx.enable_engines(gpencil_engine_needed, engine_type); draw_ctx.engines_data_validate(); - drw_debug_init(); draw_ctx.engines_init_and_sync([&](DupliCacheManager &duplis, ExtractionGraph &extraction) { /* Only iterate over objects for internal engines or when overlays are enabled */ if (do_populate_loop) { @@ -1249,7 +1246,6 @@ static void drw_draw_render_loop_2d(DRWContext &draw_ctx) draw_ctx.enable_engines(); draw_ctx.engines_data_validate(); - drw_debug_init(); draw_ctx.engines_init_and_sync([&](DupliCacheManager & /*duplis*/, ExtractionGraph &extraction) { /* Only iterate over objects when overlay uses object data. */ if (do_populate_loop) { diff --git a/source/blender/draw/intern/draw_context_private.hh b/source/blender/draw/intern/draw_context_private.hh index 237df40a68a..ef6b7ff0e5b 100644 --- a/source/blender/draw/intern/draw_context_private.hh +++ b/source/blender/draw/intern/draw_context_private.hh @@ -74,11 +74,6 @@ struct DRWData { /* Get thread local draw context. */ DRWContext &drw_get(); -void drw_debug_draw(); -void drw_debug_init(); -void drw_debug_module_free(DRWDebugModule *module); -GPUStorageBuf *drw_debug_gpu_draw_buf_get(); - void drw_batch_cache_validate(Object *ob); void drw_batch_cache_generate_requested(Object *ob, TaskGraph &task_graph); diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index 0f6bbd8a15f..bb1d729d269 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -9,6 +9,7 @@ */ #include "BKE_object.hh" +#include "BLI_math_bits.h" #include "BLI_math_matrix.h" #include "BLI_math_matrix.hh" #include "GPU_batch.hh" @@ -25,66 +26,58 @@ namespace blender::draw { /** \name Init and state * \{ */ -DebugDraw::DebugDraw() +void DebugDraw::reset() { - constexpr int circle_resolution = 16; - for (auto axis : IndexRange(3)) { - for (auto edge : IndexRange(circle_resolution)) { - for (auto vert : IndexRange(2)) { - const float angle = (2 * M_PI) * (edge + vert) / float(circle_resolution); - const float point[3] = {cosf(angle), sinf(angle), 0.0f}; - sphere_verts_.append( - float3(point[(0 + axis) % 3], point[(1 + axis) % 3], point[(2 + axis) % 3])); - } + for (int i = 0; i < 2; i++) { + vertex_len_.store(0); + + if (cpu_draw_buf_.current() == nullptr) { + cpu_draw_buf_.current() = MEM_new("DebugDrawBuf-CPU", "DebugDrawBuf-CPU"); + gpu_draw_buf_.current() = MEM_new("DebugDrawBuf-GPU", "DebugDrawBuf-GPU"); } + + cpu_draw_buf_.current()->command.vertex_len = 0; + cpu_draw_buf_.current()->command.vertex_first = 0; + cpu_draw_buf_.current()->command.instance_len = 1; + cpu_draw_buf_.current()->command.instance_first_array = 0; + + gpu_draw_buf_.current()->command.vertex_len = 0; + gpu_draw_buf_.current()->command.vertex_first = 0; + gpu_draw_buf_.current()->command.instance_len = 1; + gpu_draw_buf_.current()->command.instance_first_array = 0; + gpu_draw_buf_.current()->push_update(); + + cpu_draw_buf_.swap(); + gpu_draw_buf_.swap(); } - constexpr int point_resolution = 4; - for (auto axis : IndexRange(3)) { - for (auto edge : IndexRange(point_resolution)) { - for (auto vert : IndexRange(2)) { - const float angle = (2 * M_PI) * (edge + vert) / float(point_resolution); - const float point[3] = {cosf(angle), sinf(angle), 0.0f}; - point_verts_.append( - float3(point[(0 + axis) % 3], point[(1 + axis) % 3], point[(2 + axis) % 3])); - } - } - } -}; - -void DebugDraw::init() -{ - cpu_draw_buf_.command.vertex_len = 0; - cpu_draw_buf_.command.vertex_first = 0; - cpu_draw_buf_.command.instance_len = 1; - cpu_draw_buf_.command.instance_first_array = 0; - - gpu_draw_buf_.command.vertex_len = 0; - gpu_draw_buf_.command.vertex_first = 0; - gpu_draw_buf_.command.instance_len = 1; - gpu_draw_buf_.command.instance_first_array = 0; gpu_draw_buf_used = false; - - modelmat_reset(); -} - -void DebugDraw::modelmat_reset() -{ - model_mat_ = float4x4::identity(); -} - -void DebugDraw::modelmat_set(const float modelmat[4][4]) -{ - model_mat_ = float4x4_view(modelmat); } GPUStorageBuf *DebugDraw::gpu_draw_buf_get() { - if (!gpu_draw_buf_used) { - gpu_draw_buf_used = true; - gpu_draw_buf_.push_update(); +#ifdef WITH_DRAW_DEBUG + gpu_draw_buf_used = true; + return *gpu_draw_buf_.current(); +#else + return nullptr; +#endif +} + +void DebugDraw::clear_gpu_data() +{ + for (int i = 0; i < 2; i++) { + MEM_SAFE_DELETE(cpu_draw_buf_.current()); + MEM_SAFE_DELETE(gpu_draw_buf_.current()); + + cpu_draw_buf_.swap(); + gpu_draw_buf_.swap(); } - return gpu_draw_buf_; +} + +void drw_debug_clear() +{ + DebugDraw::get().reset(); } /** \} */ @@ -93,61 +86,101 @@ GPUStorageBuf *DebugDraw::gpu_draw_buf_get() /** \name Draw functions * \{ */ -void DebugDraw::draw_line(float3 v1, float3 v2, float4 color) +void drw_debug_line(const float3 v1, const float3 v2, const float4 color, const uint lifetime) { - draw_line(v1, v2, color_pack(color)); + DebugDraw &dd = DebugDraw::get(); + dd.draw_line(v1, v2, debug_color_pack(color), lifetime); } -void DebugDraw::draw_polygon(Span face_verts, float4 color) +void drw_debug_polygon(Span face_verts, const float4 color, const uint lifetime) { BLI_assert(!face_verts.is_empty()); - - uint col = color_pack(color); - float3 v0 = math::transform_point(model_mat_, face_verts.last()); + DebugDraw &dd = DebugDraw::get(); + uint col = debug_color_pack(color); + float3 v0 = face_verts.last(); for (auto vert : face_verts) { - float3 v1 = math::transform_point(model_mat_, vert); - draw_line(v0, v1, col); + float3 v1 = vert; + dd.draw_line(v0, v1, col, lifetime); v0 = v1; } } -void DebugDraw::draw_matrix(const float4x4 &m4) +void drw_debug_bbox(const BoundBox &bbox, const float4 color, const uint lifetime) { - float3 v0 = float3(0.0f, 0.0f, 0.0f); - float3 v1 = float3(1.0f, 0.0f, 0.0f); - float3 v2 = float3(0.0f, 1.0f, 0.0f); - float3 v3 = float3(0.0f, 0.0f, 1.0f); + DebugDraw &dd = DebugDraw::get(); + uint col = debug_color_pack(color); + dd.draw_line(bbox.vec[0], bbox.vec[1], col, lifetime); + dd.draw_line(bbox.vec[1], bbox.vec[2], col, lifetime); + dd.draw_line(bbox.vec[2], bbox.vec[3], col, lifetime); + dd.draw_line(bbox.vec[3], bbox.vec[0], col, lifetime); - mul_project_m4_v3(m4.ptr(), v0); - mul_project_m4_v3(m4.ptr(), v1); - mul_project_m4_v3(m4.ptr(), v2); - mul_project_m4_v3(m4.ptr(), v3); + dd.draw_line(bbox.vec[4], bbox.vec[5], col, lifetime); + dd.draw_line(bbox.vec[5], bbox.vec[6], col, lifetime); + dd.draw_line(bbox.vec[6], bbox.vec[7], col, lifetime); + dd.draw_line(bbox.vec[7], bbox.vec[4], col, lifetime); - draw_line(v0, v1, float4(1.0f, 0.0f, 0.0f, 1.0f)); - draw_line(v0, v2, float4(0.0f, 1.0f, 0.0f, 1.0f)); - draw_line(v0, v3, float4(0.0f, 0.0f, 1.0f, 1.0f)); + dd.draw_line(bbox.vec[0], bbox.vec[4], col, lifetime); + dd.draw_line(bbox.vec[1], bbox.vec[5], col, lifetime); + dd.draw_line(bbox.vec[2], bbox.vec[6], col, lifetime); + dd.draw_line(bbox.vec[3], bbox.vec[7], col, lifetime); } -void DebugDraw::draw_bbox(const BoundBox &bbox, const float4 color) +static Vector precompute_sphere_points(int circle_resolution) { - uint col = color_pack(color); - draw_line(bbox.vec[0], bbox.vec[1], col); - draw_line(bbox.vec[1], bbox.vec[2], col); - draw_line(bbox.vec[2], bbox.vec[3], col); - draw_line(bbox.vec[3], bbox.vec[0], col); - - draw_line(bbox.vec[4], bbox.vec[5], col); - draw_line(bbox.vec[5], bbox.vec[6], col); - draw_line(bbox.vec[6], bbox.vec[7], col); - draw_line(bbox.vec[7], bbox.vec[4], col); - - draw_line(bbox.vec[0], bbox.vec[4], col); - draw_line(bbox.vec[1], bbox.vec[5], col); - draw_line(bbox.vec[2], bbox.vec[6], col); - draw_line(bbox.vec[3], bbox.vec[7], col); + Vector result; + for (auto axis : IndexRange(3)) { + for (auto edge : IndexRange(circle_resolution)) { + for (auto vert : IndexRange(2)) { + const float angle = (2 * M_PI) * (edge + vert) / float(circle_resolution); + const float point[3] = {cosf(angle), sinf(angle), 0.0f}; + result.append(float3(point[(0 + axis) % 3], point[(1 + axis) % 3], point[(2 + axis) % 3])); + } + } + } + return result; } -void DebugDraw::draw_matrix_as_bbox(const float4x4 &mat, const float4 color) +void drw_debug_sphere(const float3 center, float radius, const float4 color, const uint lifetime) +{ + /** Precomputed shapes verts. */ + static Vector sphere_verts = precompute_sphere_points(16); + + DebugDraw &dd = DebugDraw::get(); + uint col = debug_color_pack(color); + for (auto i : IndexRange(sphere_verts.size() / 2)) { + float3 v0 = sphere_verts[i * 2] * radius + center; + float3 v1 = sphere_verts[i * 2 + 1] * radius + center; + dd.draw_line(v0, v1, col, lifetime); + } +} + +void drw_debug_point(const float3 pos, float rad, const float4 col, const uint lifetime) +{ + static Vector point_verts = precompute_sphere_points(4); + + DebugDraw &dd = DebugDraw::get(); + uint color = debug_color_pack(col); + for (auto i : IndexRange(point_verts.size() / 2)) { + float3 v0 = point_verts[i * 2] * rad + pos; + float3 v1 = point_verts[i * 2 + 1] * rad + pos; + dd.draw_line(v0, v1, color, lifetime); + } +} + +void drw_debug_matrix(const float4x4 &m4, const uint lifetime) +{ + float3 v0 = math::transform_point(m4, float3(0.0f, 0.0f, 0.0f)); + float3 v1 = math::transform_point(m4, float3(1.0f, 0.0f, 0.0f)); + float3 v2 = math::transform_point(m4, float3(0.0f, 1.0f, 0.0f)); + float3 v3 = math::transform_point(m4, float3(0.0f, 0.0f, 1.0f)); + + DebugDraw &dd = DebugDraw::get(); + dd.draw_line(v0, v1, debug_color_pack(float4(1.0f, 0.0f, 0.0f, 1.0f)), lifetime); + dd.draw_line(v0, v2, debug_color_pack(float4(0.0f, 1.0f, 0.0f, 1.0f)), lifetime); + dd.draw_line(v0, v3, debug_color_pack(float4(0.0f, 0.0f, 1.0f, 1.0f)), lifetime); +} + +void drw_debug_matrix_as_bbox(const float4x4 &mat, const float4 color, const uint lifetime) { BoundBox bb; const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; @@ -155,27 +188,7 @@ void DebugDraw::draw_matrix_as_bbox(const float4x4 &mat, const float4 color) for (auto i : IndexRange(8)) { mul_project_m4_v3(mat.ptr(), bb.vec[i]); } - draw_bbox(bb, color); -} - -void DebugDraw::draw_sphere(const float3 center, float radius, const float4 color) -{ - uint col = color_pack(color); - for (auto i : IndexRange(sphere_verts_.size() / 2)) { - float3 v0 = sphere_verts_[i * 2] * radius + center; - float3 v1 = sphere_verts_[i * 2 + 1] * radius + center; - draw_line(v0, v1, col); - } -} - -void DebugDraw::draw_point(const float3 center, float radius, const float4 color) -{ - uint col = color_pack(color); - for (auto i : IndexRange(point_verts_.size() / 2)) { - float3 v0 = point_verts_[i * 2] * radius + center; - float3 v1 = point_verts_[i * 2 + 1] * radius + center; - draw_line(v0, v1, col); - } + drw_debug_bbox(bb, color, lifetime); } /** \} */ @@ -183,91 +196,96 @@ void DebugDraw::draw_point(const float3 center, float radius, const float4 color /* -------------------------------------------------------------------- */ /** \name Internals * - * IMPORTANT: All of these are copied from the shader libraries (`common_debug_draw_lib.glsl`). - * They need to be kept in sync to write the same data. * \{ */ -void DebugDraw::draw_line(float3 v1, float3 v2, uint color) +void DebugDraw::draw_line(float3 v1, float3 v2, uint color, const uint lifetime) { - DebugDrawBuf &buf = cpu_draw_buf_; - uint index = buf.command.vertex_len; + DebugDrawBuf &buf = *cpu_draw_buf_.current(); + uint index = vertex_len_.fetch_add(2); if (index + 2 < DRW_DEBUG_DRAW_VERT_MAX) { - buf.verts[index + 0] = vert_pack(math::transform_point(model_mat_, v1), color); - buf.verts[index + 1] = vert_pack(math::transform_point(model_mat_, v2), color); + buf.verts[index / 2] = debug_line_make(float_as_uint(v1.x), + float_as_uint(v1.y), + float_as_uint(v1.z), + float_as_uint(v2.x), + float_as_uint(v2.y), + float_as_uint(v2.z), + color, + lifetime); buf.command.vertex_len += 2; } } -uint DebugDraw::color_pack(float4 color) -{ - /* NOTE: keep in sync with #drw_debug_color_pack(). */ - - color = math::clamp(color, 0.0f, 1.0f); - uint result = 0; - result |= uint(color.x * 255.0f) << 0u; - result |= uint(color.y * 255.0f) << 8u; - result |= uint(color.z * 255.0f) << 16u; - result |= uint(color.w * 255.0f) << 24u; - return result; -} - -DRWDebugVert DebugDraw::vert_pack(float3 pos, uint color) -{ - DRWDebugVert vert; - vert.pos0 = *reinterpret_cast(&pos.x); - vert.pos1 = *reinterpret_cast(&pos.y); - vert.pos2 = *reinterpret_cast(&pos.z); - vert.vert_color = color; - return vert; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Display * \{ */ -void DebugDraw::display_lines() +void DebugDraw::display_lines(View &view) { - if (cpu_draw_buf_.command.vertex_len == 0 && gpu_draw_buf_used == false) { + const bool cpu_draw_buf_used = vertex_len_.load() != 0; + + if (!cpu_draw_buf_used && !gpu_draw_buf_used) { return; } - GPU_debug_group_begin("Lines"); - cpu_draw_buf_.push_update(); - - float4x4 persmat = View::default_get().persmat(); command::StateSet::set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + gpu::Batch *batch = GPU_batch_procedural_lines_get(); GPUShader *shader = DRW_shader_debug_draw_display_get(); GPU_batch_set_shader(batch, shader); - GPU_shader_uniform_mat4(shader, "persmat", persmat.ptr()); + GPU_shader_uniform_mat4(shader, "persmat", view.persmat().ptr()); + GPU_shader_uniform_2f(shader, "size_viewport", viewport_size[2], viewport_size[3]); if (gpu_draw_buf_used) { - GPU_debug_group_begin("GPU"); - GPU_storagebuf_bind(gpu_draw_buf_, DRW_DEBUG_DRAW_SLOT); - GPU_batch_draw_indirect(batch, gpu_draw_buf_, 0); - GPU_storagebuf_unbind(gpu_draw_buf_); - GPU_debug_group_end(); + gpu::DebugScope debug_scope("GPU"); + /* Reset buffer. */ + gpu_draw_buf_.next()->command.vertex_len = 0; + gpu_draw_buf_.next()->push_update(); + + GPU_storagebuf_bind(*gpu_draw_buf_.current(), DRW_DEBUG_DRAW_SLOT); + GPU_storagebuf_bind(*gpu_draw_buf_.next(), DRW_DEBUG_DRAW_FEEDBACK_SLOT); + GPU_batch_draw_indirect(batch, *gpu_draw_buf_.current(), 0); + GPU_storagebuf_unbind(*gpu_draw_buf_.current()); + GPU_storagebuf_unbind(*gpu_draw_buf_.next()); } - GPU_debug_group_begin("CPU"); - GPU_storagebuf_bind(cpu_draw_buf_, DRW_DEBUG_DRAW_SLOT); - GPU_batch_draw_indirect(batch, cpu_draw_buf_, 0); - GPU_storagebuf_unbind(cpu_draw_buf_); - GPU_debug_group_end(); + { + gpu::DebugScope debug_scope("CPU"); + /* We might have race condition here (a writer thread might still be outputing vertices). + * But that is ok. At worse, we will be missing some vertex data and show 1 corrupted line. */ + cpu_draw_buf_.current()->command.vertex_len = vertex_len_.load(); + cpu_draw_buf_.current()->push_update(); + /* Reset buffer. */ + cpu_draw_buf_.next()->command.vertex_len = 0; + cpu_draw_buf_.next()->push_update(); - GPU_debug_group_end(); + GPU_storagebuf_bind(*cpu_draw_buf_.current(), DRW_DEBUG_DRAW_SLOT); + GPU_storagebuf_bind(*cpu_draw_buf_.next(), DRW_DEBUG_DRAW_FEEDBACK_SLOT); + GPU_batch_draw_indirect(batch, *cpu_draw_buf_.current(), 0); + GPU_storagebuf_unbind(*cpu_draw_buf_.current()); + GPU_storagebuf_unbind(*cpu_draw_buf_.next()); + + /* Read result of lifetime management. */ + cpu_draw_buf_.next()->read(); + vertex_len_.store(min_ii(DRW_DEBUG_DRAW_VERT_MAX, cpu_draw_buf_.next()->command.vertex_len)); + } + + gpu_draw_buf_.swap(); + cpu_draw_buf_.swap(); } -void DebugDraw::display_to_view() +void DebugDraw::display_to_view(View &view) { + /* Display only on the main thread. Avoid concurent usage of the resource. */ + BLI_assert(BLI_thread_is_main()); + GPU_debug_group_begin("DebugDraw"); - display_lines(); - /* Init again so we don't draw the same thing twice. */ - init(); + display_lines(view); GPU_debug_group_end(); } @@ -275,66 +293,3 @@ void DebugDraw::display_to_view() /** \} */ } // namespace blender::draw - -/* -------------------------------------------------------------------- */ -/** \name DebugDraw Access - * \{ */ - -blender::draw::DebugDraw *DRW_debug_get() -{ - /* This module is currently not in working state. Some refactor is needed (see #135521). */ - BLI_assert_unreachable(); -#ifdef WITH_DRAW_DEBUG - return reinterpret_cast(drw_get().debug); -#endif - return nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name C-API private - * \{ */ - -void drw_debug_draw() -{ -#ifdef WITH_DRAW_DEBUG - if (drw_get().debug == nullptr) { - return; - } - /* TODO(@fclem): Convenience for now. Will have to move to #DRWContext. */ - reinterpret_cast(drw_get().debug)->display_to_view(); -#endif -} - -void drw_debug_init() -{ - /* NOTE: Init is once per draw manager cycle. */ - - /* Module should not be used in release builds. */ - /* TODO(@fclem): Hide the functions declarations without using `ifdefs` everywhere. */ -#ifdef WITH_DRAW_DEBUG - /* TODO(@fclem): Convenience for now. Will have to move to #DRWContext. */ - if (drw_get().debug == nullptr) { - drw_get().debug = reinterpret_cast(new blender::draw::DebugDraw()); - } - reinterpret_cast(drw_get().debug)->init(); -#endif -} - -void drw_debug_module_free(DRWDebugModule *module) -{ - if (module != nullptr) { - delete reinterpret_cast(module); - } -} - -GPUStorageBuf *drw_debug_gpu_draw_buf_get() -{ -#ifdef WITH_DRAW_DEBUG - return reinterpret_cast(drw_get().debug)->gpu_draw_buf_get(); -#endif - return nullptr; -} - -/** \} */ diff --git a/source/blender/draw/intern/draw_debug.hh b/source/blender/draw/intern/draw_debug.hh index bfd4c0aafb1..bf8a2e35c02 100644 --- a/source/blender/draw/intern/draw_debug.hh +++ b/source/blender/draw/intern/draw_debug.hh @@ -16,7 +16,6 @@ #pragma once #include "BLI_math_vector_types.hh" -#include "BLI_vector.hh" #include "DNA_object_types.h" @@ -26,101 +25,120 @@ namespace blender::draw { -#if 0 /* The debug module is currently broken. Needs an overhaul (see #135521). */ -/* Shortcuts to avoid boilerplate code and match shader API. */ -# define drw_debug_line(...) DRW_debug_get()->draw_line(__VA_ARGS__) -# define drw_debug_polygon(...) DRW_debug_get()->draw_polygon(__VA_ARGS__) -# define drw_debug_bbox(...) DRW_debug_get()->draw_bbox(__VA_ARGS__) -# define drw_debug_sphere(...) DRW_debug_get()->draw_sphere(__VA_ARGS__) -# define drw_debug_point(...) DRW_debug_get()->draw_point(__VA_ARGS__) -# define drw_debug_matrix(...) DRW_debug_get()->draw_matrix(__VA_ARGS__) -# define drw_debug_matrix_as_bbox(...) DRW_debug_get()->draw_matrix_as_bbox(__VA_ARGS__) -#else -# define drw_debug_line(...) -# define drw_debug_polygon(...) -# define drw_debug_bbox(...) -# define drw_debug_sphere(...) -# define drw_debug_point(...) -# define drw_debug_matrix(...) -# define drw_debug_matrix_as_bbox(...) -#endif +class View; + +/** + * Clear all debug visuals (regardless of visual's lifetime). + * + * Usually called before populating persistent data to override previous visuals. + * Needs an active GPUContext. + */ +void drw_debug_clear(); + +/* Used for virtually infinite lifetime. + * Useful for debugging render or baking jobs, or non-modal operators. */ +constexpr uint drw_debug_persistent_lifetime = ~0u; + +/** + * Drawing functions that will draw wire-frames with the given color. + * + * IMPORTANT: `lifetime` is in unit of **display** and not in unit of time. + * One display is defined as one call to `DebugDraw::display_to_view` which happens once + * per 3D viewport if overlays are not turned off. + * + * - The default value of 1 is good for continuous event debugging in one viewport. + * - Above 1 is a good value for infrequent events or to compare continuous event history. + * Alternatively also allows replicating the display to several viewport. + * - drw_debug_persistent_lifetime is a good value for manually triggered event (e.g. an operator). + * It is best to clear the display cache (using `drw_debug_clear`) before adding new persistent + * visuals. + * + * All added debug drawing will be shared across viewports. If lifetime is greater than 1 or if a + * viewport doesn't display the visuals it produced, the visuals will be displayed onto other + * viewport(s). + * + * These functions are threadsafe and can be called concurrently at anytime, even outside the + * UI redraw loop. + */ + +void drw_debug_line(float3 v1, float3 v2, float4 color = {1, 0, 0, 1}, uint lifetime = 1); + +void drw_debug_polygon(Span face_verts, float4 color = {1, 0, 0, 1}, uint lifetime = 1); + +void drw_debug_bbox(const BoundBox &bbox, float4 color = {1, 0, 0, 1}, uint lifetime = 1); + +void drw_debug_sphere(float3 center, float radius, float4 color = {1, 0, 0, 1}, uint lifetime = 1); +/** Same as drw_debug_sphere but with small default radius. */ +void drw_debug_point(float3 pos, float rad = 0.01f, float4 col = {1, 0, 0, 1}, uint lifetime = 1); +/** Draw a matrix transform as 3 colored axes. */ +void drw_debug_matrix(const float4x4 &m4, uint lifetime = 1); +/** Draw a matrix as a 2 units length bounding box, centered on origin. */ +void drw_debug_matrix_as_bbox(const float4x4 &mat, float4 color = {1, 0, 0, 1}, uint lifetime = 1); class DebugDraw { private: using DebugDrawBuf = StorageBuffer; + /** + * Ensure thread-safety when adding geometry to the CPU debug buffer. + * GPU debug buffer currently expects draw submission to be externally synchronized. + */ + std::atomic vertex_len_; /** Data buffers containing all verts or chars to draw. */ - DebugDrawBuf cpu_draw_buf_ = {"DebugDrawBuf-CPU"}; - DebugDrawBuf gpu_draw_buf_ = {"DebugDrawBuf-GPU"}; + SwapChain cpu_draw_buf_ = {}; + SwapChain gpu_draw_buf_ = {}; /** True if the gpu buffer have been requested and may contain data to draw. */ bool gpu_draw_buf_used = false; - /** Matrix applied to all points before drawing. Could be a stack if needed. */ - float4x4 model_mat_; - /** Precomputed shapes verts. */ - Vector sphere_verts_; - Vector point_verts_; + + /* Reference counter used by GPUContext to allow freeing of DebugDrawBuf before the last + * context is destroyed. */ + int ref_count_ = 0; + std::mutex ref_count_mutex_; public: - DebugDraw(); - ~DebugDraw(){}; + void reset(); /** - * Resets all buffers and reset model matrix state. - * Not to be called by user. - */ - void init(); - - /** - * Resets model matrix state to identity. - */ - void modelmat_reset(); - /** - * Sets model matrix transform to apply to any vertex passed to drawing functions. - */ - void modelmat_set(const float modelmat[4][4]); - - /** - * Drawing functions that will draw wire-frames with the given color. - */ - void draw_line(float3 v1, float3 v2, float4 color = {1, 0, 0, 1}); - void draw_polygon(Span face_verts, float4 color = {1, 0, 0, 1}); - void draw_bbox(const BoundBox &bbox, const float4 color = {1, 0, 0, 1}); - void draw_sphere(const float3 center, float radius, const float4 color = {1, 0, 0, 1}); - void draw_point(const float3 center, float radius = 0.01f, const float4 color = {1, 0, 0, 1}); - /** - * Draw a matrix transformation as 3 colored axes. - */ - void draw_matrix(const float4x4 &m4); - /** - * Draw a matrix as a 2 units length bounding box, centered on origin. - */ - void draw_matrix_as_bbox(const float4x4 &mat, const float4 color = {1, 0, 0, 1}); - - /** - * Will draw all debug shapes and text cached up until now to the current view / frame-buffer. + * Draw all debug shapes to the given current view / frame-buffer. * Draw buffers will be emptied and ready for new debug data. */ - void display_to_view(); + void display_to_view(View &view); - /** - * Not to be called by user. Should become private. - */ + /** Get GPU debug draw buffer. Can, return nullptr if WITH_DRAW_DEBUG is not enabled. */ GPUStorageBuf *gpu_draw_buf_get(); + void acquire() + { + std::scoped_lock lock(ref_count_mutex_); + ref_count_++; + if (ref_count_ == 1) { + reset(); + } + } + + void release() + { + std::scoped_lock lock(ref_count_mutex_); + ref_count_--; + if (ref_count_ == 0) { + clear_gpu_data(); + } + } + + static DebugDraw &get() + { + static DebugDraw module; + return module; + } + + void draw_line(float3 v1, float3 v2, uint color, uint lifetime = 1); + + static uint color_pack(float4 color); + private: - uint color_pack(float4 color); - DRWDebugVert vert_pack(float3 pos, uint color); + void display_lines(View &view); - void draw_line(float3 v1, float3 v2, uint color); - - void display_lines(); + void clear_gpu_data(); }; } // namespace blender::draw - -/** - * Ease of use function to get the debug module. - * TODO(fclem): Should be removed once DRWContext is no longer global. - * IMPORTANT: Can return nullptr if storage buffer is not supported. - */ -blender::draw::DebugDraw *DRW_debug_get(); diff --git a/source/blender/draw/intern/draw_defines.hh b/source/blender/draw/intern/draw_defines.hh index d3103786034..22fffc1f675 100644 --- a/source/blender/draw/intern/draw_defines.hh +++ b/source/blender/draw/intern/draw_defines.hh @@ -29,8 +29,8 @@ #define DRW_OBJ_ATTR_SLOT 8 /* Slots 0-7 are reserved for engine use. */ /* Debug SSBOs are not counted in the limit [12 - 15+]. */ -#define DRW_DEBUG_PRINT_SLOT 15 #define DRW_DEBUG_DRAW_SLOT 14 +#define DRW_DEBUG_DRAW_FEEDBACK_SLOT 15 #define DRW_COMMAND_GROUP_SIZE 64 #define DRW_FINALIZE_GROUP_SIZE 64 diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index 475b86143fd..8b403b86afc 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -15,6 +15,7 @@ #include "GPU_compute.hh" #include "draw_context_private.hh" +#include "draw_debug.hh" #include "draw_defines.hh" #include "draw_manager.hh" #include "draw_pass.hh" @@ -146,15 +147,14 @@ void Manager::end_sync() void Manager::debug_bind() { -#ifdef WITH_DRAW_DEBUG - if (drw_get().debug == nullptr) { + GPUStorageBuf *gpu_buf = DebugDraw::get().gpu_draw_buf_get(); + if (gpu_buf == nullptr) { return; } - GPU_storagebuf_bind(drw_debug_gpu_draw_buf_get(), DRW_DEBUG_DRAW_SLOT); -# ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER + GPU_storagebuf_bind(gpu_buf, DRW_DEBUG_DRAW_SLOT); +#ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER /* Add a barrier to allow multiple shader writing to the same buffer. */ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); -# endif #endif } diff --git a/source/blender/draw/intern/draw_shader_shared.hh b/source/blender/draw/intern/draw_shader_shared.hh index 802f345db8b..99de89afe5c 100644 --- a/source/blender/draw/intern/draw_shader_shared.hh +++ b/source/blender/draw/intern/draw_shader_shared.hh @@ -5,6 +5,7 @@ #pragma once #if !defined(GPU_SHADER) && !defined(GLSL_CPP_STUBS) +# include "BLI_math_vector.hh" # include "GPU_shader.hh" # include "GPU_shader_shared_utils.hh" # include "draw_defines.hh" @@ -21,7 +22,7 @@ struct LayerAttribute; struct DrawCommand; struct DispatchCommand; struct DRWDebugPrintBuffer; -struct DRWDebugVert; +struct DRWDebugVertPair; struct DRWDebugDrawBuffer; struct FrustumCorners; struct FrustumPlanes; @@ -41,6 +42,8 @@ struct ObjectRef; } // namespace blender::draw +using namespace blender::math; + # endif #endif @@ -319,27 +322,55 @@ BLI_STATIC_ASSERT_ALIGN(DispatchCommand, 16) /** \name Debug draw shapes * \{ */ -struct DRWDebugVert { - /* This is a weird layout, but needed to be able to use DRWDebugVert as - * a DrawCommand and avoid alignment issues. See drw_debug_verts_buf[] definition. */ - uint pos0; - uint pos1; - uint pos2; +struct DRWDebugVertPair { + /* This is a weird layout, but needed to be able to use DRWDebugVertPair as + * a DrawCommand and avoid alignment issues. See drw_debug_lines_buf[] definition. */ + uint pos1_x; + uint pos1_y; + uint pos1_z; /* Named vert_color to avoid global namespace collision with uniform color. */ uint vert_color; -}; -BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16) -inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, uint in_vert_color) + uint pos2_x; + uint pos2_y; + uint pos2_z; + /* Number of time this line is supposed to be displayed. Decremented by one on display. */ + uint lifetime; +}; +BLI_STATIC_ASSERT_ALIGN(DRWDebugVertPair, 16) + +inline DRWDebugVertPair debug_line_make(uint in_pos1_x, + uint in_pos1_y, + uint in_pos1_z, + uint in_pos2_x, + uint in_pos2_y, + uint in_pos2_z, + uint in_vert_color, + uint in_lifetime) { - DRWDebugVert debug_vert; - debug_vert.pos0 = in_pos0; - debug_vert.pos1 = in_pos1; - debug_vert.pos2 = in_pos2; + DRWDebugVertPair debug_vert; + debug_vert.pos1_x = in_pos1_x; + debug_vert.pos1_y = in_pos1_y; + debug_vert.pos1_z = in_pos1_z; + debug_vert.pos2_x = in_pos2_x; + debug_vert.pos2_y = in_pos2_y; + debug_vert.pos2_z = in_pos2_z; debug_vert.vert_color = in_vert_color; + debug_vert.lifetime = in_lifetime; return debug_vert; } +inline uint debug_color_pack(float4 v_color) +{ + v_color = clamp(v_color, 0.0f, 1.0f); + uint result = 0; + result |= uint(v_color.x * 255.0) << 0u; + result |= uint(v_color.y * 255.0) << 8u; + result |= uint(v_color.z * 255.0) << 16u; + result |= uint(v_color.w * 255.0) << 24u; + return result; +} + /* Take the header (DrawCommand) into account. */ #define DRW_DEBUG_DRAW_VERT_MAX (64 * 8192) - 1 @@ -347,16 +378,16 @@ inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, ui * But we use plain array in shader code instead because of driver issues. */ struct DRWDebugDrawBuffer { DrawCommand command; - DRWDebugVert verts[DRW_DEBUG_DRAW_VERT_MAX]; + DRWDebugVertPair verts[DRW_DEBUG_DRAW_VERT_MAX]; }; BLI_STATIC_ASSERT_ALIGN(DRWDebugDrawBuffer, 16) /* Equivalent to `DRWDebugDrawBuffer.command.v_count`. */ -#define drw_debug_draw_v_count drw_debug_verts_buf[0].pos0 +#define drw_debug_draw_v_count(buf) buf[0].pos1_x /** - * Offset to the first data. Equal to: `sizeof(DrawCommand) / sizeof(DRWDebugVert)`. - * This is needed because we bind the whole buffer as a `DRWDebugVert` array. + * Offset to the first data. Equal to: `sizeof(DrawCommand) / sizeof(DRWDebugVertPair)`. + * This is needed because we bind the whole buffer as a `DRWDebugVertPair` array. */ -#define drw_debug_draw_offset 2 +#define drw_debug_draw_offset 1 /** \} */ diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index a293986e1b3..4446112e56a 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -18,9 +18,7 @@ #include "draw_shader.hh" #include "draw_view.hh" -#ifdef _DEBUG -# include "draw_debug.hh" -#endif +#include "draw_debug.hh" namespace blender::draw { @@ -267,12 +265,10 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, culling_freeze_[0] = static_cast(culling_[0]); culling_freeze_.push_update(); } -#ifdef WITH_DRAW_DEBUG if (debug_freeze) { float4x4 persmat = data_freeze_[0].winmat * data_freeze_[0].viewmat; drw_debug_matrix_as_bbox(math::invert(persmat), float4(0, 1, 0, 1)); } -#endif frozen_ = debug_freeze; GPU_debug_group_begin("View.compute_visibility"); diff --git a/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl b/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl index e2c3f770bd2..ba84a8c6a5e 100644 --- a/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl +++ b/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl @@ -20,6 +20,8 @@ SHADER_LIBRARY_CREATE_INFO(draw_debug_draw) /** Global switch option. */ bool drw_debug_draw_enable = true; # define drw_debug_default_color vec4(1.0, 0.0, 0.0, 1.0) +# define drw_debug_default_lifetime 1 +# define drw_debug_persistent_lifetime (~0u) /* -------------------------------------------------------------------- */ /** \name Internals @@ -27,28 +29,22 @@ bool drw_debug_draw_enable = true; uint drw_debug_start_draw(uint v_needed) { - uint vertid = atomicAdd(drw_debug_draw_v_count, v_needed); - vertid += drw_debug_draw_offset; + uint vertid = atomicAdd(drw_debug_draw_v_count(drw_debug_lines_buf), v_needed); return vertid; } -uint drw_debug_color_pack(vec4 v_color) +void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color, uint lifetime) { - v_color = clamp(v_color, 0.0, 1.0); - uint result = 0; - result |= uint(v_color.x * 255.0) << 0u; - result |= uint(v_color.y * 255.0) << 8u; - result |= uint(v_color.z * 255.0) << 16u; - result |= uint(v_color.w * 255.0) << 24u; - return result; -} - -void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color) -{ - drw_debug_verts_buf[vertid++] = debug_vert_make( - floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), v_color); - drw_debug_verts_buf[vertid++] = debug_vert_make( - floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), v_color); + uint out_line_id = vertid / 2u; + drw_debug_lines_buf[out_line_id + drw_debug_draw_offset] = debug_line_make(floatBitsToUint(v1.x), + floatBitsToUint(v1.y), + floatBitsToUint(v1.z), + floatBitsToUint(v2.x), + floatBitsToUint(v2.y), + floatBitsToUint(v2.z), + v_color, + lifetime); + vertid += 2; } /** \} */ @@ -60,7 +56,7 @@ void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color) /** * Draw a line. */ -void drw_debug_line(vec3 v1, vec3 v2, vec4 v_color) +void drw_debug_line(vec3 v1, vec3 v2, vec4 v_color, uint lifetime) { if (!drw_debug_draw_enable) { return; @@ -68,9 +64,13 @@ void drw_debug_line(vec3 v1, vec3 v2, vec4 v_color) const uint v_needed = 2; uint vertid = drw_debug_start_draw(v_needed); if (vertid + v_needed < DRW_DEBUG_DRAW_VERT_MAX) { - drw_debug_line(vertid, v1, v2, drw_debug_color_pack(v_color)); + drw_debug_line(vertid, v1, v2, debug_color_pack(v_color), lifetime); } } +void drw_debug_line(vec3 v1, vec3 v2, vec4 v_color) +{ + drw_debug_line(v1, v2, v_color, drw_debug_default_lifetime); +} void drw_debug_line(vec3 v1, vec3 v2) { drw_debug_line(v1, v2, drw_debug_default_color); @@ -79,7 +79,7 @@ void drw_debug_line(vec3 v1, vec3 v2) /** * Draw a quad contour. */ -void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 v_color) +void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 v_color, uint lifetime) { if (!drw_debug_draw_enable) { return; @@ -87,13 +87,17 @@ void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 v_color) const uint v_needed = 8; uint vertid = drw_debug_start_draw(v_needed); if (vertid + v_needed < DRW_DEBUG_DRAW_VERT_MAX) { - uint pcolor = drw_debug_color_pack(v_color); - drw_debug_line(vertid, v1, v2, pcolor); - drw_debug_line(vertid, v2, v3, pcolor); - drw_debug_line(vertid, v3, v4, pcolor); - drw_debug_line(vertid, v4, v1, pcolor); + uint pcolor = debug_color_pack(v_color); + drw_debug_line(vertid, v1, v2, pcolor, drw_debug_default_lifetime); + drw_debug_line(vertid, v2, v3, pcolor, drw_debug_default_lifetime); + drw_debug_line(vertid, v3, v4, pcolor, drw_debug_default_lifetime); + drw_debug_line(vertid, v4, v1, pcolor, drw_debug_default_lifetime); } } +void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 v_color) +{ + drw_debug_quad(v1, v2, v3, v4, v_color, drw_debug_default_lifetime); +} void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4) { drw_debug_quad(v1, v2, v3, v4, drw_debug_default_color); @@ -102,7 +106,7 @@ void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4) /** * Draw a point as octahedron wireframe. */ -void drw_debug_point(vec3 p, float radius, vec4 v_color) +void drw_debug_point(vec3 p, float radius, vec4 v_color, uint lifetime) { if (!drw_debug_draw_enable) { return; @@ -118,21 +122,25 @@ void drw_debug_point(vec3 p, float radius, vec4 v_color) const uint v_needed = 12 * 2; uint vertid = drw_debug_start_draw(v_needed); if (vertid + v_needed < DRW_DEBUG_DRAW_VERT_MAX) { - uint pcolor = drw_debug_color_pack(v_color); - drw_debug_line(vertid, v1, v2, pcolor); - drw_debug_line(vertid, v2, v3, pcolor); - drw_debug_line(vertid, v3, v4, pcolor); - drw_debug_line(vertid, v4, v1, pcolor); - drw_debug_line(vertid, v1, v5, pcolor); - drw_debug_line(vertid, v2, v5, pcolor); - drw_debug_line(vertid, v3, v5, pcolor); - drw_debug_line(vertid, v4, v5, pcolor); - drw_debug_line(vertid, v1, v6, pcolor); - drw_debug_line(vertid, v2, v6, pcolor); - drw_debug_line(vertid, v3, v6, pcolor); - drw_debug_line(vertid, v4, v6, pcolor); + uint pcolor = debug_color_pack(v_color); + drw_debug_line(vertid, v1, v2, pcolor, lifetime); + drw_debug_line(vertid, v2, v3, pcolor, lifetime); + drw_debug_line(vertid, v3, v4, pcolor, lifetime); + drw_debug_line(vertid, v4, v1, pcolor, lifetime); + drw_debug_line(vertid, v1, v5, pcolor, lifetime); + drw_debug_line(vertid, v2, v5, pcolor, lifetime); + drw_debug_line(vertid, v3, v5, pcolor, lifetime); + drw_debug_line(vertid, v4, v5, pcolor, lifetime); + drw_debug_line(vertid, v1, v6, pcolor, lifetime); + drw_debug_line(vertid, v2, v6, pcolor, lifetime); + drw_debug_line(vertid, v3, v6, pcolor, lifetime); + drw_debug_line(vertid, v4, v6, pcolor, lifetime); } } +void drw_debug_point(vec3 p, float radius, vec4 v_color) +{ + drw_debug_point(p, radius, v_color, drw_debug_default_lifetime); +} void drw_debug_point(vec3 p, float radius) { drw_debug_point(p, radius, drw_debug_default_color); @@ -145,7 +153,7 @@ void drw_debug_point(vec3 p) /** * Draw a sphere wireframe as 3 axes circle. */ -void drw_debug_sphere(vec3 p, float radius, vec4 v_color) +void drw_debug_sphere(vec3 p, float radius, vec4 v_color, uint lifetime) { if (!drw_debug_draw_enable) { return; @@ -154,7 +162,7 @@ void drw_debug_sphere(vec3 p, float radius, vec4 v_color) const uint v_needed = circle_resolution * 2 * 3; uint vertid = drw_debug_start_draw(v_needed); if (vertid + v_needed < DRW_DEBUG_DRAW_VERT_MAX) { - uint pcolor = drw_debug_color_pack(v_color); + uint pcolor = debug_color_pack(v_color); for (int axis = 0; axis < 3; axis++) { for (int edge = 0; edge < circle_resolution; edge++) { float angle1 = (2.0 * 3.141592) * float(edge + 0) / float(circle_resolution); @@ -165,11 +173,15 @@ void drw_debug_sphere(vec3 p, float radius, vec4 v_color) vec3 p2 = vec3(cos(angle2), sin(angle2), 0.0) * radius; p2 = vec3(p2[(0 + axis) % 3], p2[(1 + axis) % 3], p2[(2 + axis) % 3]); - drw_debug_line(vertid, p + p1, p + p2, pcolor); + drw_debug_line(vertid, p + p1, p + p2, pcolor, lifetime); } } } } +void drw_debug_sphere(vec3 p, float radius, vec4 v_color) +{ + drw_debug_sphere(p, radius, v_color, drw_debug_default_lifetime); +} void drw_debug_sphere(vec3 p, float radius) { drw_debug_sphere(p, radius, drw_debug_default_color); @@ -178,26 +190,26 @@ void drw_debug_sphere(vec3 p, float radius) /** * Draw a matrix transformation as 3 colored axes. */ -void drw_debug_matrix(mat4 mat, vec4 v_color) +void drw_debug_matrix(mat4 mat, uint lifetime) { vec4 p[4] = float4_array(vec4(0, 0, 0, 1), vec4(1, 0, 0, 1), vec4(0, 1, 0, 1), vec4(0, 0, 1, 1)); for (int i = 0; i < 4; i++) { p[i] = mat * p[i]; p[i].xyz /= p[i].w; } - drw_debug_line(p[0].xyz, p[0].xyz, vec4(1, 0, 0, 1)); - drw_debug_line(p[0].xyz, p[1].xyz, vec4(0, 1, 0, 1)); - drw_debug_line(p[0].xyz, p[2].xyz, vec4(0, 0, 1, 1)); + drw_debug_line(p[0].xyz, p[0].xyz, vec4(1, 0, 0, 1), lifetime); + drw_debug_line(p[0].xyz, p[1].xyz, vec4(0, 1, 0, 1), lifetime); + drw_debug_line(p[0].xyz, p[2].xyz, vec4(0, 0, 1, 1), lifetime); } void drw_debug_matrix(mat4 mat) { - drw_debug_matrix(mat, drw_debug_default_color); + drw_debug_matrix(mat, drw_debug_default_lifetime); } /** * Draw a matrix as a 2 units length bounding box, centered on origin. */ -void drw_debug_matrix_as_bbox(mat4 mat, vec4 v_color) +void drw_debug_matrix_as_bbox(mat4 mat, vec4 v_color, uint lifetime) { vec4 p[8] = float4_array(vec4(-1, -1, -1, 1), vec4(1, -1, -1, 1), @@ -211,12 +223,16 @@ void drw_debug_matrix_as_bbox(mat4 mat, vec4 v_color) p[i] = mat * p[i]; p[i].xyz /= p[i].w; } - drw_debug_quad(p[0].xyz, p[1].xyz, p[2].xyz, p[3].xyz, v_color); - drw_debug_line(p[0].xyz, p[4].xyz, v_color); - drw_debug_line(p[1].xyz, p[5].xyz, v_color); - drw_debug_line(p[2].xyz, p[6].xyz, v_color); - drw_debug_line(p[3].xyz, p[7].xyz, v_color); - drw_debug_quad(p[4].xyz, p[5].xyz, p[6].xyz, p[7].xyz, v_color); + drw_debug_quad(p[0].xyz, p[1].xyz, p[2].xyz, p[3].xyz, v_color, lifetime); + drw_debug_line(p[0].xyz, p[4].xyz, v_color, lifetime); + drw_debug_line(p[1].xyz, p[5].xyz, v_color, lifetime); + drw_debug_line(p[2].xyz, p[6].xyz, v_color, lifetime); + drw_debug_line(p[3].xyz, p[7].xyz, v_color, lifetime); + drw_debug_quad(p[4].xyz, p[5].xyz, p[6].xyz, p[7].xyz, v_color, lifetime); +} +void drw_debug_matrix_as_bbox(mat4 mat, vec4 v_color) +{ + drw_debug_matrix_as_bbox(mat, v_color, drw_debug_default_lifetime); } void drw_debug_matrix_as_bbox(mat4 mat) { diff --git a/source/blender/draw/intern/shaders/draw_debug_draw_display_frag.glsl b/source/blender/draw/intern/shaders/draw_debug_draw_display_frag.glsl index 4f9e1de194a..fe07ded0063 100644 --- a/source/blender/draw/intern/shaders/draw_debug_draw_display_frag.glsl +++ b/source/blender/draw/intern/shaders/draw_debug_draw_display_frag.glsl @@ -10,7 +10,25 @@ FRAGMENT_SHADER_CREATE_INFO(draw_debug_draw_display) +/* TODO(fclem): Deduplicate with overlay. */ +/* edge_start and edge_pos needs to be in the range [0..sizeViewport]. */ +vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos) +{ + vec2 edge = edge_start - edge_pos; + float len = length(edge); + if (len > 0.0) { + edge /= len; + vec2 perp = vec2(-edge.y, edge.x); + float dist = dot(perp, frag_co - edge_start); + /* Add 0.1 to differentiate with cleared pixels. */ + return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 1.0); + } + /* Default line if the origin is perfectly aligned with a pixel. */ + return vec4(1.0, 0.0, 0.5 + 0.1, 1.0); +} + void main() { - out_color = interp.color; + out_color = final_color; + out_line_data = pack_line_data(gl_FragCoord.xy, edge_start, edge_pos); } diff --git a/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl b/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl index 07588a43370..9ed4c44181c 100644 --- a/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl +++ b/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl @@ -12,11 +12,27 @@ VERTEX_SHADER_CREATE_INFO(draw_debug_draw_display) void main() { + int line_id = (gl_VertexID / 2); + bool is_provoking_vertex = (gl_VertexID & 1) == 0; /* Skip the first vertex containing header data. */ - DRWDebugVert vert = drw_debug_verts_buf[gl_VertexID + 2]; - vec3 pos = uintBitsToFloat(uvec3(vert.pos0, vert.pos1, vert.pos2)); + DRWDebugVertPair vert = in_debug_lines_buf[line_id + drw_debug_draw_offset]; + + vec3 pos = uintBitsToFloat((is_provoking_vertex) ? uvec3(vert.pos1_x, vert.pos1_y, vert.pos1_z) : + uvec3(vert.pos2_x, vert.pos2_y, vert.pos2_z)); vec4 col = vec4((uvec4(vert.vert_color) >> uvec4(0, 8, 16, 24)) & 0xFFu) / 255.0; - interp.color = col; + /* Lifetime management. */ + if (is_provoking_vertex && vert.lifetime > 1) { + uint vertid = atomicAdd(drw_debug_draw_v_count(out_debug_lines_buf), 2u); + if (vertid < DRW_DEBUG_DRAW_VERT_MAX) { + uint out_line_id = vertid / 2u; + vert.lifetime -= 1; + out_debug_lines_buf[out_line_id + drw_debug_draw_offset] = vert; + } + } + + final_color = col; gl_Position = persmat * vec4(pos, 1.0); + + edge_start = edge_pos = (0.5 * (gl_Position.xy / gl_Position.w) + 0.5) * size_viewport; } diff --git a/source/blender/draw/intern/shaders/draw_debug_info.hh b/source/blender/draw/intern/shaders/draw_debug_info.hh index 58e90fff905..404f22cd300 100644 --- a/source/blender/draw/intern/shaders/draw_debug_info.hh +++ b/source/blender/draw/intern/shaders/draw_debug_info.hh @@ -22,20 +22,25 @@ GPU_SHADER_CREATE_INFO(draw_debug_draw) DEFINE("DRW_DEBUG_DRAW") TYPEDEF_SOURCE("draw_shader_shared.hh") -STORAGE_BUF(DRW_DEBUG_DRAW_SLOT, READ_WRITE, DRWDebugVert, drw_debug_verts_buf[]) +STORAGE_BUF(DRW_DEBUG_DRAW_SLOT, READ_WRITE, DRWDebugVertPair, drw_debug_lines_buf[]) GPU_SHADER_CREATE_END() -GPU_SHADER_NAMED_INTERFACE_INFO(draw_debug_draw_display_iface, interp) -FLAT(VEC4, color) -GPU_SHADER_NAMED_INTERFACE_END(interp) +GPU_SHADER_INTERFACE_INFO(draw_debug_draw_display_iface) +NO_PERSPECTIVE(VEC2, edge_pos) +FLAT(VEC2, edge_start) +FLAT(VEC4, final_color) +GPU_SHADER_INTERFACE_END() GPU_SHADER_CREATE_INFO(draw_debug_draw_display) DO_STATIC_COMPILATION() TYPEDEF_SOURCE("draw_shader_shared.hh") -STORAGE_BUF(DRW_DEBUG_DRAW_SLOT, READ, DRWDebugVert, drw_debug_verts_buf[]) +STORAGE_BUF(DRW_DEBUG_DRAW_SLOT, READ, DRWDebugVertPair, in_debug_lines_buf[]) +STORAGE_BUF(DRW_DEBUG_DRAW_FEEDBACK_SLOT, READ_WRITE, DRWDebugVertPair, out_debug_lines_buf[]) VERTEX_OUT(draw_debug_draw_display_iface) FRAGMENT_OUT(0, VEC4, out_color) +FRAGMENT_OUT(1, VEC4, out_line_data) PUSH_CONSTANT(MAT4, persmat) +PUSH_CONSTANT(VEC2, size_viewport) VERTEX_SOURCE("draw_debug_draw_display_vert.glsl") FRAGMENT_SOURCE("draw_debug_draw_display_frag.glsl") GPU_SHADER_CREATE_END() diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 2a90dab0b99..0e523e6b650 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -45,6 +45,8 @@ #endif #include "dummy_backend.hh" +#include "draw_debug.hh" + #include using namespace blender::gpu; @@ -194,6 +196,9 @@ GPUContext *GPU_context_create(void *ghost_window, void *ghost_context) Context *ctx = GPUBackend::get()->context_alloc(ghost_window, ghost_context); GPU_context_active_set(wrap(ctx)); + + blender::draw::DebugDraw::get().acquire(); + return wrap(ctx); } @@ -202,6 +207,8 @@ void GPU_context_discard(GPUContext *ctx_) Context *ctx = unwrap(ctx_); BLI_assert(active_ctx == ctx); + blender::draw::DebugDraw::get().release(); + GPUBackend *backend = GPUBackend::get(); /* Flush any remaining printf while making sure we are inside render boundaries. */ backend->render_begin();