Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-02-09 13:21:18 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-02-09 13:34:54 +0300
commita02eee7e98632bc1d604bb2ef69d504bd3d1b4f2 (patch)
tree72b7afd4fa254ccc411470468e38685e6064a76b
parent4205629ea241c1332966bbe0372ea231fd689f4b (diff)
DRW: Add new draw_debug_print_lib.glsl
This lib allows any shader to use `print()` like functions for logging and debugging shaders. Usage is described in the comment at the top of the file.
-rw-r--r--source/blender/draw/CMakeLists.txt4
-rw-r--r--source/blender/draw/intern/draw_debug.c62
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_data.c25
-rw-r--r--source/blender/draw/intern/draw_shader.c10
-rw-r--r--source/blender/draw/intern/draw_shader.h1
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h6
-rw-r--r--source/blender/draw/intern/shaders/common_debug_print_lib.glsl379
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl3
-rw-r--r--source/blender/draw/intern/shaders/draw_debug_info.hh25
-rw-r--r--source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl133
-rw-r--r--source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl27
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_shader.h3
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc190
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh2
16 files changed, 871 insertions, 2 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index def6ebb7773..4cba8e5320c 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -415,6 +415,7 @@ set(GLSL_SRC
intern/shaders/common_attribute_lib.glsl
intern/shaders/common_colormanagement_lib.glsl
intern/shaders/common_debug_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
@@ -444,6 +445,9 @@ set(GLSL_SRC
intern/shaders/common_subdiv_vbo_lnor_comp.glsl
intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
+ intern/shaders/draw_debug_print_display_vert.glsl
+ intern/shaders/draw_debug_print_display_frag.glsl
+
intern/draw_shader_shared.h
engines/gpencil/shaders/gpencil_frag.glsl
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index dad71539c9f..bd3dcddee91 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -30,10 +30,14 @@
#include "BLI_link_utils.h"
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
#include "GPU_immediate.h"
+#include "GPU_uniform_buffer.h"
#include "draw_debug.h"
#include "draw_manager.h"
+#include "draw_shader.h"
/* --------- Register --------- */
@@ -149,8 +153,9 @@ void DRW_debug_sphere(const float center[3], const float radius, const float col
/* --------- Indirect Rendering --------- */
-/* Keep in sync with shader. */
+/* Keep in sync with shaders. */
#define DEBUG_VERT_MAX 16 * 4096
+#define DRW_DEBUG_PRINT_MAX 4096
static GPUVertFormat *debug_buf_format(void)
{
@@ -185,6 +190,25 @@ GPUVertBuf *drw_debug_line_buffer_get()
return buf->verts;
}
+GPUVertBuf *drw_debug_print_buffer_get()
+{
+ if (!DST.debug.print_buffer) {
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "char_data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *char_buf = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(char_buf, DRW_DEBUG_PRINT_MAX);
+
+ uint *data = GPU_vertbuf_get_data(char_buf);
+ memset(data, 0, sizeof(*data) * DRW_DEBUG_PRINT_MAX);
+
+ DST.debug.print_buffer = char_buf;
+ }
+ return DST.debug.print_buffer;
+}
+
/* --------- Render --------- */
static void drw_debug_draw_lines(void)
@@ -293,11 +317,47 @@ static void drw_debug_draw_buffers(void)
}
}
+static void drw_debug_draw_print(void)
+{
+ if (!GPU_compute_shader_support() || DST.debug.print_buffer == NULL) {
+ return;
+ }
+
+ {
+ /* Display the characters. */
+ GPUUniformBuf *view_ubo = G_draw.view_ubo;
+
+ GPUShader *sh = DRW_shader_debug_print_display_get();
+ GPUBatch *batch = GPU_batch_create_ex(
+ GPU_PRIM_POINTS, DST.debug.print_buffer, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_set_shader(batch, sh);
+
+ eGPUBlend blend = GPU_blend_get();
+
+ GPU_blend(GPU_BLEND_ALPHA_PREMULT);
+ GPU_program_point_size(true);
+ GPU_uniformbuf_bind(view_ubo, GPU_shader_get_builtin_block(sh, GPU_UNIFORM_BLOCK_DRW_VIEW));
+
+ /* Wait for all writting jobs */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ GPU_batch_draw(batch);
+ GPU_batch_discard(batch);
+ /* Freed, with the batch. */
+ DST.debug.print_buffer = NULL;
+
+ GPU_uniformbuf_unbind(G_draw.view_ubo);
+ GPU_program_point_size(false);
+ GPU_blend(blend);
+ }
+}
+
void drw_debug_draw(void)
{
drw_debug_draw_lines();
drw_debug_draw_spheres();
drw_debug_draw_buffers();
+ drw_debug_draw_print();
}
void drw_debug_init(void)
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 1f3fb42fecc..7d97ec9a44b 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -657,6 +657,7 @@ typedef struct DRWManager {
DRWDebugLine *lines;
DRWDebugSphere *spheres;
DRWDebugBuffer *line_buffers;
+ GPUVertBuf *print_buffer;
} debug;
} DRWManager;
@@ -671,6 +672,7 @@ void *drw_viewport_engine_data_ensure(void *engine_type);
void drw_state_set(DRWState state);
GPUVertBuf *drw_debug_line_buffer_get(void);
+GPUVertBuf *drw_debug_print_buffer_get(void);
void drw_debug_draw(void);
void drw_debug_init(void);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 3afc516a817..b69ce70e046 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -22,6 +22,7 @@
#include "draw_manager.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_duplilist.h"
#include "BKE_global.h"
@@ -31,6 +32,9 @@
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "WM_api.h"
+#include "wm_window.h"
+
#include "DNA_curve_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
@@ -54,6 +58,9 @@
#include "intern/gpu_codegen.h"
+/* We add */
+//#define DISABLE_DEBUG_SHADER_PRINT_BARRIER
+
/* -------------------------------------------------------------------- */
/** \name Uniform Buffer Object (DRW_uniformbuffer)
* \{ */
@@ -1473,6 +1480,17 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
GPUVertBuf *vertbuf = drw_debug_line_buffer_get();
drw_shgroup_uniform_create_ex(
shgroup, debugbuf_location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, vertbuf, 0, 0, 1);
+
+ int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_BUFFER_BLOCK_DEBUG_PRINT);
+ if (debug_print_location != -1) {
+ GPUVertBuf *vertbuf = drw_debug_print_buffer_get();
+ drw_shgroup_uniform_create_ex(
+ shgroup, debug_print_location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, vertbuf, 0, 0, 1);
+ /* Add a barrier to allow multiple shader writting to the same buffer. */
+# ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER
+ /** IMPORTANT: This might change the application behavior. Comment if needed. */
+ DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE);
+# endif
}
#endif
@@ -1968,6 +1986,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;
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c
index 28ac76ccd7f..018e095529a 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.c
@@ -39,6 +39,7 @@ extern 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;
} e_data = {{NULL}};
/* -------------------------------------------------------------------- */
@@ -107,6 +108,14 @@ GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
return e_data.hair_refine_sh[refinement];
}
+GPUShader *DRW_shader_debug_print_display_get()
+{
+ if (e_data.debug_print_display_sh == NULL) {
+ e_data.debug_print_display_sh = GPU_shader_create_from_info_name("draw_debug_print_display");
+ }
+ return e_data.debug_print_display_sh;
+}
+
/** \} */
void DRW_shaders_free(void)
@@ -114,4 +123,5 @@ void DRW_shaders_free(void)
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);
}
diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h
index f9fa452671b..17b4243b956 100644
--- a/source/blender/draw/intern/draw_shader.h
+++ b/source/blender/draw/intern/draw_shader.h
@@ -40,6 +40,7 @@ typedef enum eParticleRefineShaderType {
/* draw_shader.c */
struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type);
+struct GPUShader *DRW_shader_debug_print_display_get(void);
void DRW_shaders_free(void);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index a73cb4ad5b6..c54d81a552a 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -32,6 +32,12 @@ struct ViewInfos {
/** NOTE: vec3 arrays are paded 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)
diff --git a/source/blender/draw/intern/shaders/common_debug_print_lib.glsl b/source/blender/draw/intern/shaders/common_debug_print_lib.glsl
new file mode 100644
index 00000000000..ade2d4cb2c4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_debug_print_lib.glsl
@@ -0,0 +1,379 @@
+
+/**
+ * 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.")`.
+ * `print_no_endl()`:
+ * Same as `print()` but does not finish the line.
+ * `print_value()`:
+ * Display only the value of a variable. Does not finish the line.
+ * `print_value_hex()`:
+ * Display only the hex representation of a variable. Does not finish the line.
+ * `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 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_PRINT_BARRIER to remove the barriers if that happens.
+ * But then you are limited to a single invocation output.
+ */
+
+#ifndef DRAW_DEBUG_PRINT_DATA
+/* Comment that out if you want to debug a library included in multiply shader.
+ * Then use DRAW_DEBUG_PRINT_DATA to check if the print buffer is present. */
+// # error "Missing draw_debug_print additional create info on shader create info"
+#else
+
+/* Vertex shader discards the first 3 vertex. */
+# define print_row drw_print_buf[0]
+# define print_col drw_print_buf[1]
+# define print_cursor drw_print_buf[2]
+
+# define DRW_DEBUG_PRINT_MAX 4096
+
+# define PRINT_WORD_WRAP_COLUMN 80u
+
+void print_newline()
+{
+ atomicExchange(print_col, 0u);
+ atomicAdd(print_row, 1u);
+}
+
+void print_string_start(uint len)
+{
+ /* Break before word. */
+ if (print_col + len > PRINT_WORD_WRAP_COLUMN) {
+ print_newline();
+ }
+}
+
+void 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;
+ }
+ uint cursor = atomicAdd(print_cursor, 1u) + 3;
+ if (cursor < DRW_DEBUG_PRINT_MAX) {
+ /* For future usage. (i.e: Color) */
+ uint flags = 0u;
+ uint col = atomicAdd(print_col, 1u);
+ uint print_header = (flags << 24u) | (print_row << 16u) | (col << 8u);
+ drw_print_buf[cursor] = print_header | char1;
+ /* Break word. */
+ if (print_col > PRINT_WORD_WRAP_COLUMN) {
+ 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 print_append_char(uint char1, inout uint char4)
+{
+ char4 = (char4 << 8u) | char1;
+}
+
+void print_append_digit(uint digit, inout uint char4)
+{
+ char4 = (char4 << 8u) | ((digit > 9u) ? 0x41u - 10u : 0x30u) + digit;
+}
+
+void print_append_space(inout uint char4)
+{
+ char4 = (char4 << 8u) | 0x20u;
+}
+
+void print_value_binary(uint value)
+{
+ print_no_endl("0b");
+ print_string_start(10u * 4u);
+ uint digits[10] = array(uint)(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 print_value_binary(int value)
+{
+ print_value_binary(uint(value));
+}
+
+void print_value_binary(float value)
+{
+ print_value_binary(floatBitsToUint(value));
+}
+
+void 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] = array(uint)(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]);
+ }
+}
+
+void print_value_hex(uint value)
+{
+ print_value_uint(value, true, false, false);
+}
+
+void print_value_hex(int value)
+{
+ print_value_uint(uint(value), true, false, false);
+}
+
+void print_value_hex(float value)
+{
+ print_value_uint(floatBitsToUint(value), true, false, false);
+}
+
+void print_value(uint value)
+{
+ print_value_uint(value, false, false, true);
+}
+
+void print_value(int value)
+{
+ print_value_uint(uint(abs(value)), false, (value < 0), false);
+}
+
+void print_value(bool value)
+{
+ if (value) {
+ print_no_endl("true ");
+ }
+ else {
+ 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 print_value_hex and transcribe the
+ * value manually with another tool. */
+void print_value(float val)
+{
+ /* We pad the string to match normal float values length. */
+ if (isnan(val)) {
+ print_no_endl(" NaN");
+ return;
+ }
+ if (isinf(val)) {
+ if (sign(val) < 0.0) {
+ print_no_endl(" -Inf");
+ }
+ else {
+ 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;
+ print_string_start(3u * 4u);
+ uint digits[3] = array(uint)(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) {
+ print_append_digit(value % base, digits[digit / 4u]);
+ digit++;
+ }
+ /* Exponent sign. */
+ uint sign_char = (exponent < 0.0) ? '-' : '+';
+ print_append_char(sign_char, digits[digit / 4u]);
+ digit++;
+ /* Exponent `e` suffix. */
+ 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) {
+ print_append_digit(value % base, digits[digit / 4u]);
+ digit++;
+ }
+ /* Point separator. */
+ 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) {
+ print_append_digit(value % base, digits[digit / 4u]);
+ digit++;
+ }
+ /* Negative sign. */
+ if (val < 0.0) {
+ 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]);
+ }
+}
+
+void print_value(vec2 value)
+{
+ print_no_endl("vec2(", value[0], ", ", value[1], ")");
+}
+
+void print_value(vec3 value)
+{
+ print_no_endl("vec3(", value[0], ", ", value[1], ", ", value[1], ")");
+}
+
+void print_value(vec4 value)
+{
+ print_no_endl("vec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
+}
+
+void print_value(ivec2 value)
+{
+ print_no_endl("ivec2(", value[0], ", ", value[1], ")");
+}
+
+void print_value(ivec3 value)
+{
+ print_no_endl("ivec3(", value[0], ", ", value[1], ", ", value[1], ")");
+}
+
+void print_value(ivec4 value)
+{
+ print_no_endl("ivec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
+}
+
+void print_value(uvec2 value)
+{
+ print_no_endl("uvec2(", value[0], ", ", value[1], ")");
+}
+
+void print_value(uvec3 value)
+{
+ print_no_endl("uvec3(", value[0], ", ", value[1], ", ", value[1], ")");
+}
+
+void print_value(uvec4 value)
+{
+ print_no_endl("uvec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
+}
+
+void print_value(bvec2 value)
+{
+ print_no_endl("bvec2(", value[0], ", ", value[1], ")");
+}
+
+void print_value(bvec3 value)
+{
+ print_no_endl("bvec3(", value[0], ", ", value[1], ", ", value[1], ")");
+}
+
+void print_value(bvec4 value)
+{
+ print_no_endl("bvec4(", value[0], ", ", value[1], ", ", value[2], ", ", value[3], ")");
+}
+
+#endif
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index c1a65f6b261..3eb519d1851 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -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)
diff --git a/source/blender/draw/intern/shaders/draw_debug_info.hh b/source/blender/draw/intern/shaders/draw_debug_info.hh
new file mode 100644
index 00000000000..2d170840830
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_debug_info.hh
@@ -0,0 +1,25 @@
+
+#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)
+ .define("DRAW_DEBUG_PRINT_DATA")
+ .storage_buf(15, Qualifier::READ_WRITE, "uint", "drw_print_buf[]", Frequency::PASS);
+
+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)
+ .vertex_in(0, Type::UINT, "char_data")
+ .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");
+
+/** \} */
diff --git a/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl b/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl
new file mode 100644
index 00000000000..83179c80da6
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl
@@ -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] = array(uvec2)(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);
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl b/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl
new file mode 100644
index 00000000000..61404bf7f7a
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl
@@ -0,0 +1,27 @@
+
+/**
+ * Display characters using an ascii table. Outputs one point per character.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+void main()
+{
+ char_index = (char_data & 0xFFu) - 0x20u;
+
+ /* Discard invalid chars and the first 3 vertex containing header data. */
+ if (char_index >= 96u || gl_VertexID < 3) {
+ 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;
+} \ No newline at end of file
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 13522f049e8..f1283ff6407 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -424,6 +424,7 @@ set(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_object_infos_info.hh
../draw/intern/shaders/draw_view_info.hh
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 8dacc1e09be..846bda07127 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -164,7 +164,8 @@ typedef enum {
} GPUUniformBlockBuiltin;
typedef enum {
- GPU_BUFFER_BLOCK_DEBUG = 0, /* debugBuf */
+ GPU_BUFFER_BLOCK_DEBUG = 0, /* debugBuf */
+ GPU_BUFFER_BLOCK_DEBUG_PRINT, /* drw_print_buf */
GPU_NUM_BUFFER_BLOCKS, /* Special value, denotes number of builtin buffer blocks. */
} GPUBufferBlockBuiltin;
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 267acb27072..61a732932eb 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -26,6 +26,7 @@
#include <iostream>
#include <regex>
+#include <sstream>
#include "BLI_ghash.h"
#include "BLI_map.hh"
@@ -112,6 +113,14 @@ struct GPUSource {
enum_preprocess();
}
+ if (source.find("'")) {
+ char_literals_preprocess();
+ }
+
+ if (source.find("print")) {
+ string_preprocess();
+ }
+
if (is_from_material_library()) {
material_functions_parse(g_functions);
}
@@ -445,6 +454,187 @@ 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 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, "print", cursor + 1);
+ if (cursor == -1) {
+ break;
+ }
+
+ bool do_endl = false;
+ StringRef func = input.substr(cursor);
+ if (func.startswith("print(")) {
+ do_endl = true;
+ }
+ else if (func.startswith("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 << "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 << "print_char4(" << StringRefNull(uint_hex) << ");";
+ }
+ return 0;
+ };
+
+ 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 << "print_value(" << input_args << ");";
+ }
+ else {
+ const std::regex arg_regex(
+ /* String args. */
+ "\"([^\\r\\n\\t\\f\\v\"]+)\""
+ /* OR. */
+ "|"
+ /* value args. */
+ "[\\s]+([^\\r\\n\\t\\f\\v\"]+),");
+ std::smatch args_match;
+ std::string func_args = input_args;
+ 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()) {
+ sub_output << "print_value(" << arg_val << ");";
+ }
+ else {
+ print_string(arg_string);
+ }
+ }
+ }
+
+ if (do_endl) {
+ sub_output << "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 (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
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index f23c9ac03eb..9de41873229 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -241,6 +241,8 @@ inline const char *ShaderInterface::builtin_buffer_block_name(GPUBufferBlockBuil
switch (u) {
case GPU_BUFFER_BLOCK_DEBUG:
return "debugBuf";
+ case GPU_BUFFER_BLOCK_DEBUG_PRINT:
+ return "drw_print_buf";
default:
return NULL;
}