DRW: DebugDraw: Revamp the module and make it global

- Make the module global and allow usage from anywhere.
- Remove the matrix API for thread safety reason
- Add lifetime management
- Make display linked to the overlays for easy toggling

## Notes
- Lifetime is in redraw. If there is 4 viewport redrawing, the lifetime decrement by 4 for each window redraw. This allows one viewport to be producer and another one being the consumer.
- Display happens at the start of overlays. Any added visuals inside of the overlays drawing functions will be displayed the next redraw.
- Redraw is not given to happen. It is only given if there is some scene / render update which tags the viewport to redraw.
- Persistent lines are not reset on file load.

Rel #137006

Pull Request: https://projects.blender.org/blender/blender/pulls/137106
This commit is contained in:
Clément Foucault
2025-04-09 21:37:23 +02:00
committed by Clément Foucault
parent 712e35a627
commit 890e00cecb
16 changed files with 465 additions and 407 deletions

View File

@@ -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
}
/** \} */

View File

@@ -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
}
/** \} */

View File

@@ -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. */

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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>("DebugDrawBuf-CPU", "DebugDrawBuf-CPU");
gpu_draw_buf_.current() = MEM_new<DebugDrawBuf>("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<float3> face_verts, float4 color)
void drw_debug_polygon(Span<float3> 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<float3> 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<float3> 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<float3> 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<float3> 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<uint32_t *>(&pos.x);
vert.pos1 = *reinterpret_cast<uint32_t *>(&pos.y);
vert.pos2 = *reinterpret_cast<uint32_t *>(&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<blender::draw::DebugDraw *>(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<blender::draw::DebugDraw *>(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<DRWDebugModule *>(new blender::draw::DebugDraw());
}
reinterpret_cast<blender::draw::DebugDraw *>(drw_get().debug)->init();
#endif
}
void drw_debug_module_free(DRWDebugModule *module)
{
if (module != nullptr) {
delete reinterpret_cast<blender::draw::DebugDraw *>(module);
}
}
GPUStorageBuf *drw_debug_gpu_draw_buf_get()
{
#ifdef WITH_DRAW_DEBUG
return reinterpret_cast<blender::draw::DebugDraw *>(drw_get().debug)->gpu_draw_buf_get();
#endif
return nullptr;
}
/** \} */

View File

@@ -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<float3> 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<DRWDebugDrawBuffer>;
/**
* Ensure thread-safety when adding geometry to the CPU debug buffer.
* GPU debug buffer currently expects draw submission to be externally synchronized.
*/
std::atomic<int> vertex_len_;
/** Data buffers containing all verts or chars to draw. */
DebugDrawBuf cpu_draw_buf_ = {"DebugDrawBuf-CPU"};
DebugDrawBuf gpu_draw_buf_ = {"DebugDrawBuf-GPU"};
SwapChain<DebugDrawBuf *, 2> cpu_draw_buf_ = {};
SwapChain<DebugDrawBuf *, 2> 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<float3> sphere_verts_;
Vector<float3> 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<float3> 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();

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
/** \} */

View File

@@ -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<ViewCullingData>(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");

View File

@@ -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)
{

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -45,6 +45,8 @@
#endif
#include "dummy_backend.hh"
#include "draw_debug.hh"
#include <mutex>
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();