DRW: DebugDraw: Port module to C++ and add GPU capabilities
This is a complete rewrite of the draw debug drawing module in C++. It uses `GPUStorageBuf` to store the data to be drawn and use indirect drawing. This makes it easier to do a mirror API for GPU shaders. The C++ API class is exposed through `draw_debug.hh` and should be used when possible in new code. However, the debug drawing will not work for platform not yet supporting `GPUStorageBuf`. Also keep in mind that this module must only be used in debug build for performance and compatibility reasons.
This commit is contained in:
@@ -83,7 +83,7 @@ set(SRC
|
||||
intern/draw_color_management.cc
|
||||
intern/draw_common.c
|
||||
intern/draw_curves.cc
|
||||
intern/draw_debug.c
|
||||
intern/draw_debug.cc
|
||||
intern/draw_fluid.c
|
||||
intern/draw_hair.cc
|
||||
intern/draw_instance_data.c
|
||||
@@ -214,6 +214,7 @@ set(SRC
|
||||
intern/draw_common_shader_shared.h
|
||||
intern/draw_curves_private.h
|
||||
intern/draw_debug.h
|
||||
intern/draw_debug.hh
|
||||
intern/draw_hair_private.h
|
||||
intern/draw_instance_data.h
|
||||
intern/draw_manager.h
|
||||
@@ -434,20 +435,19 @@ set(GLSL_SRC
|
||||
|
||||
intern/shaders/common_attribute_lib.glsl
|
||||
intern/shaders/common_colormanagement_lib.glsl
|
||||
intern/shaders/common_debug_draw_lib.glsl
|
||||
intern/shaders/common_debug_print_lib.glsl
|
||||
intern/shaders/common_fullscreen_vert.glsl
|
||||
intern/shaders/common_fxaa_lib.glsl
|
||||
intern/shaders/common_globals_lib.glsl
|
||||
intern/shaders/common_gpencil_lib.glsl
|
||||
intern/shaders/common_pointcloud_lib.glsl
|
||||
intern/shaders/common_hair_lib.glsl
|
||||
intern/shaders/common_hair_refine_vert.glsl
|
||||
intern/shaders/common_hair_refine_comp.glsl
|
||||
intern/shaders/common_math_lib.glsl
|
||||
intern/shaders/common_hair_refine_vert.glsl
|
||||
intern/shaders/common_math_geom_lib.glsl
|
||||
intern/shaders/common_view_clipping_lib.glsl
|
||||
intern/shaders/common_view_lib.glsl
|
||||
intern/shaders/common_fxaa_lib.glsl
|
||||
intern/shaders/common_math_lib.glsl
|
||||
intern/shaders/common_pointcloud_lib.glsl
|
||||
intern/shaders/common_smaa_lib.glsl
|
||||
intern/shaders/common_fullscreen_vert.glsl
|
||||
|
||||
intern/shaders/common_subdiv_custom_data_interp_comp.glsl
|
||||
intern/shaders/common_subdiv_ibo_lines_comp.glsl
|
||||
intern/shaders/common_subdiv_ibo_tris_comp.glsl
|
||||
@@ -460,6 +460,13 @@ set(GLSL_SRC
|
||||
intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
|
||||
intern/shaders/common_subdiv_vbo_lnor_comp.glsl
|
||||
intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
|
||||
intern/shaders/common_view_clipping_lib.glsl
|
||||
intern/shaders/common_view_lib.glsl
|
||||
intern/shaders/draw_debug_draw_display_frag.glsl
|
||||
intern/shaders/draw_debug_draw_display_vert.glsl
|
||||
intern/shaders/draw_debug_info.hh
|
||||
intern/shaders/draw_debug_print_display_frag.glsl
|
||||
intern/shaders/draw_debug_print_display_vert.glsl
|
||||
|
||||
intern/draw_common_shader_shared.h
|
||||
intern/draw_shader_shared.h
|
||||
|
||||
@@ -357,7 +357,7 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
|
||||
mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
|
||||
|
||||
#ifdef DEBUG_CSM
|
||||
DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true);
|
||||
DRW_debug_m4_as_bbox(viewprojmat, true, dbg_col);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2018 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*
|
||||
* \brief Simple API to draw debug shapes in the viewport.
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_link_utils.h"
|
||||
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_matrix.h"
|
||||
|
||||
#include "draw_debug.h"
|
||||
#include "draw_manager.h"
|
||||
|
||||
/* --------- Register --------- */
|
||||
|
||||
/* Matrix applied to all points before drawing. Could be a stack if needed. */
|
||||
static float g_modelmat[4][4];
|
||||
|
||||
void DRW_debug_modelmat_reset(void)
|
||||
{
|
||||
unit_m4(g_modelmat);
|
||||
}
|
||||
|
||||
void DRW_debug_modelmat(const float modelmat[4][4])
|
||||
{
|
||||
copy_m4_m4(g_modelmat, modelmat);
|
||||
}
|
||||
|
||||
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4])
|
||||
{
|
||||
DRWDebugLine *line = MEM_mallocN(sizeof(DRWDebugLine), "DRWDebugLine");
|
||||
mul_v3_m4v3(line->pos[0], g_modelmat, v1);
|
||||
mul_v3_m4v3(line->pos[1], g_modelmat, v2);
|
||||
copy_v4_v4(line->color, color);
|
||||
BLI_LINKS_PREPEND(DST.debug.lines, line);
|
||||
}
|
||||
|
||||
void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4])
|
||||
{
|
||||
BLI_assert(vert_len > 1);
|
||||
|
||||
for (int i = 0; i < vert_len; i++) {
|
||||
DRW_debug_line_v3v3(v[i], v[(i + 1) % vert_len], color);
|
||||
}
|
||||
}
|
||||
|
||||
void DRW_debug_m4(const float m[4][4])
|
||||
{
|
||||
float v0[3] = {0.0f, 0.0f, 0.0f};
|
||||
float v1[3] = {1.0f, 0.0f, 0.0f};
|
||||
float v2[3] = {0.0f, 1.0f, 0.0f};
|
||||
float v3[3] = {0.0f, 0.0f, 1.0f};
|
||||
|
||||
mul_m4_v3(m, v0);
|
||||
mul_m4_v3(m, v1);
|
||||
mul_m4_v3(m, v2);
|
||||
mul_m4_v3(m, v3);
|
||||
|
||||
DRW_debug_line_v3v3(v0, v1, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
|
||||
DRW_debug_line_v3v3(v0, v2, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
|
||||
DRW_debug_line_v3v3(v0, v3, (float[4]){0.0f, 0.0f, 1.0f, 1.0f});
|
||||
}
|
||||
|
||||
void DRW_debug_bbox(const BoundBox *bbox, const float color[4])
|
||||
{
|
||||
DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[1], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[2], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[3], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[0], color);
|
||||
|
||||
DRW_debug_line_v3v3(bbox->vec[4], bbox->vec[5], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[5], bbox->vec[6], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[6], bbox->vec[7], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[7], bbox->vec[4], color);
|
||||
|
||||
DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[4], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[5], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[6], color);
|
||||
DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[7], color);
|
||||
}
|
||||
|
||||
void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert)
|
||||
{
|
||||
BoundBox bb;
|
||||
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
|
||||
float project_matrix[4][4];
|
||||
if (invert) {
|
||||
invert_m4_m4(project_matrix, m);
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(project_matrix, m);
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(&bb, min, max);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mul_project_m4_v3(project_matrix, bb.vec[i]);
|
||||
}
|
||||
DRW_debug_bbox(&bb, color);
|
||||
}
|
||||
|
||||
void DRW_debug_sphere(const float center[3], const float radius, const float color[4])
|
||||
{
|
||||
float size_mat[4][4];
|
||||
DRWDebugSphere *sphere = MEM_mallocN(sizeof(DRWDebugSphere), "DRWDebugSphere");
|
||||
/* Bake all transform into a Matrix4 */
|
||||
scale_m4_fl(size_mat, radius);
|
||||
copy_m4_m4(sphere->mat, g_modelmat);
|
||||
translate_m4(sphere->mat, center[0], center[1], center[2]);
|
||||
mul_m4_m4m4(sphere->mat, sphere->mat, size_mat);
|
||||
|
||||
copy_v4_v4(sphere->color, color);
|
||||
BLI_LINKS_PREPEND(DST.debug.spheres, sphere);
|
||||
}
|
||||
|
||||
/* --------- Render --------- */
|
||||
|
||||
static void drw_debug_draw_lines(void)
|
||||
{
|
||||
int count = BLI_linklist_count((LinkNode *)DST.debug.lines);
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUVertFormat *vert_format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
uint col = GPU_vertformat_attr_add(vert_format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, count * 2);
|
||||
|
||||
while (DST.debug.lines) {
|
||||
void *next = DST.debug.lines->next;
|
||||
|
||||
immAttr4fv(col, DST.debug.lines->color);
|
||||
immVertex3fv(pos, DST.debug.lines->pos[0]);
|
||||
|
||||
immAttr4fv(col, DST.debug.lines->color);
|
||||
immVertex3fv(pos, DST.debug.lines->pos[1]);
|
||||
|
||||
MEM_freeN(DST.debug.lines);
|
||||
DST.debug.lines = next;
|
||||
}
|
||||
immEnd();
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
static void drw_debug_draw_spheres(void)
|
||||
{
|
||||
int count = BLI_linklist_count((LinkNode *)DST.debug.spheres);
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float persmat[4][4];
|
||||
DRW_view_persmat_get(NULL, persmat, false);
|
||||
|
||||
GPUBatch *empty_sphere = DRW_cache_empty_sphere_get();
|
||||
GPU_batch_program_set_builtin(empty_sphere, GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
while (DST.debug.spheres) {
|
||||
void *next = DST.debug.spheres->next;
|
||||
float MVP[4][4];
|
||||
|
||||
mul_m4_m4m4(MVP, persmat, DST.debug.spheres->mat);
|
||||
GPU_batch_uniform_mat4(empty_sphere, "ModelViewProjectionMatrix", MVP);
|
||||
GPU_batch_uniform_4fv(empty_sphere, "color", DST.debug.spheres->color);
|
||||
GPU_batch_draw(empty_sphere);
|
||||
|
||||
MEM_freeN(DST.debug.spheres);
|
||||
DST.debug.spheres = next;
|
||||
}
|
||||
}
|
||||
|
||||
void drw_debug_draw(void)
|
||||
{
|
||||
drw_debug_draw_lines();
|
||||
drw_debug_draw_spheres();
|
||||
}
|
||||
|
||||
void drw_debug_init(void)
|
||||
{
|
||||
DRW_debug_modelmat_reset();
|
||||
}
|
||||
719
source/blender/draw/intern/draw_debug.cc
Normal file
719
source/blender/draw/intern/draw_debug.cc
Normal file
@@ -0,0 +1,719 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2018 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*
|
||||
* \brief Simple API to draw debug shapes in the viewport.
|
||||
*/
|
||||
|
||||
#include "BKE_object.h"
|
||||
#include "BLI_link_utils.h"
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_debug.h"
|
||||
|
||||
#include "draw_debug.h"
|
||||
#include "draw_debug.hh"
|
||||
#include "draw_manager.h"
|
||||
#include "draw_shader.h"
|
||||
#include "draw_shader_shared.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
namespace blender::draw {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Init and state
|
||||
* \{ */
|
||||
|
||||
DebugDraw::DebugDraw()
|
||||
{
|
||||
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);
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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_print_buf_.command.v_count = 0;
|
||||
cpu_print_buf_.command.v_first = 0;
|
||||
cpu_print_buf_.command.i_count = 1;
|
||||
cpu_print_buf_.command.i_first = 0;
|
||||
|
||||
cpu_draw_buf_.command.v_count = 0;
|
||||
cpu_draw_buf_.command.v_first = 0;
|
||||
cpu_draw_buf_.command.i_count = 1;
|
||||
cpu_draw_buf_.command.i_first = 0;
|
||||
|
||||
gpu_print_buf_.command.v_count = 0;
|
||||
gpu_print_buf_.command.v_first = 0;
|
||||
gpu_print_buf_.command.i_count = 1;
|
||||
gpu_print_buf_.command.i_first = 0;
|
||||
gpu_print_buf_used = false;
|
||||
|
||||
gpu_draw_buf_.command.v_count = 0;
|
||||
gpu_draw_buf_.command.v_first = 0;
|
||||
gpu_draw_buf_.command.i_count = 1;
|
||||
gpu_draw_buf_.command.i_first = 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_ = modelmat;
|
||||
}
|
||||
|
||||
GPUStorageBuf *DebugDraw::gpu_draw_buf_get()
|
||||
{
|
||||
BLI_assert(GPU_shader_storage_buffer_objects_support());
|
||||
if (!gpu_draw_buf_used) {
|
||||
gpu_draw_buf_used = true;
|
||||
gpu_draw_buf_.push_update();
|
||||
}
|
||||
return gpu_draw_buf_;
|
||||
}
|
||||
|
||||
GPUStorageBuf *DebugDraw::gpu_print_buf_get()
|
||||
{
|
||||
BLI_assert(GPU_shader_storage_buffer_objects_support());
|
||||
if (!gpu_print_buf_used) {
|
||||
gpu_print_buf_used = true;
|
||||
gpu_print_buf_.push_update();
|
||||
}
|
||||
return gpu_print_buf_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Draw functions
|
||||
* \{ */
|
||||
|
||||
void DebugDraw::draw_line(float3 v1, float3 v2, float4 color)
|
||||
{
|
||||
draw_line(v1, v2, color_pack(color));
|
||||
}
|
||||
|
||||
void DebugDraw::draw_polygon(Span<float3> poly_verts, float4 color)
|
||||
{
|
||||
BLI_assert(!poly_verts.is_empty());
|
||||
|
||||
uint col = color_pack(color);
|
||||
float3 v0 = model_mat_ * poly_verts.last();
|
||||
for (auto vert : poly_verts) {
|
||||
float3 v1 = model_mat_ * vert;
|
||||
draw_line(v0, v1, col);
|
||||
v0 = v1;
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::draw_matrix(const float4x4 m4)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void DebugDraw::draw_bbox(const BoundBox &bbox, const float4 color)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void DebugDraw::draw_matrix_as_bbox(float4x4 mat, const float4 color)
|
||||
{
|
||||
BoundBox bb;
|
||||
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
|
||||
BKE_boundbox_init_from_minmax(&bb, min, max);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Print functions
|
||||
* \{ */
|
||||
|
||||
template<> void DebugDraw::print_value<uint>(const uint &value)
|
||||
{
|
||||
print_value_uint(value, false, false, true);
|
||||
}
|
||||
template<> void DebugDraw::print_value<int>(const int &value)
|
||||
{
|
||||
print_value_uint(uint(abs(value)), false, (value < 0), false);
|
||||
}
|
||||
template<> void DebugDraw::print_value<bool>(const bool &value)
|
||||
{
|
||||
print_string(value ? "true " : "false");
|
||||
}
|
||||
template<> void DebugDraw::print_value<float>(const float &val)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setw(12) << std::to_string(val);
|
||||
print_string(ss.str());
|
||||
}
|
||||
template<> void DebugDraw::print_value<double>(const double &val)
|
||||
{
|
||||
print_value(float(val));
|
||||
}
|
||||
|
||||
template<> void DebugDraw::print_value_hex<uint>(const uint &value)
|
||||
{
|
||||
print_value_uint(value, true, false, false);
|
||||
}
|
||||
template<> void DebugDraw::print_value_hex<int>(const int &value)
|
||||
{
|
||||
print_value_uint(uint(value), true, false, false);
|
||||
}
|
||||
template<> void DebugDraw::print_value_hex<float>(const float &value)
|
||||
{
|
||||
print_value_uint(*reinterpret_cast<const uint *>(&value), true, false, false);
|
||||
}
|
||||
template<> void DebugDraw::print_value_hex<double>(const double &val)
|
||||
{
|
||||
print_value_hex(float(val));
|
||||
}
|
||||
|
||||
template<> void DebugDraw::print_value_binary<uint>(const uint &value)
|
||||
{
|
||||
print_value_binary(value);
|
||||
}
|
||||
template<> void DebugDraw::print_value_binary<int>(const int &value)
|
||||
{
|
||||
print_value_binary(uint(value));
|
||||
}
|
||||
template<> void DebugDraw::print_value_binary<float>(const float &value)
|
||||
{
|
||||
print_value_binary(*reinterpret_cast<const uint *>(&value));
|
||||
}
|
||||
template<> void DebugDraw::print_value_binary<double>(const double &val)
|
||||
{
|
||||
print_value_binary(float(val));
|
||||
}
|
||||
|
||||
template<> void DebugDraw::print_value<float2>(const float2 &value)
|
||||
{
|
||||
print_no_endl("float2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<float3>(const float3 &value)
|
||||
{
|
||||
print_no_endl("float3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<float4>(const float4 &value)
|
||||
{
|
||||
print_no_endl("float4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
template<> void DebugDraw::print_value<int2>(const int2 &value)
|
||||
{
|
||||
print_no_endl("int2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<int3>(const int3 &value)
|
||||
{
|
||||
print_no_endl("int3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<int4>(const int4 &value)
|
||||
{
|
||||
print_no_endl("int4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
template<> void DebugDraw::print_value<uint2>(const uint2 &value)
|
||||
{
|
||||
print_no_endl("uint2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<uint3>(const uint3 &value)
|
||||
{
|
||||
print_no_endl("uint3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
template<> void DebugDraw::print_value<uint4>(const uint4 &value)
|
||||
{
|
||||
print_no_endl("uint4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internals
|
||||
*
|
||||
* IMPORTANT: All of these are copied from the shader libs (common_debug_draw_lib.glsl &
|
||||
* common_debug_print_lib.glsl). They need to be kept in sync to write the same data.
|
||||
* \{ */
|
||||
|
||||
void DebugDraw::draw_line(float3 v1, float3 v2, uint color)
|
||||
{
|
||||
DebugDrawBuf &buf = cpu_draw_buf_;
|
||||
uint index = buf.command.v_count;
|
||||
if (index + 2 < DRW_DEBUG_DRAW_VERT_MAX) {
|
||||
buf.verts[index + 0] = vert_pack(model_mat_ * v1, color);
|
||||
buf.verts[index + 1] = vert_pack(model_mat_ * v2, color);
|
||||
buf.command.v_count += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep in sync with drw_debug_color_pack(). */
|
||||
uint DebugDraw::color_pack(float4 color)
|
||||
{
|
||||
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.color = color;
|
||||
return vert;
|
||||
}
|
||||
|
||||
void DebugDraw::print_newline()
|
||||
{
|
||||
print_col_ = 0u;
|
||||
print_row_ = ++cpu_print_buf_.command.i_first;
|
||||
}
|
||||
|
||||
void DebugDraw::print_string_start(uint len)
|
||||
{
|
||||
/* Break before word. */
|
||||
if (print_col_ + len > DRW_DEBUG_PRINT_WORD_WRAP_COLUMN) {
|
||||
print_newline();
|
||||
}
|
||||
}
|
||||
|
||||
/* Copied from gpu_shader_dependency. */
|
||||
void DebugDraw::print_string(std::string str)
|
||||
{
|
||||
size_t len_before_pad = str.length();
|
||||
/* Pad string to uint size to avoid out of bound reads. */
|
||||
while (str.length() % 4 != 0) {
|
||||
str += " ";
|
||||
}
|
||||
|
||||
print_string_start(len_before_pad);
|
||||
for (size_t i = 0; i < len_before_pad; i += 4) {
|
||||
union {
|
||||
uint8_t chars[4];
|
||||
uint32_t word;
|
||||
};
|
||||
|
||||
chars[0] = *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 0);
|
||||
chars[1] = *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 1);
|
||||
chars[2] = *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 2);
|
||||
chars[3] = *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 3);
|
||||
|
||||
if (i + 4 > len_before_pad) {
|
||||
chars[len_before_pad - i] = '\0';
|
||||
}
|
||||
print_char4(word);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep in sync with shader. */
|
||||
void DebugDraw::print_char4(uint data)
|
||||
{
|
||||
/* Convert into char stream. */
|
||||
for (; data != 0u; data >>= 8u) {
|
||||
uint char1 = data & 0xFFu;
|
||||
/* Check for null terminator. */
|
||||
if (char1 == 0x00) {
|
||||
break;
|
||||
}
|
||||
/* NOTE: Do not skip the header manually like in GPU. */
|
||||
uint cursor = cpu_print_buf_.command.v_count++;
|
||||
if (cursor < DRW_DEBUG_PRINT_MAX) {
|
||||
/* For future usage. (i.e: Color) */
|
||||
uint flags = 0u;
|
||||
uint col = print_col_++;
|
||||
uint print_header = (flags << 24u) | (print_row_ << 16u) | (col << 8u);
|
||||
cpu_print_buf_.char_array[cursor] = print_header | char1;
|
||||
/* Break word. */
|
||||
if (print_col_ > DRW_DEBUG_PRINT_WORD_WRAP_COLUMN) {
|
||||
print_newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::print_append_char(uint char1, uint &char4)
|
||||
{
|
||||
char4 = (char4 << 8u) | char1;
|
||||
}
|
||||
|
||||
void DebugDraw::print_append_digit(uint digit, uint &char4)
|
||||
{
|
||||
const uint char_A = 0x41u;
|
||||
const uint char_0 = 0x30u;
|
||||
bool is_hexadecimal = digit > 9u;
|
||||
char4 = (char4 << 8u) | (is_hexadecimal ? (char_A + digit - 10u) : (char_0 + digit));
|
||||
}
|
||||
|
||||
void DebugDraw::print_append_space(uint &char4)
|
||||
{
|
||||
char4 = (char4 << 8u) | 0x20u;
|
||||
}
|
||||
|
||||
void DebugDraw::print_value_binary(uint value)
|
||||
{
|
||||
print_string("0b");
|
||||
print_string_start(10u * 4u);
|
||||
uint digits[10] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
|
||||
uint digit = 0u;
|
||||
for (uint i = 0u; i < 32u; i++) {
|
||||
print_append_digit(((value >> i) & 1u), digits[digit / 4u]);
|
||||
digit++;
|
||||
if ((i % 4u) == 3u) {
|
||||
print_append_space(digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
}
|
||||
/* Numbers are written from right to left. So we need to reverse the order. */
|
||||
for (int j = 9; j >= 0; j--) {
|
||||
print_char4(digits[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::print_value_uint(uint value,
|
||||
const bool hex,
|
||||
bool is_negative,
|
||||
const bool is_unsigned)
|
||||
{
|
||||
print_string_start(3u * 4u);
|
||||
const uint blank_value = hex ? 0x30303030u : 0x20202020u;
|
||||
const uint prefix = hex ? 0x78302020u : 0x20202020u;
|
||||
uint digits[3] = {blank_value, blank_value, prefix};
|
||||
const uint base = hex ? 16u : 10u;
|
||||
uint digit = 0u;
|
||||
/* Add `u` suffix. */
|
||||
if (is_unsigned) {
|
||||
print_append_char('u', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Number's digits. */
|
||||
for (; value != 0u || digit == uint(is_unsigned); value /= base) {
|
||||
print_append_digit(value % base, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Add negative sign. */
|
||||
if (is_negative) {
|
||||
print_append_char('-', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Need to pad to uint alignment because we are issuing chars in "reverse". */
|
||||
for (uint i = digit % 4u; i < 4u && i > 0u; i++) {
|
||||
print_append_space(digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Numbers are written from right to left. So we need to reverse the order. */
|
||||
for (int j = 2; j >= 0; j--) {
|
||||
print_char4(digits[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Display
|
||||
* \{ */
|
||||
|
||||
void DebugDraw::display_lines()
|
||||
{
|
||||
if (cpu_draw_buf_.command.v_count == 0 && gpu_draw_buf_used == false) {
|
||||
return;
|
||||
}
|
||||
GPU_debug_group_begin("Lines");
|
||||
cpu_draw_buf_.push_update();
|
||||
|
||||
float4x4 persmat;
|
||||
const DRWView *view = DRW_view_get_active();
|
||||
DRW_view_persmat_get(view, persmat.ptr(), false);
|
||||
|
||||
drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
||||
|
||||
GPUBatch *batch = drw_cache_procedural_lines_get();
|
||||
GPUShader *shader = DRW_shader_debug_draw_display_get();
|
||||
GPU_batch_set_shader(batch, shader);
|
||||
int slot = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS);
|
||||
GPU_shader_uniform_mat4(shader, "persmat", persmat.ptr());
|
||||
|
||||
if (gpu_draw_buf_used) {
|
||||
GPU_debug_group_begin("GPU");
|
||||
GPU_storagebuf_bind(gpu_draw_buf_, slot);
|
||||
GPU_batch_draw_indirect(batch, gpu_draw_buf_);
|
||||
GPU_storagebuf_unbind(gpu_draw_buf_);
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
GPU_debug_group_begin("CPU");
|
||||
GPU_storagebuf_bind(cpu_draw_buf_, slot);
|
||||
GPU_batch_draw_indirect(batch, cpu_draw_buf_);
|
||||
GPU_storagebuf_unbind(cpu_draw_buf_);
|
||||
GPU_debug_group_end();
|
||||
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
void DebugDraw::display_prints()
|
||||
{
|
||||
if (cpu_print_buf_.command.v_count == 0 && gpu_print_buf_used == false) {
|
||||
return;
|
||||
}
|
||||
GPU_debug_group_begin("Prints");
|
||||
cpu_print_buf_.push_update();
|
||||
|
||||
drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_PROGRAM_POINT_SIZE);
|
||||
|
||||
GPUBatch *batch = drw_cache_procedural_points_get();
|
||||
GPUShader *shader = DRW_shader_debug_print_display_get();
|
||||
GPU_batch_set_shader(batch, shader);
|
||||
int slot = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT);
|
||||
|
||||
if (gpu_print_buf_used) {
|
||||
GPU_debug_group_begin("GPU");
|
||||
GPU_storagebuf_bind(gpu_print_buf_, slot);
|
||||
GPU_batch_draw_indirect(batch, gpu_print_buf_);
|
||||
GPU_storagebuf_unbind(gpu_print_buf_);
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
GPU_debug_group_begin("CPU");
|
||||
GPU_storagebuf_bind(cpu_print_buf_, slot);
|
||||
GPU_batch_draw_indirect(batch, cpu_print_buf_);
|
||||
GPU_storagebuf_unbind(cpu_print_buf_);
|
||||
GPU_debug_group_end();
|
||||
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
void DebugDraw::display_to_view()
|
||||
{
|
||||
GPU_debug_group_begin("DebugDraw");
|
||||
|
||||
display_lines();
|
||||
/* Print 3D shapes before text to avoid overlaps. */
|
||||
display_prints();
|
||||
/* Init again so we don't draw the same thing twice. */
|
||||
init();
|
||||
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
} // namespace blender::draw
|
||||
|
||||
blender::draw::DebugDraw *DRW_debug_get()
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<blender::draw::DebugDraw *>(DST.debug);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name C-API private
|
||||
* \{ */
|
||||
|
||||
void drw_debug_draw()
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
/* TODO(fclem): Convenience for now. Will have to move to DRWManager. */
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->display_to_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Init is once per draw manager cycle.
|
||||
*/
|
||||
void drw_debug_init()
|
||||
{
|
||||
/* Module should not be used in release builds. */
|
||||
/* TODO(fclem): Hide the functions declarations without using ifdefs everywhere. */
|
||||
#ifdef DEBUG
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
/* TODO(fclem): Convenience for now. Will have to move to DRWManager. */
|
||||
if (DST.debug == nullptr) {
|
||||
DST.debug = reinterpret_cast<DRWDebugModule *>(new blender::draw::DebugDraw());
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void drw_debug_module_free(DRWDebugModule *module)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
if (module != nullptr) {
|
||||
delete reinterpret_cast<blender::draw::DebugDraw *>(module);
|
||||
}
|
||||
}
|
||||
|
||||
GPUStorageBuf *drw_debug_gpu_draw_buf_get()
|
||||
{
|
||||
return reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->gpu_draw_buf_get();
|
||||
}
|
||||
|
||||
GPUStorageBuf *drw_debug_gpu_print_buf_get()
|
||||
{
|
||||
return reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->gpu_print_buf_get();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name C-API public
|
||||
* \{ */
|
||||
|
||||
void DRW_debug_modelmat_reset()
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->modelmat_reset();
|
||||
}
|
||||
|
||||
void DRW_debug_modelmat(const float modelmat[4][4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->modelmat_set(modelmat);
|
||||
}
|
||||
|
||||
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_line(v1, v2, color);
|
||||
}
|
||||
|
||||
void DRW_debug_polygon_v3(const float (*v)[3], int vert_len, const float color[4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_polygon(
|
||||
blender::Span<float3>((float3 *)v, vert_len), color);
|
||||
}
|
||||
|
||||
void DRW_debug_m4(const float m[4][4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_matrix(m);
|
||||
}
|
||||
|
||||
void DRW_debug_m4_as_bbox(const float m[4][4], bool invert, const float color[4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
blender::float4x4 m4 = m;
|
||||
if (invert) {
|
||||
m4 = m4.inverted();
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_matrix_as_bbox(m4, color);
|
||||
}
|
||||
|
||||
void DRW_debug_bbox(const BoundBox *bbox, const float color[4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_bbox(*bbox, color);
|
||||
}
|
||||
|
||||
void DRW_debug_sphere(const float center[3], float radius, const float color[4])
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_sphere(center, radius, color);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -3,21 +3,38 @@
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*
|
||||
* \brief Simple API to draw debug shapes in the viewport.
|
||||
* IMPORTANT: This is the legacy API for C. Use draw_debug.hh instead in new C++ code.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DRWDebugModule DRWDebugModule;
|
||||
|
||||
struct BoundBox;
|
||||
|
||||
void DRW_debug_modelmat_reset(void);
|
||||
void DRW_debug_modelmat(const float modelmat[4][4]);
|
||||
|
||||
/**
|
||||
* IMPORTANT: For now there is a limit of DRW_DEBUG_DRAW_VERT_MAX that can be drawn
|
||||
* using all the draw functions.
|
||||
*/
|
||||
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
|
||||
void DRW_debug_polygon_v3(const float (*v)[3], int vert_len, const float color[4]);
|
||||
/**
|
||||
* \note g_modelmat is still applied on top.
|
||||
*/
|
||||
void DRW_debug_m4(const float m[4][4]);
|
||||
void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], bool invert);
|
||||
void DRW_debug_m4_as_bbox(const float m[4][4], bool invert, const float color[4]);
|
||||
void DRW_debug_bbox(const BoundBox *bbox, const float color[4]);
|
||||
void DRW_debug_sphere(const float center[3], float radius, const float color[4]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
198
source/blender/draw/intern/draw_debug.hh
Normal file
198
source/blender/draw/intern/draw_debug.hh
Normal file
@@ -0,0 +1,198 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*
|
||||
* \brief Simple API to draw debug shapes and log in the viewport.
|
||||
*
|
||||
* Both CPU and GPU implementation are supported and symmetrical (meaning GPU shader can use it
|
||||
* too, see common_debug_print/draw_lib.glsl).
|
||||
*
|
||||
* NOTE: CPU logging will overlap GPU logging on screen as it is drawn after.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
|
||||
namespace blender::draw {
|
||||
|
||||
/* 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__)
|
||||
#define drw_print(...) DRW_debug_get()->print(__VA_ARGS__)
|
||||
#define drw_print_hex(...) DRW_debug_get()->print_hex(__VA_ARGS__)
|
||||
#define drw_print_binary(...) DRW_debug_get()->print_binary(__VA_ARGS__)
|
||||
#define drw_print_no_endl(...) DRW_debug_get()->print_no_endl(__VA_ARGS__)
|
||||
|
||||
/* Will log variable along with its name, like the shader version of print(). */
|
||||
#define drw_print_id(v_) DRW_debug_get()->print(#v_, "= ", v_)
|
||||
#define drw_print_id_no_endl(v_) DRW_debug_get()->print_no_endl(#v_, "= ", v_)
|
||||
|
||||
class DebugDraw {
|
||||
private:
|
||||
using DebugDrawBuf = StorageBuffer<DRWDebugDrawBuffer>;
|
||||
using DebugPrintBuf = StorageBuffer<DRWDebugPrintBuffer>;
|
||||
|
||||
/** Data buffers containing all verts or chars to draw. */
|
||||
DebugDrawBuf cpu_draw_buf_ = {"DebugDrawBuf-CPU"};
|
||||
DebugDrawBuf gpu_draw_buf_ = {"DebugDrawBuf-GPU"};
|
||||
DebugPrintBuf cpu_print_buf_ = {"DebugPrintBuf-CPU"};
|
||||
DebugPrintBuf gpu_print_buf_ = {"DebugPrintBuf-GPU"};
|
||||
/** True if the gpu buffer have been requested and may contain data to draw. */
|
||||
bool gpu_print_buf_used = false;
|
||||
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_;
|
||||
/** Cursor position for print functionality. */
|
||||
uint print_col_ = 0;
|
||||
uint print_row_ = 0;
|
||||
|
||||
public:
|
||||
DebugDraw();
|
||||
~DebugDraw(){};
|
||||
|
||||
/**
|
||||
* 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> poly_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(float4x4 mat, const float4 color = {1, 0, 0, 1});
|
||||
|
||||
/**
|
||||
* Will draw all debug shapes and text cached up until now to the current view / framebuffer.
|
||||
* Draw buffers will be emptied and ready for new debug data.
|
||||
*/
|
||||
void display_to_view();
|
||||
|
||||
/**
|
||||
* Log variable or strings inside the viewport.
|
||||
* Using a unique non string argument will print the variable name with it.
|
||||
* Concatenate by using multiple arguments. i.e: `print("Looped ", n, "times.")`.
|
||||
*/
|
||||
template<typename... Ts> void print(StringRefNull str, Ts... args)
|
||||
{
|
||||
print_no_endl(str, args...);
|
||||
print_newline();
|
||||
}
|
||||
template<typename T> void print(const T &&value)
|
||||
{
|
||||
print_value(value);
|
||||
print_newline();
|
||||
}
|
||||
template<typename T> void print_hex(const T &&value)
|
||||
{
|
||||
print_value_hex(value);
|
||||
print_newline();
|
||||
}
|
||||
template<typename T> void print_binary(const T &&value)
|
||||
{
|
||||
print_value_binary(value);
|
||||
print_newline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `print()` but does not finish the line.
|
||||
*/
|
||||
void print_no_endl(std::string arg)
|
||||
{
|
||||
print_string(arg);
|
||||
}
|
||||
void print_no_endl(StringRef arg)
|
||||
{
|
||||
print_string(arg);
|
||||
}
|
||||
void print_no_endl(StringRefNull arg)
|
||||
{
|
||||
print_string(arg);
|
||||
}
|
||||
void print_no_endl(char const *arg)
|
||||
{
|
||||
print_string(StringRefNull(arg));
|
||||
}
|
||||
template<typename T> void print_no_endl(T arg)
|
||||
{
|
||||
print_value(arg);
|
||||
}
|
||||
template<typename T, typename... Ts> void print_no_endl(T arg, Ts... args)
|
||||
{
|
||||
print_no_endl(arg);
|
||||
print_no_endl(args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not to be called by user. Should become private.
|
||||
*/
|
||||
GPUStorageBuf *gpu_draw_buf_get();
|
||||
GPUStorageBuf *gpu_print_buf_get();
|
||||
|
||||
private:
|
||||
uint color_pack(float4 color);
|
||||
DRWDebugVert vert_pack(float3 pos, uint color);
|
||||
|
||||
void draw_line(float3 v1, float3 v2, uint color);
|
||||
|
||||
void print_newline();
|
||||
void print_string_start(uint len);
|
||||
void print_string(std::string str);
|
||||
void print_char4(uint data);
|
||||
void print_append_char(uint char1, uint &char4);
|
||||
void print_append_digit(uint digit, uint &char4);
|
||||
void print_append_space(uint &char4);
|
||||
void print_value_binary(uint value);
|
||||
void print_value_uint(uint value, const bool hex, bool is_negative, const bool is_unsigned);
|
||||
|
||||
template<typename T> void print_value(const T &value);
|
||||
template<typename T> void print_value_hex(const T &value);
|
||||
template<typename T> void print_value_binary(const T &value);
|
||||
|
||||
void display_lines();
|
||||
void display_prints();
|
||||
};
|
||||
|
||||
} // namespace blender::draw
|
||||
|
||||
/**
|
||||
* Ease of use function to get the debug module.
|
||||
* TODO(fclem): Should be removed once DRWManager is no longer global.
|
||||
* IMPORTANT: Can return nullptr if storage buffer is not supported.
|
||||
*/
|
||||
blender::draw::DebugDraw *DRW_debug_get();
|
||||
@@ -3028,6 +3028,8 @@ void DRW_engines_free(void)
|
||||
DRW_stats_free();
|
||||
DRW_globals_free();
|
||||
|
||||
drw_debug_module_free(DST.debug);
|
||||
|
||||
DRW_UBO_FREE_SAFE(G_draw.block_ubo);
|
||||
DRW_UBO_FREE_SAFE(G_draw.view_ubo);
|
||||
DRW_TEXTURE_FREE_SAFE(G_draw.ramp);
|
||||
|
||||
@@ -501,20 +501,6 @@ typedef struct DRWCommandSmallChunk {
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16);
|
||||
#endif
|
||||
|
||||
/* ------------- DRAW DEBUG ------------ */
|
||||
|
||||
typedef struct DRWDebugLine {
|
||||
struct DRWDebugLine *next; /* linked list */
|
||||
float pos[2][3];
|
||||
float color[4];
|
||||
} DRWDebugLine;
|
||||
|
||||
typedef struct DRWDebugSphere {
|
||||
struct DRWDebugSphere *next; /* linked list */
|
||||
float mat[4][4];
|
||||
float color[4];
|
||||
} DRWDebugSphere;
|
||||
|
||||
/* ------------- Memory Pools ------------ */
|
||||
|
||||
/* Contains memory pools information */
|
||||
@@ -656,11 +642,7 @@ typedef struct DRWManager {
|
||||
|
||||
GPUDrawList *draw_list;
|
||||
|
||||
struct {
|
||||
/* TODO(@fclem): optimize: use chunks. */
|
||||
DRWDebugLine *lines;
|
||||
DRWDebugSphere *spheres;
|
||||
} debug;
|
||||
DRWDebugModule *debug;
|
||||
} DRWManager;
|
||||
|
||||
extern DRWManager DST; /* TODO: get rid of this and allow multi-threaded rendering. */
|
||||
@@ -675,6 +657,9 @@ void drw_state_set(DRWState state);
|
||||
|
||||
void drw_debug_draw(void);
|
||||
void drw_debug_init(void);
|
||||
void drw_debug_module_free(DRWDebugModule *module);
|
||||
GPUStorageBuf *drw_debug_gpu_draw_buf_get(void);
|
||||
GPUStorageBuf *drw_debug_gpu_print_buf_get(void);
|
||||
|
||||
eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index);
|
||||
|
||||
|
||||
@@ -17,9 +17,14 @@
|
||||
#include "BKE_pbvh.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
/* For debug cursor position. */
|
||||
#include "WM_api.h"
|
||||
#include "wm_window.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meta_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_hash.h"
|
||||
@@ -39,6 +44,16 @@
|
||||
|
||||
#include "intern/gpu_codegen.h"
|
||||
|
||||
/**
|
||||
* IMPORTANT:
|
||||
* In order to be able to write to the same print buffer sequentially, we add a barrier to allow
|
||||
* multiple shader calls writting to the same buffer.
|
||||
* However, this adds explicit synchronisation events which might change the rest of the
|
||||
* application behavior and hide some bugs. If you know you are using shader debug print in only
|
||||
* one shader pass, you can comment this out to remove the aforementioned barrier.
|
||||
*/
|
||||
#define DISABLE_DEBUG_SHADER_PRINT_BARRIER
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Uniform Buffer Object (DRW_uniformbuffer)
|
||||
* \{ */
|
||||
@@ -647,7 +662,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
|
||||
drw_call_calc_orco(ob, ob_infos->orcotexfac);
|
||||
/* Random float value. */
|
||||
uint random = (DST.dupli_source) ?
|
||||
DST.dupli_source->random_id :
|
||||
DST.dupli_source->random_id :
|
||||
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
|
||||
* put it in ob->runtime and make depsgraph ensure it is up to date. */
|
||||
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
|
||||
@@ -1510,6 +1525,27 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
|
||||
shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT);
|
||||
if (debug_print_location != -1) {
|
||||
GPUStorageBuf *buf = drw_debug_gpu_print_buf_get();
|
||||
drw_shgroup_uniform_create_ex(
|
||||
shgroup, debug_print_location, DRW_UNIFORM_STORAGE_BLOCK, buf, 0, 0, 1);
|
||||
# ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER
|
||||
/* Add a barrier to allow multiple shader writting to the same buffer. */
|
||||
DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE);
|
||||
# endif
|
||||
}
|
||||
|
||||
int debug_draw_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS);
|
||||
if (debug_draw_location != -1) {
|
||||
GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get();
|
||||
drw_shgroup_uniform_create_ex(
|
||||
shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, 0, 0, 1);
|
||||
/* NOTE(fclem): No barrier as ordering is not important. */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Not supported. */
|
||||
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
|
||||
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
|
||||
@@ -1986,6 +2022,13 @@ DRWView *DRW_view_create(const float viewmat[4][4],
|
||||
|
||||
copy_v4_fl4(view->storage.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
if (DST.draw_ctx.evil_C && DST.draw_ctx.region) {
|
||||
int region_origin[2] = {DST.draw_ctx.region->winrct.xmin, DST.draw_ctx.region->winrct.ymin};
|
||||
struct wmWindow *win = CTX_wm_window(DST.draw_ctx.evil_C);
|
||||
wm_cursor_position_get(win, &view->storage.mouse_pixel[0], &view->storage.mouse_pixel[1]);
|
||||
sub_v2_v2v2_int(view->storage.mouse_pixel, view->storage.mouse_pixel, region_origin);
|
||||
}
|
||||
|
||||
DRW_view_update(view, viewmat, winmat, culling_viewmat, culling_winmat);
|
||||
|
||||
return view;
|
||||
|
||||
@@ -24,6 +24,8 @@ extern "C" char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
|
||||
|
||||
static struct {
|
||||
struct GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER];
|
||||
struct GPUShader *debug_print_display_sh;
|
||||
struct GPUShader *debug_draw_display_sh;
|
||||
} e_data = {{nullptr}};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -109,6 +111,22 @@ GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineSh
|
||||
return e_data.hair_refine_sh[type];
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_debug_print_display_get()
|
||||
{
|
||||
if (e_data.debug_print_display_sh == nullptr) {
|
||||
e_data.debug_print_display_sh = GPU_shader_create_from_info_name("draw_debug_print_display");
|
||||
}
|
||||
return e_data.debug_print_display_sh;
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_debug_draw_display_get()
|
||||
{
|
||||
if (e_data.debug_draw_display_sh == nullptr) {
|
||||
e_data.debug_draw_display_sh = GPU_shader_create_from_info_name("draw_debug_draw_display");
|
||||
}
|
||||
return e_data.debug_draw_display_sh;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
void DRW_shaders_free()
|
||||
@@ -116,4 +134,6 @@ void DRW_shaders_free()
|
||||
for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
|
||||
DRW_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]);
|
||||
}
|
||||
DRW_SHADER_FREE_SAFE(e_data.debug_print_display_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.debug_draw_display_sh);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
|
||||
struct GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type,
|
||||
eParticleRefineShaderType sh_type);
|
||||
|
||||
struct GPUShader *DRW_shader_debug_print_display_get(void);
|
||||
struct GPUShader *DRW_shader_debug_draw_display_get(void);
|
||||
|
||||
void DRW_shaders_free(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -14,6 +14,9 @@ typedef struct CurvesInfos CurvesInfos;
|
||||
typedef struct DrawCommand DrawCommand;
|
||||
typedef struct DrawCommandIndexed DrawCommandIndexed;
|
||||
typedef struct DispatchCommand DispatchCommand;
|
||||
typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer;
|
||||
typedef struct DRWDebugVert DRWDebugVert;
|
||||
typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer;
|
||||
#endif
|
||||
|
||||
#define DRW_SHADER_SHARED_H
|
||||
@@ -48,6 +51,12 @@ struct ViewInfos {
|
||||
/** NOTE: vec3 arrays are padded to vec4. */
|
||||
float4 frustum_corners[8];
|
||||
float4 frustum_planes[6];
|
||||
|
||||
/** For debugging purpose */
|
||||
/* Mouse pixel. */
|
||||
int2 mouse_pixel;
|
||||
|
||||
int2 _pad0;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
|
||||
|
||||
@@ -131,3 +140,59 @@ struct DispatchCommand {
|
||||
uint _pad0;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DispatchCommand, 16)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug print
|
||||
* \{ */
|
||||
|
||||
/* Take the header (DrawCommand) into account. */
|
||||
#define DRW_DEBUG_PRINT_MAX (8 * 1024) - 4
|
||||
/* NOTE: Cannot be more than 255 (because of column encoding). */
|
||||
#define DRW_DEBUG_PRINT_WORD_WRAP_COLUMN 120u
|
||||
|
||||
/* The debug print buffer is laid-out as the following struct.
|
||||
* But we use plain array in shader code instead because of driver issues. */
|
||||
struct DRWDebugPrintBuffer {
|
||||
DrawCommand command;
|
||||
/** Each character is encoded as 3 uchar with char_index, row and column position. */
|
||||
uint char_array[DRW_DEBUG_PRINT_MAX];
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWDebugPrintBuffer, 16)
|
||||
|
||||
/* Use number of char as vertex count. Equivalent to `DRWDebugPrintBuffer.command.v_count`. */
|
||||
#define drw_debug_print_cursor drw_debug_print_buf[0]
|
||||
/* Reuse first instance as row index as we don't use instancing. Equivalent to
|
||||
* `DRWDebugPrintBuffer.command.i_first`. */
|
||||
#define drw_debug_print_row_shared drw_debug_print_buf[3]
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \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;
|
||||
uint color;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16)
|
||||
|
||||
/* Take the header (DrawCommand) into account. */
|
||||
#define DRW_DEBUG_DRAW_VERT_MAX (64 * 1024) - 1
|
||||
|
||||
/* The debug draw buffer is laid-out as the following struct.
|
||||
* But we use plain array in shader code instead because of driver issues. */
|
||||
struct DRWDebugDrawBuffer {
|
||||
DrawCommand command;
|
||||
DRWDebugVert verts[DRW_DEBUG_DRAW_VERT_MAX];
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWDebugPrintBuffer, 16)
|
||||
|
||||
/* Equivalent to `DRWDebugDrawBuffer.command.v_count`. */
|
||||
#define drw_debug_draw_v_count drw_debug_verts_buf[0].pos0
|
||||
|
||||
/** \} */
|
||||
|
||||
216
source/blender/draw/intern/shaders/common_debug_draw_lib.glsl
Normal file
216
source/blender/draw/intern/shaders/common_debug_draw_lib.glsl
Normal file
@@ -0,0 +1,216 @@
|
||||
|
||||
/**
|
||||
* Debugging drawing library
|
||||
*
|
||||
* Quick way to draw debug geometry. All input should be in world space and
|
||||
* will be rendered in the default view. No additional setup required.
|
||||
**/
|
||||
|
||||
/** Global switch option. */
|
||||
bool drw_debug_draw_enable = true;
|
||||
const vec4 drw_debug_default_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Interals
|
||||
* \{ */
|
||||
|
||||
uint drw_debug_start_draw(uint v_needed)
|
||||
{
|
||||
uint vertid = atomicAdd(drw_debug_draw_v_count, v_needed);
|
||||
/* NOTE: Skip the header manually. */
|
||||
vertid += 1;
|
||||
return vertid;
|
||||
}
|
||||
|
||||
uint drw_debug_color_pack(vec4 color)
|
||||
{
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
uint result = 0;
|
||||
result |= uint(color.x * 255.0) << 0u;
|
||||
result |= uint(color.y * 255.0) << 8u;
|
||||
result |= uint(color.z * 255.0) << 16u;
|
||||
result |= uint(color.w * 255.0) << 24u;
|
||||
return result;
|
||||
}
|
||||
|
||||
void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint color)
|
||||
{
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), color);
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), color);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name API
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Draw a line.
|
||||
*/
|
||||
void drw_debug_line(vec3 v1, vec3 v2, vec4 color)
|
||||
{
|
||||
if (!drw_debug_draw_enable) {
|
||||
return;
|
||||
}
|
||||
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(color));
|
||||
}
|
||||
}
|
||||
void drw_debug_line(vec3 v1, vec3 v2)
|
||||
{
|
||||
drw_debug_line(v1, v2, drw_debug_default_color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a quad contour.
|
||||
*/
|
||||
void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 color)
|
||||
{
|
||||
if (!drw_debug_draw_enable) {
|
||||
return;
|
||||
}
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4)
|
||||
{
|
||||
drw_debug_quad(v1, v2, v3, v4, drw_debug_default_color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a point as octahedron wireframe.
|
||||
*/
|
||||
void drw_debug_point(vec3 p, float radius, vec4 color)
|
||||
{
|
||||
if (!drw_debug_draw_enable) {
|
||||
return;
|
||||
}
|
||||
vec3 c = vec3(radius, -radius, 0);
|
||||
vec3 v1 = p + c.xzz;
|
||||
vec3 v2 = p + c.zxz;
|
||||
vec3 v3 = p + c.yzz;
|
||||
vec3 v4 = p + c.zyz;
|
||||
vec3 v5 = p + c.zzx;
|
||||
vec3 v6 = p + c.zzy;
|
||||
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
void drw_debug_point(vec3 p, float radius)
|
||||
{
|
||||
drw_debug_point(p, radius, drw_debug_default_color);
|
||||
}
|
||||
void drw_debug_point(vec3 p)
|
||||
{
|
||||
drw_debug_point(p, 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a sphere wireframe as 3 axes circle.
|
||||
*/
|
||||
void drw_debug_sphere(vec3 p, float radius, vec4 color)
|
||||
{
|
||||
if (!drw_debug_draw_enable) {
|
||||
return;
|
||||
}
|
||||
const int circle_resolution = 16;
|
||||
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(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);
|
||||
vec3 p1 = vec3(cos(angle1), sin(angle1), 0.0);
|
||||
p1 = vec3(p1[(0 + axis) % 3], p1[(1 + axis) % 3], p1[(2 + axis) % 3]);
|
||||
|
||||
float angle2 = (2.0 * 3.141592) * float(edge + 1) / float(circle_resolution);
|
||||
vec3 p2 = vec3(cos(angle2), sin(angle2), 0.0);
|
||||
p2 = vec3(p2[(0 + axis) % 3], p2[(1 + axis) % 3], p2[(2 + axis) % 3]);
|
||||
|
||||
drw_debug_line(vertid, p1, p2, pcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void drw_debug_sphere(vec3 p, float radius)
|
||||
{
|
||||
drw_debug_sphere(p, radius, drw_debug_default_color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a matrix transformation as 3 colored axes.
|
||||
*/
|
||||
void drw_debug_matrix(mat4 mat, vec4 color)
|
||||
{
|
||||
vec4 p[4] = vec4[4](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));
|
||||
}
|
||||
void drw_debug_matrix(mat4 mat)
|
||||
{
|
||||
drw_debug_matrix(mat, drw_debug_default_color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a matrix as a 2 units length bounding box, centered on origin.
|
||||
*/
|
||||
void drw_debug_matrix_as_bbox(mat4 mat, vec4 color)
|
||||
{
|
||||
vec4 p[8] = vec4[8](vec4(-1, -1, -1, 1),
|
||||
vec4(1, -1, -1, 1),
|
||||
vec4(1, 1, -1, 1),
|
||||
vec4(-1, 1, -1, 1),
|
||||
vec4(-1, -1, 1, 1),
|
||||
vec4(1, -1, 1, 1),
|
||||
vec4(1, 1, 1, 1),
|
||||
vec4(-1, 1, 1, 1));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
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, color);
|
||||
drw_debug_line(p[0].xyz, p[4].xyz, color);
|
||||
drw_debug_line(p[1].xyz, p[5].xyz, color);
|
||||
drw_debug_line(p[2].xyz, p[6].xyz, color);
|
||||
drw_debug_line(p[3].xyz, p[7].xyz, color);
|
||||
drw_debug_quad(p[4].xyz, p[5].xyz, p[6].xyz, p[7].xyz, color);
|
||||
}
|
||||
void drw_debug_matrix_as_bbox(mat4 mat)
|
||||
{
|
||||
drw_debug_matrix_as_bbox(mat, drw_debug_default_color);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
389
source/blender/draw/intern/shaders/common_debug_print_lib.glsl
Normal file
389
source/blender/draw/intern/shaders/common_debug_print_lib.glsl
Normal file
@@ -0,0 +1,389 @@
|
||||
|
||||
/**
|
||||
* Debug print implementation for shaders.
|
||||
*
|
||||
* `print()`:
|
||||
* Log variable or strings inside the viewport.
|
||||
* Using a unique non string argument will print the variable name with it.
|
||||
* Concatenate by using multiple arguments. i.e: `print("Looped ", n, "times.")`.
|
||||
* `drw_print_no_endl()`:
|
||||
* Same as `print()` but does not finish the line.
|
||||
* `drw_print_value()`:
|
||||
* Display only the value of a variable. Does not finish the line.
|
||||
* `drw_print_value_hex()`:
|
||||
* Display only the hex representation of a variable. Does not finish the line.
|
||||
* `drw_print_value_binary()`: Display only the binary representation of a
|
||||
* variable. Does not finish the line.
|
||||
*
|
||||
* IMPORTANT: As it is now, it is not yet thread safe. Only print from one thread. You can use the
|
||||
* IS_DEBUG_MOUSE_FRAGMENT macro in fragment shader to filter using mouse position or
|
||||
* IS_FIRST_INVOCATION in compute shaders.
|
||||
*
|
||||
* NOTE: Floating point representation might not be very precise (see drw_print_value(float)).
|
||||
*
|
||||
* IMPORTANT: Multipler drawcalls can write to the buffer in sequence (if they are from different
|
||||
* shgroups). However, we add barriers to support this case and it might change the application
|
||||
* behavior. Uncomment DISABLE_DEBUG_SHADER_drw_print_BARRIER to remove the barriers if that
|
||||
* happens. But then you are limited to a single invocation output.
|
||||
*
|
||||
* IMPORTANT: All of these are copied to the CPU debug libs (draw_debug.cc). They need to be kept
|
||||
* in sync to write the same data.
|
||||
*/
|
||||
|
||||
/** Global switch option when you want to silence all prints from all shaders at once. */
|
||||
bool drw_debug_print_enable = true;
|
||||
|
||||
/* Set drw_print_col to max value so we will start by creating a new line and get the correct
|
||||
* threadsafe row. */
|
||||
uint drw_print_col = DRW_DEBUG_PRINT_WORD_WRAP_COLUMN;
|
||||
uint drw_print_row = 0u;
|
||||
|
||||
void drw_print_newline()
|
||||
{
|
||||
if (!drw_debug_print_enable) {
|
||||
return;
|
||||
}
|
||||
drw_print_col = 0u;
|
||||
drw_print_row = atomicAdd(drw_debug_print_row_shared, 1u) + 1u;
|
||||
}
|
||||
|
||||
void drw_print_string_start(uint len)
|
||||
{
|
||||
if (!drw_debug_print_enable) {
|
||||
return;
|
||||
}
|
||||
/* Break before word. */
|
||||
if (drw_print_col + len > DRW_DEBUG_PRINT_WORD_WRAP_COLUMN) {
|
||||
drw_print_newline();
|
||||
}
|
||||
}
|
||||
|
||||
void drw_print_char4(uint data)
|
||||
{
|
||||
if (!drw_debug_print_enable) {
|
||||
return;
|
||||
}
|
||||
/* Convert into char stream. */
|
||||
for (; data != 0u; data >>= 8u) {
|
||||
uint char1 = data & 0xFFu;
|
||||
/* Check for null terminator. */
|
||||
if (char1 == 0x00) {
|
||||
break;
|
||||
}
|
||||
uint cursor = atomicAdd(drw_debug_print_cursor, 1u);
|
||||
/* NOTE: Skip the header manually. */
|
||||
cursor += 4;
|
||||
if (cursor < DRW_DEBUG_PRINT_MAX) {
|
||||
/* For future usage. (i.e: Color) */
|
||||
uint flags = 0u;
|
||||
uint col = drw_print_col++;
|
||||
uint drw_print_header = (flags << 24u) | (drw_print_row << 16u) | (col << 8u);
|
||||
drw_debug_print_buf[cursor] = drw_print_header | char1;
|
||||
/* Break word. */
|
||||
if (drw_print_col > DRW_DEBUG_PRINT_WORD_WRAP_COLUMN) {
|
||||
drw_print_newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE(fclem): Strange behavior emerge when trying to increment the digit
|
||||
* counter inside the append function. It looks like the compiler does not see
|
||||
* it is referenced as an index for char4 and thus do not capture the right
|
||||
* reference. I do not know if this is undefined behavior. As a matter of
|
||||
* precaution, we implement all the append function separately. This behavior
|
||||
* was observed on both Mesa & amdgpu-pro.
|
||||
*/
|
||||
/* Using ascii char code. Expect char1 to be less or equal to 0xFF. Appends chars to the right. */
|
||||
void drw_print_append_char(uint char1, inout uint char4)
|
||||
{
|
||||
char4 = (char4 << 8u) | char1;
|
||||
}
|
||||
|
||||
void drw_print_append_digit(uint digit, inout uint char4)
|
||||
{
|
||||
const uint char_A = 0x41u;
|
||||
const uint char_0 = 0x30u;
|
||||
bool is_hexadecimal = digit > 9u;
|
||||
char4 = (char4 << 8u) | (is_hexadecimal ? (char_A + digit - 10u) : (char_0 + digit));
|
||||
}
|
||||
|
||||
void drw_print_append_space(inout uint char4)
|
||||
{
|
||||
char4 = (char4 << 8u) | 0x20u;
|
||||
}
|
||||
|
||||
void drw_print_value_binary(uint value)
|
||||
{
|
||||
drw_print_no_endl("0b");
|
||||
drw_print_string_start(10u * 4u);
|
||||
uint digits[10] = uint[10](0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
|
||||
uint digit = 0u;
|
||||
for (uint i = 0u; i < 32u; i++) {
|
||||
drw_print_append_digit(((value >> i) & 1u), digits[digit / 4u]);
|
||||
digit++;
|
||||
if ((i % 4u) == 3u) {
|
||||
drw_print_append_space(digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
}
|
||||
/* Numbers are written from right to left. So we need to reverse the order. */
|
||||
for (int j = 9; j >= 0; j--) {
|
||||
drw_print_char4(digits[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void drw_print_value_binary(int value)
|
||||
{
|
||||
drw_print_value_binary(uint(value));
|
||||
}
|
||||
|
||||
void drw_print_value_binary(float value)
|
||||
{
|
||||
drw_print_value_binary(floatBitsToUint(value));
|
||||
}
|
||||
|
||||
void drw_print_value_uint(uint value, const bool hex, bool is_negative, const bool is_unsigned)
|
||||
{
|
||||
drw_print_string_start(3u * 4u);
|
||||
const uint blank_value = hex ? 0x30303030u : 0x20202020u;
|
||||
const uint prefix = hex ? 0x78302020u : 0x20202020u;
|
||||
uint digits[3] = uint[3](blank_value, blank_value, prefix);
|
||||
const uint base = hex ? 16u : 10u;
|
||||
uint digit = 0u;
|
||||
/* Add `u` suffix. */
|
||||
if (is_unsigned) {
|
||||
drw_print_append_char('u', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Number's digits. */
|
||||
for (; value != 0u || digit == uint(is_unsigned); value /= base) {
|
||||
drw_print_append_digit(value % base, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Add negative sign. */
|
||||
if (is_negative) {
|
||||
drw_print_append_char('-', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Need to pad to uint alignment because we are issuing chars in "reverse". */
|
||||
for (uint i = digit % 4u; i < 4u && i > 0u; i++) {
|
||||
drw_print_append_space(digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Numbers are written from right to left. So we need to reverse the order. */
|
||||
for (int j = 2; j >= 0; j--) {
|
||||
drw_print_char4(digits[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void drw_print_value_hex(uint value)
|
||||
{
|
||||
drw_print_value_uint(value, true, false, false);
|
||||
}
|
||||
|
||||
void drw_print_value_hex(int value)
|
||||
{
|
||||
drw_print_value_uint(uint(value), true, false, false);
|
||||
}
|
||||
|
||||
void drw_print_value_hex(float value)
|
||||
{
|
||||
drw_print_value_uint(floatBitsToUint(value), true, false, false);
|
||||
}
|
||||
|
||||
void drw_print_value(uint value)
|
||||
{
|
||||
drw_print_value_uint(value, false, false, true);
|
||||
}
|
||||
|
||||
void drw_print_value(int value)
|
||||
{
|
||||
drw_print_value_uint(uint(abs(value)), false, (value < 0), false);
|
||||
}
|
||||
|
||||
void drw_print_value(bool value)
|
||||
{
|
||||
if (value) {
|
||||
drw_print_no_endl("true ");
|
||||
}
|
||||
else {
|
||||
drw_print_no_endl("false");
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE(@fclem): This is homebrew and might not be 100% accurate (accuracy has
|
||||
* not been tested and might dependent on compiler implementation). If unsure,
|
||||
* use drw_print_value_hex and transcribe the value manually with another tool. */
|
||||
void drw_print_value(float val)
|
||||
{
|
||||
/* We pad the string to match normal float values length. */
|
||||
if (isnan(val)) {
|
||||
drw_print_no_endl(" NaN");
|
||||
return;
|
||||
}
|
||||
if (isinf(val)) {
|
||||
if (sign(val) < 0.0) {
|
||||
drw_print_no_endl(" -Inf");
|
||||
}
|
||||
else {
|
||||
drw_print_no_endl(" Inf");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Adjusted for significant digits (6) with sign (1), decimal separator (1)
|
||||
* and exponent (4). */
|
||||
const float significant_digits = 6.0;
|
||||
drw_print_string_start(3u * 4u);
|
||||
uint digits[3] = uint[3](0x20202020u, 0x20202020u, 0x20202020u);
|
||||
|
||||
float exponent = floor(log(abs(val)) / log(10.0));
|
||||
bool display_exponent = exponent >= (significant_digits) ||
|
||||
exponent <= (-significant_digits + 1.0);
|
||||
|
||||
float int_significant_digits = min(exponent + 1.0, significant_digits);
|
||||
float dec_significant_digits = max(0.0, significant_digits - int_significant_digits);
|
||||
/* Power to get to the rounding point. */
|
||||
float rounding_power = dec_significant_digits;
|
||||
|
||||
if (val == 0.0 || isinf(exponent)) {
|
||||
display_exponent = false;
|
||||
int_significant_digits = dec_significant_digits = 1.0;
|
||||
}
|
||||
/* Remap to keep significant numbers count. */
|
||||
if (display_exponent) {
|
||||
int_significant_digits = 1.0;
|
||||
dec_significant_digits = significant_digits - int_significant_digits;
|
||||
rounding_power = -exponent + dec_significant_digits;
|
||||
}
|
||||
/* Round at the last significant digit. */
|
||||
val = round(val * pow(10.0, rounding_power));
|
||||
/* Get back to final exponent. */
|
||||
val *= pow(10.0, -dec_significant_digits);
|
||||
|
||||
float int_part;
|
||||
float dec_part = modf(val, int_part);
|
||||
|
||||
dec_part *= pow(10.0, dec_significant_digits);
|
||||
|
||||
const uint base = 10u;
|
||||
uint digit = 0u;
|
||||
/* Exponent */
|
||||
uint value = uint(abs(exponent));
|
||||
if (display_exponent) {
|
||||
for (int i = 0; value != 0u || i == 0; i++, value /= base) {
|
||||
drw_print_append_digit(value % base, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Exponent sign. */
|
||||
uint sign_char = (exponent < 0.0) ? '-' : '+';
|
||||
drw_print_append_char(sign_char, digits[digit / 4u]);
|
||||
digit++;
|
||||
/* Exponent `e` suffix. */
|
||||
drw_print_append_char(0x65u, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Decimal part. */
|
||||
value = uint(abs(dec_part));
|
||||
#if 0 /* We don't do that because it makes unstable values really hard to \
|
||||
read. */
|
||||
/* Trim trailing zeros. */
|
||||
while ((value % base) == 0u) {
|
||||
value /= base;
|
||||
if (value == 0u) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (value != 0u) {
|
||||
for (int i = 0; value != 0u || i == 0; i++, value /= base) {
|
||||
drw_print_append_digit(value % base, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Point separator. */
|
||||
drw_print_append_char('.', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Integer part. */
|
||||
value = uint(abs(int_part));
|
||||
for (int i = 0; value != 0u || i == 0; i++, value /= base) {
|
||||
drw_print_append_digit(value % base, digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Negative sign. */
|
||||
if (val < 0.0) {
|
||||
drw_print_append_char('-', digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Need to pad to uint alignment because we are issuing chars in "reverse". */
|
||||
for (uint i = digit % 4u; i < 4u && i > 0u; i++) {
|
||||
drw_print_append_space(digits[digit / 4u]);
|
||||
digit++;
|
||||
}
|
||||
/* Numbers are written from right to left. So we need to reverse the order. */
|
||||
for (int j = 2; j >= 0; j--) {
|
||||
drw_print_char4(digits[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void drw_print_value(vec2 value)
|
||||
{
|
||||
drw_print_no_endl("vec2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(vec3 value)
|
||||
{
|
||||
drw_print_no_endl("vec3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(vec4 value)
|
||||
{
|
||||
drw_print_no_endl("vec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(ivec2 value)
|
||||
{
|
||||
drw_print_no_endl("ivec2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(ivec3 value)
|
||||
{
|
||||
drw_print_no_endl("ivec3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(ivec4 value)
|
||||
{
|
||||
drw_print_no_endl("ivec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(uvec2 value)
|
||||
{
|
||||
drw_print_no_endl("uvec2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(uvec3 value)
|
||||
{
|
||||
drw_print_no_endl("uvec3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(uvec4 value)
|
||||
{
|
||||
drw_print_no_endl("uvec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(bvec2 value)
|
||||
{
|
||||
drw_print_no_endl("bvec2(", value[0], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(bvec3 value)
|
||||
{
|
||||
drw_print_no_endl("bvec3(", value[0], ", ", value[1], ", ", value[1], ")");
|
||||
}
|
||||
|
||||
void drw_print_value(bvec4 value)
|
||||
{
|
||||
drw_print_no_endl("bvec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
|
||||
}
|
||||
@@ -37,6 +37,9 @@ layout(std140) uniform viewBlock
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define IS_DEBUG_MOUSE_FRAGMENT (ivec2(gl_FragCoord) == drw_view.mouse_pixel)
|
||||
#define IS_FIRST_INVOCATION (gl_GlobalInvocationID == uvec3(0))
|
||||
|
||||
#define ViewNear (ViewVecs[0].w)
|
||||
#define ViewFar (ViewVecs[1].w)
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
/**
|
||||
* Display debug edge list.
|
||||
**/
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = interp.color;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
/**
|
||||
* Display debug edge list.
|
||||
**/
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Skip the first vertex containing header data. */
|
||||
DRWDebugVert vert = drw_debug_verts_buf[gl_VertexID + 1];
|
||||
vec3 pos = uintBitsToFloat(uvec3(vert.pos0, vert.pos1, vert.pos2));
|
||||
vec4 col = vec4((uvec4(vert.color) >> uvec4(0, 8, 16, 24)) & 0xFFu);
|
||||
|
||||
interp.color = col;
|
||||
gl_Position = persmat * vec4(pos, 1.0);
|
||||
}
|
||||
51
source/blender/draw/intern/shaders/draw_debug_info.hh
Normal file
51
source/blender/draw/intern/shaders/draw_debug_info.hh
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug print
|
||||
*
|
||||
* Allows print() function to have logging support inside shaders.
|
||||
* \{ */
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_debug_print)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(7, Qualifier::READ_WRITE, "uint", "drw_debug_print_buf[]");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(draw_debug_print_display_iface, "").flat(Type::UINT, "char_index");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_debug_print_display)
|
||||
.do_static_compilation(true)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(7, Qualifier::READ, "uint", "drw_debug_print_buf[]")
|
||||
.vertex_out(draw_debug_print_display_iface)
|
||||
.fragment_out(0, Type::VEC4, "out_color")
|
||||
.vertex_source("draw_debug_print_display_vert.glsl")
|
||||
.fragment_source("draw_debug_print_display_frag.glsl")
|
||||
.additional_info("draw_view");
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug draw shapes
|
||||
*
|
||||
* Allows to draw lines and points just like the DRW_debug module functions.
|
||||
* \{ */
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_debug_draw)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "DRWDebugVert", "drw_debug_verts_buf[]");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(draw_debug_draw_display_iface, "interp").flat(Type::VEC4, "color");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_debug_draw_display)
|
||||
.do_static_compilation(true)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(6, Qualifier::READ, "DRWDebugVert", "drw_debug_verts_buf[]")
|
||||
.vertex_out(draw_debug_draw_display_iface)
|
||||
.fragment_out(0, Type::VEC4, "out_color")
|
||||
.push_constant(Type::MAT4, "persmat")
|
||||
.vertex_source("draw_debug_draw_display_vert.glsl")
|
||||
.fragment_source("draw_debug_draw_display_frag.glsl")
|
||||
.additional_info("draw_view");
|
||||
|
||||
/** \} */
|
||||
@@ -0,0 +1,133 @@
|
||||
|
||||
/**
|
||||
* Display characters using an ascii table.
|
||||
**/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
bool char_intersect(uvec2 bitmap_position)
|
||||
{
|
||||
/* Using 8x8 = 64bits = uvec2. */
|
||||
uvec2 ascii_bitmap[96] = uvec2[96](uvec2(0x00000000u, 0x00000000u),
|
||||
uvec2(0x18001800u, 0x183c3c18u),
|
||||
uvec2(0x00000000u, 0x36360000u),
|
||||
uvec2(0x7f363600u, 0x36367f36u),
|
||||
uvec2(0x301f0c00u, 0x0c3e031eu),
|
||||
uvec2(0x0c666300u, 0x00633318u),
|
||||
uvec2(0x3b336e00u, 0x1c361c6eu),
|
||||
uvec2(0x00000000u, 0x06060300u),
|
||||
uvec2(0x060c1800u, 0x180c0606u),
|
||||
uvec2(0x180c0600u, 0x060c1818u),
|
||||
uvec2(0x3c660000u, 0x00663cffu),
|
||||
uvec2(0x0c0c0000u, 0x000c0c3fu),
|
||||
uvec2(0x000c0c06u, 0x00000000u),
|
||||
uvec2(0x00000000u, 0x0000003fu),
|
||||
uvec2(0x000c0c00u, 0x00000000u),
|
||||
uvec2(0x06030100u, 0x6030180cu),
|
||||
uvec2(0x6f673e00u, 0x3e63737bu),
|
||||
uvec2(0x0c0c3f00u, 0x0c0e0c0cu),
|
||||
uvec2(0x06333f00u, 0x1e33301cu),
|
||||
uvec2(0x30331e00u, 0x1e33301cu),
|
||||
uvec2(0x7f307800u, 0x383c3633u),
|
||||
uvec2(0x30331e00u, 0x3f031f30u),
|
||||
uvec2(0x33331e00u, 0x1c06031fu),
|
||||
uvec2(0x0c0c0c00u, 0x3f333018u),
|
||||
uvec2(0x33331e00u, 0x1e33331eu),
|
||||
uvec2(0x30180e00u, 0x1e33333eu),
|
||||
uvec2(0x000c0c00u, 0x000c0c00u),
|
||||
uvec2(0x000c0c06u, 0x000c0c00u),
|
||||
uvec2(0x060c1800u, 0x180c0603u),
|
||||
uvec2(0x003f0000u, 0x00003f00u),
|
||||
uvec2(0x180c0600u, 0x060c1830u),
|
||||
uvec2(0x0c000c00u, 0x1e333018u),
|
||||
uvec2(0x7b031e00u, 0x3e637b7bu),
|
||||
uvec2(0x3f333300u, 0x0c1e3333u),
|
||||
uvec2(0x66663f00u, 0x3f66663eu),
|
||||
uvec2(0x03663c00u, 0x3c660303u),
|
||||
uvec2(0x66361f00u, 0x1f366666u),
|
||||
uvec2(0x16467f00u, 0x7f46161eu),
|
||||
uvec2(0x16060f00u, 0x7f46161eu),
|
||||
uvec2(0x73667c00u, 0x3c660303u),
|
||||
uvec2(0x33333300u, 0x3333333fu),
|
||||
uvec2(0x0c0c1e00u, 0x1e0c0c0cu),
|
||||
uvec2(0x33331e00u, 0x78303030u),
|
||||
uvec2(0x36666700u, 0x6766361eu),
|
||||
uvec2(0x46667f00u, 0x0f060606u),
|
||||
uvec2(0x6b636300u, 0x63777f7fu),
|
||||
uvec2(0x73636300u, 0x63676f7bu),
|
||||
uvec2(0x63361c00u, 0x1c366363u),
|
||||
uvec2(0x06060f00u, 0x3f66663eu),
|
||||
uvec2(0x3b1e3800u, 0x1e333333u),
|
||||
uvec2(0x36666700u, 0x3f66663eu),
|
||||
uvec2(0x38331e00u, 0x1e33070eu),
|
||||
uvec2(0x0c0c1e00u, 0x3f2d0c0cu),
|
||||
uvec2(0x33333f00u, 0x33333333u),
|
||||
uvec2(0x331e0c00u, 0x33333333u),
|
||||
uvec2(0x7f776300u, 0x6363636bu),
|
||||
uvec2(0x1c366300u, 0x6363361cu),
|
||||
uvec2(0x0c0c1e00u, 0x3333331eu),
|
||||
uvec2(0x4c667f00u, 0x7f633118u),
|
||||
uvec2(0x06061e00u, 0x1e060606u),
|
||||
uvec2(0x30604000u, 0x03060c18u),
|
||||
uvec2(0x18181e00u, 0x1e181818u),
|
||||
uvec2(0x00000000u, 0x081c3663u),
|
||||
uvec2(0x000000ffu, 0x00000000u),
|
||||
uvec2(0x00000000u, 0x0c0c1800u),
|
||||
uvec2(0x3e336e00u, 0x00001e30u),
|
||||
uvec2(0x66663b00u, 0x0706063eu),
|
||||
uvec2(0x03331e00u, 0x00001e33u),
|
||||
uvec2(0x33336e00u, 0x3830303eu),
|
||||
uvec2(0x3f031e00u, 0x00001e33u),
|
||||
uvec2(0x06060f00u, 0x1c36060fu),
|
||||
uvec2(0x333e301fu, 0x00006e33u),
|
||||
uvec2(0x66666700u, 0x0706366eu),
|
||||
uvec2(0x0c0c1e00u, 0x0c000e0cu),
|
||||
uvec2(0x3033331eu, 0x30003030u),
|
||||
uvec2(0x1e366700u, 0x07066636u),
|
||||
uvec2(0x0c0c1e00u, 0x0e0c0c0cu),
|
||||
uvec2(0x7f6b6300u, 0x0000337fu),
|
||||
uvec2(0x33333300u, 0x00001f33u),
|
||||
uvec2(0x33331e00u, 0x00001e33u),
|
||||
uvec2(0x663e060fu, 0x00003b66u),
|
||||
uvec2(0x333e3078u, 0x00006e33u),
|
||||
uvec2(0x66060f00u, 0x00003b6eu),
|
||||
uvec2(0x1e301f00u, 0x00003e03u),
|
||||
uvec2(0x0c2c1800u, 0x080c3e0cu),
|
||||
uvec2(0x33336e00u, 0x00003333u),
|
||||
uvec2(0x331e0c00u, 0x00003333u),
|
||||
uvec2(0x7f7f3600u, 0x0000636bu),
|
||||
uvec2(0x1c366300u, 0x00006336u),
|
||||
uvec2(0x333e301fu, 0x00003333u),
|
||||
uvec2(0x0c263f00u, 0x00003f19u),
|
||||
uvec2(0x0c0c3800u, 0x380c0c07u),
|
||||
uvec2(0x18181800u, 0x18181800u),
|
||||
uvec2(0x0c0c0700u, 0x070c0c38u),
|
||||
uvec2(0x00000000u, 0x6e3b0000u),
|
||||
uvec2(0x00000000u, 0x00000000u));
|
||||
|
||||
if (!in_range_inclusive(bitmap_position, uvec2(0), uvec2(7))) {
|
||||
return false;
|
||||
}
|
||||
uint char_bits = ascii_bitmap[char_index][bitmap_position.y >> 2u & 1u];
|
||||
char_bits = (char_bits >> ((bitmap_position.y & 3u) * 8u + bitmap_position.x));
|
||||
return (char_bits & 1u) != 0u;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
uvec2 bitmap_position = uvec2(gl_PointCoord.xy * 8.0);
|
||||
/* Point coord start from top left corner. But layout is from bottom to top. */
|
||||
bitmap_position.y = 7 - bitmap_position.y;
|
||||
|
||||
if (char_intersect(bitmap_position)) {
|
||||
out_color = vec4(1);
|
||||
}
|
||||
else if (char_intersect(bitmap_position + uvec2(0, 1))) {
|
||||
/* Shadow */
|
||||
out_color = vec4(0, 0, 0, 1);
|
||||
}
|
||||
else {
|
||||
/* Transparent Background for ease of read. */
|
||||
out_color = vec4(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/**
|
||||
* Display characters using an ascii table. Outputs one point per character.
|
||||
**/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Skip first 4 chars containing header data. */
|
||||
uint char_data = drw_debug_print_buf[gl_VertexID + 4];
|
||||
char_index = (char_data & 0xFFu) - 0x20u;
|
||||
|
||||
/* Discard invalid chars. */
|
||||
if (char_index >= 96u) {
|
||||
gl_Position = vec4(-1);
|
||||
gl_PointSize = 0.0;
|
||||
return;
|
||||
}
|
||||
uint row = (char_data >> 16u) & 0xFFu;
|
||||
uint col = (char_data >> 8u) & 0xFFu;
|
||||
|
||||
float char_size = 16.0;
|
||||
/* Change anchor point to the top left. */
|
||||
vec2 pos_on_screen = char_size * vec2(col, row) + char_size * 4;
|
||||
gl_Position = vec4(
|
||||
pos_on_screen * drw_view.viewport_size_inverse * vec2(2.0, -2.0) - vec2(1.0, -1.0), 0, 1);
|
||||
gl_PointSize = char_size;
|
||||
}
|
||||
@@ -486,6 +486,7 @@ set(SRC_SHADER_CREATE_INFOS
|
||||
../draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
|
||||
../draw/engines/workbench/shaders/infos/workbench_volume_info.hh
|
||||
../draw/engines/image/shaders/infos/engine_image_info.hh
|
||||
../draw/intern/shaders/draw_debug_info.hh
|
||||
../draw/intern/shaders/draw_fullscreen_info.hh
|
||||
../draw/intern/shaders/draw_hair_refine_info.hh
|
||||
../draw/intern/shaders/draw_object_infos_info.hh
|
||||
|
||||
@@ -148,11 +148,19 @@ typedef enum {
|
||||
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
|
||||
} GPUUniformBlockBuiltin;
|
||||
|
||||
typedef enum {
|
||||
GPU_STORAGE_BUFFER_DEBUG_VERTS = 0, /* drw_debug_verts_buf */
|
||||
GPU_STORAGE_BUFFER_DEBUG_PRINT, /* drw_debug_print_buf */
|
||||
|
||||
GPU_NUM_STORAGE_BUFFERS, /* Special value, denotes number of builtin buffer blocks. */
|
||||
} GPUStorageBufferBuiltin;
|
||||
|
||||
void GPU_shader_set_srgb_uniform(GPUShader *shader);
|
||||
|
||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
|
||||
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
|
||||
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
|
||||
int GPU_shader_get_builtin_ssbo(GPUShader *shader, int builtin);
|
||||
/** DEPRECATED: Kept only because of Python GPU API. */
|
||||
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
|
||||
int GPU_shader_get_ssbo(GPUShader *shader, const char *name);
|
||||
|
||||
@@ -578,6 +578,12 @@ int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
|
||||
return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
|
||||
}
|
||||
|
||||
int GPU_shader_get_builtin_ssbo(GPUShader *shader, int builtin)
|
||||
{
|
||||
ShaderInterface *interface = unwrap(shader)->interface;
|
||||
return interface->ssbo_builtin((GPUStorageBufferBuiltin)builtin);
|
||||
}
|
||||
|
||||
int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
|
||||
{
|
||||
ShaderInterface *interface = unwrap(shader)->interface;
|
||||
|
||||
@@ -306,6 +306,14 @@ void gpu_shader_create_info_init()
|
||||
info->builtins_ |= gpu_shader_dependency_get_builtins(info->fragment_source_);
|
||||
info->builtins_ |= gpu_shader_dependency_get_builtins(info->geometry_source_);
|
||||
info->builtins_ |= gpu_shader_dependency_get_builtins(info->compute_source_);
|
||||
|
||||
/* Automatically amend the create info for ease of use of the debug feature. */
|
||||
if ((info->builtins_ & BuiltinBits::USE_DEBUG_DRAW) == BuiltinBits::USE_DEBUG_DRAW) {
|
||||
info->additional_info("draw_debug_draw");
|
||||
}
|
||||
if ((info->builtins_ & BuiltinBits::USE_DEBUG_PRINT) == BuiltinBits::USE_DEBUG_PRINT) {
|
||||
info->additional_info("draw_debug_print");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,8 +127,12 @@ enum class BuiltinBits {
|
||||
VERTEX_ID = (1 << 14),
|
||||
WORK_GROUP_ID = (1 << 15),
|
||||
WORK_GROUP_SIZE = (1 << 16),
|
||||
|
||||
/* Not a builtin but a flag we use to tag shaders that use the debug features. */
|
||||
USE_DEBUG_DRAW = (1 << 29),
|
||||
USE_DEBUG_PRINT = (1 << 30),
|
||||
};
|
||||
ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE);
|
||||
ENUM_OPERATORS(BuiltinBits, BuiltinBits::USE_DEBUG_PRINT);
|
||||
|
||||
/**
|
||||
* Follow convention described in:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
@@ -42,7 +43,7 @@ struct GPUSource {
|
||||
StringRefNull source;
|
||||
Vector<GPUSource *> dependencies;
|
||||
bool dependencies_init = false;
|
||||
shader::BuiltinBits builtins = (shader::BuiltinBits)0;
|
||||
shader::BuiltinBits builtins = shader::BuiltinBits::NONE;
|
||||
std::string processed_source;
|
||||
|
||||
GPUSource(const char *path,
|
||||
@@ -54,46 +55,45 @@ struct GPUSource {
|
||||
/* Scan for builtins. */
|
||||
/* FIXME: This can trigger false positive caused by disabled #if blocks. */
|
||||
/* TODO(fclem): Could be made faster by scanning once. */
|
||||
if (source.find("gl_FragCoord", 0)) {
|
||||
if (source.find("gl_FragCoord", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::FRAG_COORD;
|
||||
}
|
||||
if (source.find("gl_FrontFacing", 0)) {
|
||||
if (source.find("gl_FrontFacing", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::FRONT_FACING;
|
||||
}
|
||||
if (source.find("gl_GlobalInvocationID", 0)) {
|
||||
if (source.find("gl_GlobalInvocationID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::GLOBAL_INVOCATION_ID;
|
||||
}
|
||||
if (source.find("gl_InstanceID", 0)) {
|
||||
if (source.find("gl_InstanceID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::INSTANCE_ID;
|
||||
}
|
||||
if (source.find("gl_LocalInvocationID", 0)) {
|
||||
if (source.find("gl_LocalInvocationID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID;
|
||||
}
|
||||
if (source.find("gl_LocalInvocationIndex", 0)) {
|
||||
if (source.find("gl_LocalInvocationIndex", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::LOCAL_INVOCATION_INDEX;
|
||||
}
|
||||
if (source.find("gl_NumWorkGroup", 0)) {
|
||||
if (source.find("gl_NumWorkGroup", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::NUM_WORK_GROUP;
|
||||
}
|
||||
if (source.find("gl_PointCoord", 0)) {
|
||||
if (source.find("gl_PointCoord", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::POINT_COORD;
|
||||
}
|
||||
if (source.find("gl_PointSize", 0)) {
|
||||
if (source.find("gl_PointSize", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::POINT_SIZE;
|
||||
}
|
||||
if (source.find("gl_PrimitiveID", 0)) {
|
||||
if (source.find("gl_PrimitiveID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::PRIMITIVE_ID;
|
||||
}
|
||||
if (source.find("gl_VertexID", 0)) {
|
||||
if (source.find("gl_VertexID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::VERTEX_ID;
|
||||
}
|
||||
if (source.find("gl_WorkGroupID", 0)) {
|
||||
if (source.find("gl_WorkGroupID", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::WORK_GROUP_ID;
|
||||
}
|
||||
if (source.find("gl_WorkGroupSize", 0)) {
|
||||
if (source.find("gl_WorkGroupSize", 0) != StringRef::not_found) {
|
||||
builtins |= shader::BuiltinBits::WORK_GROUP_SIZE;
|
||||
}
|
||||
|
||||
/* TODO(fclem): We could do that at compile time. */
|
||||
/* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
|
||||
if (filename.endswith(".h") || filename.endswith(".hh")) {
|
||||
@@ -101,6 +101,18 @@ struct GPUSource {
|
||||
quote_preprocess();
|
||||
}
|
||||
else {
|
||||
if (source.find("'") != StringRef::not_found) {
|
||||
char_literals_preprocess();
|
||||
}
|
||||
if (source.find("drw_print") != StringRef::not_found) {
|
||||
string_preprocess();
|
||||
}
|
||||
if ((source.find("drw_debug_") != StringRef::not_found) &&
|
||||
/* Avoid theses two files where it makes no sense to add the dependency. */
|
||||
(filename != "common_debug_draw_lib.glsl" &&
|
||||
filename != "draw_debug_draw_display_vert.glsl")) {
|
||||
builtins |= shader::BuiltinBits::USE_DEBUG_DRAW;
|
||||
}
|
||||
check_no_quotes();
|
||||
}
|
||||
|
||||
@@ -522,6 +534,217 @@ struct GPUSource {
|
||||
}
|
||||
}
|
||||
|
||||
void char_literals_preprocess()
|
||||
{
|
||||
const StringRefNull input = source;
|
||||
std::stringstream output;
|
||||
int64_t cursor = -1;
|
||||
int64_t last_pos = 0;
|
||||
|
||||
while (true) {
|
||||
cursor = find_token(input, '\'', cursor + 1);
|
||||
if (cursor == -1) {
|
||||
break;
|
||||
}
|
||||
/* Output anything between 2 print statement. */
|
||||
output << input.substr(last_pos, cursor - last_pos);
|
||||
|
||||
/* Extract string. */
|
||||
int64_t char_start = cursor + 1;
|
||||
int64_t char_end = find_token(input, '\'', char_start);
|
||||
CHECK(char_end, input, cursor, "Malformed char literal. Missing ending `'`.");
|
||||
|
||||
StringRef input_char = input.substr(char_start, char_end - char_start);
|
||||
if (input_char.size() == 0) {
|
||||
CHECK(-1, input, cursor, "Malformed char literal. Empty character constant");
|
||||
}
|
||||
|
||||
uint8_t char_value = input_char[0];
|
||||
|
||||
if (input_char[0] == '\\') {
|
||||
if (input_char[1] == 'n') {
|
||||
char_value = '\n';
|
||||
}
|
||||
else {
|
||||
CHECK(-1, input, cursor, "Unsupported escaped character");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (input_char.size() > 1) {
|
||||
CHECK(-1, input, cursor, "Malformed char literal. Multi-character character constant");
|
||||
}
|
||||
}
|
||||
|
||||
char hex[8];
|
||||
SNPRINTF(hex, "0x%.2Xu", char_value);
|
||||
output << hex;
|
||||
|
||||
cursor = last_pos = char_end + 1;
|
||||
}
|
||||
/* If nothing has been changed, do not allocate processed_source. */
|
||||
if (last_pos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_pos != 0) {
|
||||
output << input.substr(last_pos);
|
||||
}
|
||||
processed_source = output.str();
|
||||
source = processed_source.c_str();
|
||||
}
|
||||
|
||||
/* Replace print(string) by equivalent drw_print_char4() sequence. */
|
||||
void string_preprocess()
|
||||
{
|
||||
const StringRefNull input = source;
|
||||
std::stringstream output;
|
||||
int64_t cursor = -1;
|
||||
int64_t last_pos = 0;
|
||||
|
||||
while (true) {
|
||||
cursor = find_keyword(input, "drw_print", cursor + 1);
|
||||
if (cursor == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool do_endl = false;
|
||||
StringRef func = input.substr(cursor);
|
||||
if (func.startswith("drw_print(")) {
|
||||
do_endl = true;
|
||||
}
|
||||
else if (func.startswith("drw_print_no_endl(")) {
|
||||
do_endl = false;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Output anything between 2 print statement. */
|
||||
output << input.substr(last_pos, cursor - last_pos);
|
||||
|
||||
/* Extract string. */
|
||||
int64_t str_start = input.find('(', cursor) + 1;
|
||||
int64_t semicolon = find_token(input, ';', str_start + 1);
|
||||
CHECK(semicolon, input, cursor, "Malformed print(). Missing `;` .");
|
||||
int64_t str_end = rfind_token(input, ')', semicolon);
|
||||
if (str_end < str_start) {
|
||||
CHECK(-1, input, cursor, "Malformed print(). Missing closing `)` .");
|
||||
}
|
||||
|
||||
std::stringstream sub_output;
|
||||
StringRef input_args = input.substr(str_start, str_end - str_start);
|
||||
|
||||
auto print_string = [&](std::string str) -> int {
|
||||
size_t len_before_pad = str.length();
|
||||
/* Pad string to uint size. */
|
||||
while (str.length() % 4 != 0) {
|
||||
str += " ";
|
||||
}
|
||||
/* Keep everything in one line to not mess with the shader logs. */
|
||||
sub_output << "/* " << str << "*/";
|
||||
sub_output << "drw_print_string_start(" << len_before_pad << ");";
|
||||
for (size_t i = 0; i < len_before_pad; i += 4) {
|
||||
uint8_t chars[4] = {*(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 0),
|
||||
*(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 1),
|
||||
*(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 2),
|
||||
*(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 3)};
|
||||
if (i + 4 > len_before_pad) {
|
||||
chars[len_before_pad - i] = '\0';
|
||||
}
|
||||
char uint_hex[12];
|
||||
SNPRINTF(uint_hex, "0x%.2X%.2X%.2X%.2Xu", chars[3], chars[2], chars[1], chars[0]);
|
||||
sub_output << "drw_print_char4(" << StringRefNull(uint_hex) << ");";
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
std::string func_args = input_args;
|
||||
/* Workaround to support function call inside prints. We replace commas by a non control
|
||||
* caracter $ in order to use simpler regex later. */
|
||||
bool string_scope = false;
|
||||
int func_scope = 0;
|
||||
for (char &c : func_args) {
|
||||
if (c == '"') {
|
||||
string_scope = !string_scope;
|
||||
}
|
||||
else if (!string_scope) {
|
||||
if (c == '(') {
|
||||
func_scope++;
|
||||
}
|
||||
else if (c == ')') {
|
||||
func_scope--;
|
||||
}
|
||||
else if (c == ',' && func_scope != 0) {
|
||||
c = '$';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool print_as_variable = (input_args[0] != '"') && find_token(input_args, ',') == -1;
|
||||
if (print_as_variable) {
|
||||
/* Variable or expression debuging. */
|
||||
std::string arg = input_args;
|
||||
/* Pad align most values. */
|
||||
while (arg.length() % 4 != 0) {
|
||||
arg += " ";
|
||||
}
|
||||
print_string(arg);
|
||||
print_string("= ");
|
||||
sub_output << "drw_print_value(" << input_args << ");";
|
||||
}
|
||||
else {
|
||||
const std::regex arg_regex(
|
||||
/* String args. */
|
||||
"[\\s]*\"([^\r\n\t\f\v\"]*)\""
|
||||
/* OR. */
|
||||
"|"
|
||||
/* value args. */
|
||||
"([^,]+)");
|
||||
std::smatch args_match;
|
||||
std::string::const_iterator args_search_start(func_args.cbegin());
|
||||
while (std::regex_search(args_search_start, func_args.cend(), args_match, arg_regex)) {
|
||||
args_search_start = args_match.suffix().first;
|
||||
std::string arg_string = args_match[1].str();
|
||||
std::string arg_val = args_match[2].str();
|
||||
|
||||
if (arg_string.empty()) {
|
||||
for (char &c : arg_val) {
|
||||
if (c == '$') {
|
||||
c = ',';
|
||||
}
|
||||
}
|
||||
sub_output << "drw_print_value(" << arg_val << ");";
|
||||
}
|
||||
else {
|
||||
print_string(arg_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_endl) {
|
||||
sub_output << "drw_print_newline();";
|
||||
}
|
||||
|
||||
output << sub_output.str();
|
||||
|
||||
cursor = last_pos = str_end + 1;
|
||||
}
|
||||
/* If nothing has been changed, do not allocate processed_source. */
|
||||
if (last_pos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename != "common_debug_print_lib.glsl") {
|
||||
builtins |= shader::BuiltinBits::USE_DEBUG_PRINT;
|
||||
}
|
||||
|
||||
if (last_pos != 0) {
|
||||
output << input.substr(last_pos);
|
||||
}
|
||||
processed_source = output.str();
|
||||
source = processed_source.c_str();
|
||||
}
|
||||
|
||||
#undef find_keyword
|
||||
#undef rfind_keyword
|
||||
#undef find_token
|
||||
@@ -537,6 +760,15 @@ struct GPUSource {
|
||||
this->dependencies_init = true;
|
||||
int64_t pos = -1;
|
||||
|
||||
using namespace shader;
|
||||
/* Auto dependency injection for debug capabilities. */
|
||||
if ((builtins & BuiltinBits::USE_DEBUG_DRAW) == BuiltinBits::USE_DEBUG_DRAW) {
|
||||
dependencies.append_non_duplicates(dict.lookup("common_debug_draw_lib.glsl"));
|
||||
}
|
||||
if ((builtins & BuiltinBits::USE_DEBUG_PRINT) == BuiltinBits::USE_DEBUG_PRINT) {
|
||||
dependencies.append_non_duplicates(dict.lookup("common_debug_print_lib.glsl"));
|
||||
}
|
||||
|
||||
while (true) {
|
||||
GPUSource *dependency_source = nullptr;
|
||||
|
||||
@@ -558,6 +790,7 @@ struct GPUSource {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursive. */
|
||||
int result = dependency_source->init_dependencies(dict, g_functions);
|
||||
if (result != 0) {
|
||||
@@ -583,7 +816,7 @@ struct GPUSource {
|
||||
|
||||
shader::BuiltinBits builtins_get() const
|
||||
{
|
||||
shader::BuiltinBits out_builtins = shader::BuiltinBits::NONE;
|
||||
shader::BuiltinBits out_builtins = builtins;
|
||||
for (auto *dep : dependencies) {
|
||||
out_builtins |= dep->builtins;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class ShaderInterface {
|
||||
/** Location of builtin uniforms. Fast access, no lookup needed. */
|
||||
int32_t builtins_[GPU_NUM_UNIFORMS];
|
||||
int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS];
|
||||
int32_t builtin_buffers_[GPU_NUM_STORAGE_BUFFERS];
|
||||
|
||||
public:
|
||||
ShaderInterface();
|
||||
@@ -116,9 +117,17 @@ class ShaderInterface {
|
||||
return builtin_blocks_[builtin];
|
||||
}
|
||||
|
||||
/* Returns binding position. */
|
||||
inline int32_t ssbo_builtin(const GPUStorageBufferBuiltin builtin) const
|
||||
{
|
||||
BLI_assert(builtin >= 0 && builtin < GPU_NUM_STORAGE_BUFFERS);
|
||||
return builtin_buffers_[builtin];
|
||||
}
|
||||
|
||||
protected:
|
||||
static inline const char *builtin_uniform_name(GPUUniformBuiltin u);
|
||||
static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u);
|
||||
static inline const char *builtin_storage_block_name(GPUStorageBufferBuiltin u);
|
||||
|
||||
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
|
||||
inline void copy_input_name(ShaderInput *input,
|
||||
@@ -212,6 +221,18 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *ShaderInterface::builtin_storage_block_name(GPUStorageBufferBuiltin u)
|
||||
{
|
||||
switch (u) {
|
||||
case GPU_STORAGE_BUFFER_DEBUG_VERTS:
|
||||
return "drw_debug_verts_buf";
|
||||
case GPU_STORAGE_BUFFER_DEBUG_PRINT:
|
||||
return "drw_debug_print_buf";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns string length including '\0' terminator. */
|
||||
inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
|
||||
char *name,
|
||||
|
||||
@@ -318,6 +318,13 @@ GLShaderInterface::GLShaderInterface(GLuint program)
|
||||
builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
|
||||
}
|
||||
|
||||
/* Builtin Storage Buffers */
|
||||
for (int32_t u_int = 0; u_int < GPU_NUM_STORAGE_BUFFERS; u_int++) {
|
||||
GPUStorageBufferBuiltin u = static_cast<GPUStorageBufferBuiltin>(u_int);
|
||||
const ShaderInput *block = this->ssbo_get(builtin_storage_block_name(u));
|
||||
builtin_buffers_[u] = (block != nullptr) ? block->binding : -1;
|
||||
}
|
||||
|
||||
MEM_freeN(uniforms_from_blocks);
|
||||
|
||||
/* Resize name buffer to save some memory. */
|
||||
@@ -481,6 +488,13 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
|
||||
builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
|
||||
}
|
||||
|
||||
/* Builtin Storage Buffers */
|
||||
for (int32_t u_int = 0; u_int < GPU_NUM_STORAGE_BUFFERS; u_int++) {
|
||||
GPUStorageBufferBuiltin u = static_cast<GPUStorageBufferBuiltin>(u_int);
|
||||
const ShaderInput *block = this->ssbo_get(builtin_storage_block_name(u));
|
||||
builtin_buffers_[u] = (block != nullptr) ? block->binding : -1;
|
||||
}
|
||||
|
||||
this->sort_inputs();
|
||||
|
||||
// this->debug_print();
|
||||
|
||||
Reference in New Issue
Block a user