summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd/shaders
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2022-09-30 09:59:45 +0200
committerRémi Verschelde <rverschelde@gmail.com>2022-09-30 09:59:45 +0200
commit67961d875d518b565bc1fa923772af56fb227063 (patch)
tree852e3c083882e2dcec3942cf99b5a0a652762e65 /servers/rendering/renderer_rd/shaders
parent300befdc9e0fbe8d119f01f00b1bb8c69c3ccdb4 (diff)
parent27a3014f5052ae40f89684a5559c17fbebe7aa8d (diff)
Merge pull request #66178 from clayjohn/double-precision-rendering
Emulate double precision for regular rendering operation when REAL_T_IS_DOUBLE
Diffstat (limited to 'servers/rendering/renderer_rd/shaders')
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl81
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl80
2 files changed, 153 insertions, 8 deletions
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index d41474118d..adc4d9d01e 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -129,12 +129,52 @@ invariant gl_Position;
#GLOBALS
+#ifdef USE_DOUBLE_PRECISION
+// Helper functions for emulating double precision when adding floats.
+vec3 quick_two_sum(vec3 a, vec3 b, out vec3 out_p) {
+ vec3 s = a + b;
+ out_p = b - (s - a);
+ return s;
+}
+
+vec3 two_sum(vec3 a, vec3 b, out vec3 out_p) {
+ vec3 s = a + b;
+ vec3 v = s - a;
+ out_p = (a - (s - v)) + (b - v);
+ return s;
+}
+
+vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec3 out_precision) {
+ vec3 s, t, se, te;
+ s = two_sum(base_a, base_b, se);
+ t = two_sum(prec_a, prec_b, te);
+ se += t;
+ s = quick_two_sum(s, se, se);
+ se += te;
+ s = quick_two_sum(s, se, out_precision);
+ return s;
+}
+#endif
+
void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
#endif
+ mat4 inv_view_matrix = scene_data.inv_view_matrix;
+
+#ifdef USE_DOUBLE_PRECISION
+ vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
+ model_matrix[0][3] = 0.0;
+ model_matrix[1][3] = 0.0;
+ model_matrix[2][3] = 0.0;
+ vec3 view_precision = vec3(inv_view_matrix[0][3], inv_view_matrix[1][3], inv_view_matrix[2][3]);
+ inv_view_matrix[0][3] = 0.0;
+ inv_view_matrix[1][3] = 0.0;
+ inv_view_matrix[2][3] = 0.0;
+#endif
+
mat3 model_normal_matrix;
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
@@ -142,11 +182,12 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
model_normal_matrix = mat3(model_matrix);
}
+ mat4 matrix;
+ mat4 read_model_matrix = model_matrix;
+
if (is_multimesh) {
//multimesh, instances are for it
- mat4 matrix;
-
#ifdef USE_PARTICLE_TRAILS
uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
uint stride = 3 + 1 + 1; //particles always uses this format
@@ -232,7 +273,14 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
#endif
//transpose
matrix = transpose(matrix);
- model_matrix = model_matrix * matrix;
+#if !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED) || defined(MODEL_MATRIX_USED)
+ // Normally we can bake the multimesh transform into the model matrix, but when using double precision
+ // we avoid baking it in so we can emulate high precision.
+ read_model_matrix = model_matrix * matrix;
+#if !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED)
+ model_matrix = read_model_matrix;
+#endif // !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED)
+#endif // !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED) || defined(MODEL_MATRIX_USED)
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
@@ -297,7 +345,22 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
// using local coordinates (default)
#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
+#ifdef USE_DOUBLE_PRECISION
+ // We separate the basis from the origin becasue the basis is fine with single point precision.
+ // Then we combine the translations from the model matrix and the view matrix using emulated doubles.
+ // We add the result to the vertex and ignore the final lost precision.
+ vec3 model_origin = model_matrix[3].xyz;
+ if (is_multimesh) {
+ vertex = mat3(matrix) * vertex;
+ model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
+ }
+ vertex = mat3(model_matrix) * vertex;
+ vec3 temp_precision; // Will be ignored.
+ vertex += double_add_vec3(model_origin, model_precision, scene_data.inv_view_matrix[3].xyz, view_precision, temp_precision);
+ vertex = mat3(scene_data.view_matrix) * vertex;
+#else
vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#endif
#ifdef NORMAL_USED
normal = modelview_normal * normal;
#endif
@@ -490,7 +553,6 @@ layout(location = 10) in flat uint instance_index_interp;
//defines to keep compatibility with vertex
-#define model_matrix instances.data[draw_call.instance_index].transform
#ifdef USE_MULTIVIEW
#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
#define inv_projection_matrix scene_data.inv_projection_matrix_view[ViewIndex]
@@ -737,6 +799,17 @@ void fragment_shader(in SceneData scene_data) {
vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
#endif // ALPHA_ANTIALIASING_EDGE_USED
+ mat4 inv_view_matrix = scene_data.inv_view_matrix;
+ mat4 read_model_matrix = instances.data[instance_index].transform;
+#ifdef USE_DOUBLE_PRECISION
+ read_model_matrix[0][3] = 0.0;
+ read_model_matrix[1][3] = 0.0;
+ read_model_matrix[2][3] = 0.0;
+ inv_view_matrix[0][3] = 0.0;
+ inv_view_matrix[1][3] = 0.0;
+ inv_view_matrix[2][3] = 0.0;
+#endif
+
{
#CODE : FRAGMENT
}
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index a109fd4d75..4e5c5b6c5b 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -123,6 +123,33 @@ invariant gl_Position;
#define scene_data scene_data_block.data
+#ifdef USE_DOUBLE_PRECISION
+// Helper functions for emulating double precision when adding floats.
+vec3 quick_two_sum(vec3 a, vec3 b, out vec3 out_p) {
+ vec3 s = a + b;
+ out_p = b - (s - a);
+ return s;
+}
+
+vec3 two_sum(vec3 a, vec3 b, out vec3 out_p) {
+ vec3 s = a + b;
+ vec3 v = s - a;
+ out_p = (a - (s - v)) + (b - v);
+ return s;
+}
+
+vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec3 out_precision) {
+ vec3 s, t, se, te;
+ s = two_sum(base_a, base_b, se);
+ t = two_sum(prec_a, prec_b, te);
+ se += t;
+ s = quick_two_sum(s, se, se);
+ se += te;
+ s = quick_two_sum(s, se, out_precision);
+ return s;
+}
+#endif
+
void main() {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
@@ -132,6 +159,17 @@ void main() {
bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH);
mat4 model_matrix = draw_call.transform;
+ mat4 inv_view_matrix = scene_data.inv_view_matrix;
+#ifdef USE_DOUBLE_PRECISION
+ vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
+ model_matrix[0][3] = 0.0;
+ model_matrix[1][3] = 0.0;
+ model_matrix[2][3] = 0.0;
+ vec3 view_precision = vec3(inv_view_matrix[0][3], inv_view_matrix[1][3], inv_view_matrix[2][3]);
+ inv_view_matrix[0][3] = 0.0;
+ inv_view_matrix[1][3] = 0.0;
+ inv_view_matrix[2][3] = 0.0;
+#endif
mat3 model_normal_matrix;
if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
@@ -140,11 +178,12 @@ void main() {
model_normal_matrix = mat3(model_matrix);
}
+ mat4 matrix;
+ mat4 read_model_matrix = model_matrix;
+
if (is_multimesh) {
//multimesh, instances are for it
- mat4 matrix;
-
#ifdef USE_PARTICLE_TRAILS
uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
uint stride = 3 + 1 + 1; //particles always uses this format
@@ -230,7 +269,15 @@ void main() {
#endif
//transpose
matrix = transpose(matrix);
- model_matrix = model_matrix * matrix;
+
+#if !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED) || defined(MODEL_MATRIX_USED)
+ // Normally we can bake the multimesh transform into the model matrix, but when using double precision
+ // we avoid baking it in so we can emulate high precision.
+ read_model_matrix = model_matrix * matrix;
+#if !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED)
+ model_matrix = read_model_matrix;
+#endif // !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED)
+#endif // !defined(USE_DOUBLE_PRECISION) || defined(SKIP_TRANSFORM_USED) || defined(VERTEX_WORLD_COORDS_USED) || defined(MODEL_MATRIX_USED)
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
@@ -297,7 +344,22 @@ void main() {
// using local coordinates (default)
#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
+#ifdef USE_DOUBLE_PRECISION
+ // We separate the basis from the origin becasue the basis is fine with single point precision.
+ // Then we combine the translations from the model matrix and the view matrix using emulated doubles.
+ // We add the result to the vertex and ignore the final lost precision.
+ vec3 model_origin = model_matrix[3].xyz;
+ if (is_multimesh) {
+ vertex = mat3(matrix) * vertex;
+ model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
+ }
+ vertex = mat3(model_matrix) * vertex;
+ vec3 temp_precision;
+ vertex += double_add_vec3(model_origin, model_precision, scene_data.inv_view_matrix[3].xyz, view_precision, temp_precision);
+ vertex = mat3(scene_data.view_matrix) * vertex;
+#else
vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#endif
#ifdef NORMAL_USED
normal = modelview_normal * normal;
#endif
@@ -468,7 +530,6 @@ layout(location = 9) highp in float dp_clip;
//defines to keep compatibility with vertex
-#define model_matrix draw_call.transform
#ifdef USE_MULTIVIEW
#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
#define inv_projection_matrix scene_data.inv_projection_matrix_view[ViewIndex]
@@ -685,6 +746,17 @@ void main() {
vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
#endif // ALPHA_ANTIALIASING_EDGE_USED
+ mat4 inv_view_matrix = scene_data.inv_view_matrix;
+ mat4 read_model_matrix = draw_call.transform;
+#ifdef USE_DOUBLE_PRECISION
+ read_model_matrix[0][3] = 0.0;
+ read_model_matrix[1][3] = 0.0;
+ read_model_matrix[2][3] = 0.0;
+ inv_view_matrix[0][3] = 0.0;
+ inv_view_matrix[1][3] = 0.0;
+ inv_view_matrix[2][3] = 0.0;
+#endif
+
{
#CODE : FRAGMENT
}