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:
committed by
Clément Foucault
parent
712e35a627
commit
890e00cecb
@@ -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
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user