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:
2022-08-08 19:01:38 +02:00
committed by Clément Foucault
parent 2e4727e123
commit f6639cc4fc
28 changed files with 2247 additions and 244 deletions

View File

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

View File

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

View File

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

View 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);
}
/** \} */

View File

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

View 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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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);
}
/** \} */

View 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], ")");
}

View File

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

View File

@@ -0,0 +1,9 @@
/**
* Display debug edge list.
**/
void main()
{
out_color = interp.color;
}

View File

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

View 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");
/** \} */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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