From 23c375d6b4f6e10690906e07a7e50ec53260d440 Mon Sep 17 00:00:00 2001 From: bitsawer Date: Wed, 15 Mar 2023 08:40:06 +0200 Subject: [PATCH] Fix shader uniform storage conversions and crash --- drivers/gles3/storage/material_storage.cpp | 637 +++-------------- editor/shader_globals_editor.cpp | 46 +- scene/main/shader_globals_override.cpp | 6 +- scene/resources/material.cpp | 28 +- .../storage_rd/material_storage.cpp | 655 +++--------------- servers/rendering/shader_language.cpp | 14 +- .../rendering/storage/variant_converters.h | 322 +++++++++ 7 files changed, 560 insertions(+), 1148 deletions(-) create mode 100644 servers/rendering/storage/variant_converters.h diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index d92c1b94ae8..d246c47b6a7 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -39,32 +39,24 @@ #include "drivers/gles3/rasterizer_canvas_gles3.h" #include "drivers/gles3/rasterizer_gles3.h" +#include "servers/rendering/storage/variant_converters.h" using namespace GLES3; /////////////////////////////////////////////////////////////////////////// // UBI helper functions -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data) { +static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data) { switch (type) { case ShaderLanguage::TYPE_BOOL: { uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = (r[i] != 0) ? 1 : 0; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored + PackedInt32Array ba = value; + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { bool v = value; gui[0] = v ? 1 : 0; @@ -74,22 +66,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 2 * p_array_size; - - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i] ? 1 : 0; - gui[j + 1] = r[i + 1] ? 1 : 0; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = v & 1 ? 1 : 0; @@ -100,23 +81,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 3 * p_array_size; - - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i] ? 1 : 0; - gui[j + 1] = r[i + 1] ? 1 : 0; - gui[j + 2] = r[i + 2] ? 1 : 0; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = (v & 1) ? 1 : 0; @@ -128,24 +97,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 4 * p_array_size; - - for (int i = 0; i < count; i += 4) { - if (i < s) { - gui[i] = r[i] ? 1 : 0; - gui[i + 1] = r[i + 1] ? 1 : 0; - gui[i + 2] = r[i + 2] ? 1 : 0; - gui[i + 3] = r[i + 3] ? 1 : 0; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = (v & 1) ? 1 : 0; @@ -158,20 +114,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int32_t *gui = (int32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - const int *r = iv.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = r[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = value; + write_array_std140(iv, gui, p_array_size, 4); } else { int v = value; gui[0] = v; @@ -179,25 +123,12 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_IVEC2: { int32_t *gui = (int32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 2 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector2i v = value; + Vector2i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } @@ -206,25 +137,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int32_t *gui = (int32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 3 * p_array_size; - - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - gui[j + 2] = r[i + 2]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector3i v = value; + Vector3i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -234,26 +150,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int32_t *gui = (int32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 4 * p_array_size; - - const int *r = iv.ptr(); - for (int i = 0; i < count; i += 4) { - if (i < s) { - gui[i] = r[i]; - gui[i + 1] = r[i + 1]; - gui[i + 2] = r[i + 2]; - gui[i + 3] = r[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector4i v = value; + Vector4i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -264,20 +164,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - const int *r = iv.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = r[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = value; + write_array_std140(iv, gui, p_array_size, 4); } else { int v = value; gui[0] = v; @@ -285,25 +173,12 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_UVEC2: { uint32_t *gui = (uint32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 2 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector2i v = value; + Vector2i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } @@ -312,25 +187,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 3 * p_array_size; - - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - gui[j + 2] = r[i + 2]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector3i v = value; + Vector3i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -340,26 +200,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 4 * p_array_size; - - const int *r = iv.ptr(); - for (int i = 0; i < count; i++) { - if (i < s) { - gui[i] = r[i]; - gui[i + 1] = r[i + 1]; - gui[i + 2] = r[i + 2]; - gui[i + 3] = r[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector4i v = value; + Vector4i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -371,18 +215,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy if (p_array_size > 0) { const PackedFloat32Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + write_array_std140(a, gui, p_array_size, 4); } else { float v = value; gui[0] = v; @@ -392,22 +225,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = (float *)data; if (p_array_size > 0) { - const PackedVector2Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i].x; - gui[j + 1] = a[i].y; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 4); } else { - Vector2 v = value; + Vector2 v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } @@ -416,133 +237,27 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = (float *)data; if (p_array_size > 0) { - if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { - const PackedColorArray &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - Color color = a[i]; - gui[j] = color.r; - gui[j + 1] = color.g; - gui[j + 2] = color.b; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } - } else { - const PackedVector3Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i].x; - gui[j + 1] = a[i].y; - gui[j + 2] = a[i].z; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } - } + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 4); } else { - if (value.get_type() == Variant::COLOR) { - Color v = value; - - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - } else { - Vector3 v = value; - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - } + Vector3 v = convert_to_vector(value); + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; } } break; case ShaderLanguage::TYPE_VEC4: { float *gui = (float *)data; if (p_array_size > 0) { - if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { - const PackedColorArray &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - Color color = a[i]; - gui[j] = color.r; - gui[j + 1] = color.g; - gui[j + 2] = color.b; - gui[j + 3] = color.a; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - gui[j + 3] = 0; - } - } - } else { - const PackedFloat32Array &a = value; - int s = a.size(); - int count = 4 * p_array_size; - - for (int i = 0; i < count; i += 4) { - if (i + 3 < s) { - gui[i] = a[i]; - gui[i + 1] = a[i + 1]; - gui[i + 2] = a[i + 2]; - gui[i + 3] = a[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } - } + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 4); } else { - if (value.get_type() == Variant::COLOR) { - Color v = value; - - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - gui[3] = v.a; - } else if (value.get_type() == Variant::RECT2) { - Rect2 v = value; - - gui[0] = v.position.x; - gui[1] = v.position.y; - gui[2] = v.size.x; - gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUATERNION) { - Quaternion v = value; - - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else if (value.get_type() == Variant::VECTOR4) { - Vector4 v = value; - - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else { - Plane v = value; - - gui[0] = v.normal.x; - gui[1] = v.normal.y; - gui[2] = v.normal.z; - gui[3] = v.d; - } + Vector4 v = convert_to_vector(value); + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + gui[3] = v.w; } } break; case ShaderLanguage::TYPE_MAT2: { @@ -590,135 +305,42 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = (float *)data; if (p_array_size > 0) { - const PackedFloat32Array &a = value; - int s = a.size(); + const PackedFloat32Array &a = convert_array_std140(value); + const Basis default_basis; + const int s = a.size(); for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) { if (i + 8 < s) { gui[j] = a[i]; gui[j + 1] = a[i + 1]; gui[j + 2] = a[i + 2]; + gui[j + 3] = 0; // Ignored. gui[j + 4] = a[i + 3]; gui[j + 5] = a[i + 4]; gui[j + 6] = a[i + 5]; + gui[j + 7] = 0; // Ignored. gui[j + 8] = a[i + 6]; gui[j + 9] = a[i + 7]; gui[j + 10] = a[i + 8]; + gui[j + 11] = 0; // Ignored. } else { - gui[j] = 1; - gui[j + 1] = 0; - gui[j + 2] = 0; - - gui[j + 4] = 0; - gui[j + 5] = 1; - gui[j + 6] = 0; - - gui[j + 8] = 0; - gui[j + 9] = 0; - gui[j + 10] = 1; + convert_item_std140(default_basis, gui + j); } - gui[j + 3] = 0; // ignored - gui[j + 7] = 0; // ignored - gui[j + 11] = 0; // ignored } } else { - Basis v = value; - gui[0] = v.rows[0][0]; - gui[1] = v.rows[1][0]; - gui[2] = v.rows[2][0]; - gui[3] = 0; // ignored - - gui[4] = v.rows[0][1]; - gui[5] = v.rows[1][1]; - gui[6] = v.rows[2][1]; - gui[7] = 0; // ignored - - gui[8] = v.rows[0][2]; - gui[9] = v.rows[1][2]; - gui[10] = v.rows[2][2]; - gui[11] = 0; // ignored + convert_item_std140(value, gui); } } break; case ShaderLanguage::TYPE_MAT4: { float *gui = (float *)data; if (p_array_size > 0) { - const PackedFloat32Array &a = value; - int s = a.size(); - - for (int i = 0; i < p_array_size * 16; i += 16) { - if (i + 15 < s) { - gui[i] = a[i]; - gui[i + 1] = a[i + 1]; - gui[i + 2] = a[i + 2]; - gui[i + 3] = a[i + 3]; - - gui[i + 4] = a[i + 4]; - gui[i + 5] = a[i + 5]; - gui[i + 6] = a[i + 6]; - gui[i + 7] = a[i + 7]; - - gui[i + 8] = a[i + 8]; - gui[i + 9] = a[i + 9]; - gui[i + 10] = a[i + 10]; - gui[i + 11] = a[i + 11]; - - gui[i + 12] = a[i + 12]; - gui[i + 13] = a[i + 13]; - gui[i + 14] = a[i + 14]; - gui[i + 15] = a[i + 15]; - } else { - gui[i] = 1; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - - gui[i + 4] = 0; - gui[i + 5] = 1; - gui[i + 6] = 0; - gui[i + 7] = 0; - - gui[i + 8] = 0; - gui[i + 9] = 0; - gui[i + 10] = 1; - gui[i + 11] = 0; - - gui[i + 12] = 0; - gui[i + 13] = 0; - gui[i + 14] = 0; - gui[i + 15] = 1; - } - } - } else if (value.get_type() == Variant::TRANSFORM3D) { - Transform3D v = value; - gui[0] = v.basis.rows[0][0]; - gui[1] = v.basis.rows[1][0]; - gui[2] = v.basis.rows[2][0]; - gui[3] = 0; - - gui[4] = v.basis.rows[0][1]; - gui[5] = v.basis.rows[1][1]; - gui[6] = v.basis.rows[2][1]; - gui[7] = 0; - - gui[8] = v.basis.rows[0][2]; - gui[9] = v.basis.rows[1][2]; - gui[10] = v.basis.rows[2][2]; - gui[11] = 0; - - gui[12] = v.origin.x; - gui[13] = v.origin.y; - gui[14] = v.origin.z; - gui[15] = 1; + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 16); } else { - Projection v = value; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - gui[i * 4 + j] = v.columns[i][j]; - } - } + convert_item_std140(value, gui); } } break; default: { @@ -1943,7 +1565,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC2: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector2i v = p_value; + Vector2i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -1951,7 +1573,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC3: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector3i v = p_value; + Vector3i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -1959,11 +1581,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC4: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector v = p_value; - bv.x = v.size() >= 1 ? v[0] : 0; - bv.y = v.size() >= 2 ? v[1] : 0; - bv.z = v.size() >= 3 ? v[2] : 0; - bv.w = v.size() >= 4 ? v[3] : 0; + Vector4i v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_RECT2I: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; @@ -1983,7 +1605,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC2: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector2i v = p_value; + Vector2i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -1991,7 +1613,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC3: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector3i v = p_value; + Vector3i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -1999,11 +1621,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC4: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector v = p_value; - bv.x = v.size() >= 1 ? v[0] : 0; - bv.y = v.size() >= 2 ? v[1] : 0; - bv.z = v.size() >= 3 ? v[2] : 0; - bv.w = v.size() >= 4 ? v[3] : 0; + Vector4i v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_FLOAT: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; @@ -2015,7 +1637,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC2: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Vector2 v = p_value; + Vector2 v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -2023,7 +1645,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC3: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Vector3 v = p_value; + Vector3 v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -2031,11 +1653,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC4: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Plane v = p_value; - bv.x = v.normal.x; - bv.y = v.normal.y; - bv.z = v.normal.z; - bv.w = v.d; + Vector4 v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_COLOR: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; @@ -2081,92 +1703,25 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS case RS::GLOBAL_VAR_TYPE_MAT3: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Basis v = p_value; - bv[0].x = v.rows[0][0]; - bv[0].y = v.rows[1][0]; - bv[0].z = v.rows[2][0]; - bv[0].w = 0; - - bv[1].x = v.rows[0][1]; - bv[1].y = v.rows[1][1]; - bv[1].z = v.rows[2][1]; - bv[1].w = 0; - - bv[2].x = v.rows[0][2]; - bv[2].y = v.rows[1][2]; - bv[2].z = v.rows[2][2]; - bv[2].w = 0; + convert_item_std140(v, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_MAT4: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; - - Vector m2 = p_value; - if (m2.size() < 16) { - m2.resize(16); - } - - bv[0].x = m2[0]; - bv[0].y = m2[1]; - bv[0].z = m2[2]; - bv[0].w = m2[3]; - - bv[1].x = m2[4]; - bv[1].y = m2[5]; - bv[1].z = m2[6]; - bv[1].w = m2[7]; - - bv[2].x = m2[8]; - bv[2].y = m2[9]; - bv[2].z = m2[10]; - bv[2].w = m2[11]; - - bv[3].x = m2[12]; - bv[3].y = m2[13]; - bv[3].z = m2[14]; - bv[3].w = m2[15]; + Projection m = p_value; + convert_item_std140(m, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Transform2D v = p_value; - bv[0].x = v.columns[0][0]; - bv[0].y = v.columns[0][1]; - bv[0].z = 0; - bv[0].w = 0; - - bv[1].x = v.columns[1][0]; - bv[1].y = v.columns[1][1]; - bv[1].z = 0; - bv[1].w = 0; - - bv[2].x = v.columns[2][0]; - bv[2].y = v.columns[2][1]; - bv[2].z = 1; - bv[2].w = 0; + convert_item_std140(v, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Transform3D v = p_value; - bv[0].x = v.basis.rows[0][0]; - bv[0].y = v.basis.rows[1][0]; - bv[0].z = v.basis.rows[2][0]; - bv[0].w = 0; - - bv[1].x = v.basis.rows[0][1]; - bv[1].y = v.basis.rows[1][1]; - bv[1].z = v.basis.rows[2][1]; - bv[1].w = 0; - - bv[2].x = v.basis.rows[0][2]; - bv[2].y = v.basis.rows[1][2]; - bv[2].z = v.basis.rows[2][2]; - bv[2].w = 0; - - bv[3].x = v.origin.x; - bv[3].y = v.origin.y; - bv[3].z = v.origin.z; - bv[3].w = 1; + convert_item_std140(v, &bv->x); } break; default: { diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 800de431eb8..8e59e55b511 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -198,7 +198,7 @@ protected: pinfo.type = Variant::COLOR; } break; case RS::GLOBAL_VAR_TYPE_MAT2: { - pinfo.type = Variant::PACKED_INT32_ARRAY; + pinfo.type = Variant::PACKED_FLOAT32_ARRAY; } break; case RS::GLOBAL_VAR_TYPE_MAT3: { pinfo.type = Variant::BASIS; @@ -271,13 +271,7 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { return Vector3i(); } case RS::GLOBAL_VAR_TYPE_IVEC4: { - Vector v4; - v4.resize(4); - v4.write[0] = 0; - v4.write[1] = 0; - v4.write[2] = 0; - v4.write[3] = 0; - return v4; + return Vector4i(); } case RS::GLOBAL_VAR_TYPE_RECT2I: { return Rect2i(); @@ -292,13 +286,7 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { return Vector3i(); } case RS::GLOBAL_VAR_TYPE_UVEC4: { - Vector v4; - v4.resize(4); - v4.write[0] = 0; - v4.write[1] = 0; - v4.write[2] = 0; - v4.write[3] = 0; - return v4; + return Vector4i(); } case RS::GLOBAL_VAR_TYPE_FLOAT: { return 0.0; @@ -310,7 +298,7 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { return Vector3(); } case RS::GLOBAL_VAR_TYPE_VEC4: { - return Quaternion(); + return Vector4(); } case RS::GLOBAL_VAR_TYPE_RECT2: { return Rect2(); @@ -319,7 +307,7 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { return Color(); } case RS::GLOBAL_VAR_TYPE_MAT2: { - Vector xform; + Vector xform; xform.resize(4); xform.write[0] = 1; xform.write[1] = 0; @@ -337,29 +325,7 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { return Transform3D(); } case RS::GLOBAL_VAR_TYPE_MAT4: { - Vector xform; - xform.resize(16); - xform.write[0] = 1; - xform.write[1] = 0; - xform.write[2] = 0; - xform.write[3] = 0; - - xform.write[4] = 0; - xform.write[5] = 1; - xform.write[6] = 0; - xform.write[7] = 0; - - xform.write[8] = 0; - xform.write[9] = 0; - xform.write[10] = 1; - xform.write[11] = 0; - - xform.write[12] = 0; - xform.write[13] = 0; - xform.write[14] = 0; - xform.write[15] = 1; - - return xform; + return Projection(); } case RS::GLOBAL_VAR_TYPE_SAMPLER2D: { return ""; diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 51fc948886f..7fff74e8e1a 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -128,7 +128,7 @@ void ShaderGlobalsOverride::_get_property_list(List *p_list) const pinfo.type = Variant::VECTOR3I; } break; case RS::GLOBAL_VAR_TYPE_IVEC4: { - pinfo.type = Variant::PACKED_INT32_ARRAY; + pinfo.type = Variant::VECTOR4I; } break; case RS::GLOBAL_VAR_TYPE_RECT2I: { pinfo.type = Variant::RECT2I; @@ -143,7 +143,7 @@ void ShaderGlobalsOverride::_get_property_list(List *p_list) const pinfo.type = Variant::VECTOR3I; } break; case RS::GLOBAL_VAR_TYPE_UVEC4: { - pinfo.type = Variant::PACKED_INT32_ARRAY; + pinfo.type = Variant::VECTOR4I; } break; case RS::GLOBAL_VAR_TYPE_FLOAT: { pinfo.type = Variant::FLOAT; @@ -164,7 +164,7 @@ void ShaderGlobalsOverride::_get_property_list(List *p_list) const pinfo.type = Variant::COLOR; } break; case RS::GLOBAL_VAR_TYPE_MAT2: { - pinfo.type = Variant::PACKED_INT32_ARRAY; + pinfo.type = Variant::PACKED_FLOAT32_ARRAY; } break; case RS::GLOBAL_VAR_TYPE_MAT3: { pinfo.type = Variant::BASIS; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 5752f4cc1a8..3966a9116be 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -306,10 +306,34 @@ void ShaderMaterial::_get_property_list(List *p_list) const { vgroups.push_back(Pair>("", { "" })); } + const bool is_uniform_cached = param_cache.has(E->get().name); + bool is_uniform_type_compatible = true; + + if (is_uniform_cached) { + // Check if the uniform Variant type changed, for example vec3 to vec4. + const Variant &cached = param_cache.get(E->get().name); + + if (cached.is_array()) { + // Allow some array conversions for backwards compatibility. + is_uniform_type_compatible = Variant::can_convert(E->get().type, cached.get_type()); + } else { + is_uniform_type_compatible = E->get().type == cached.get_type(); + } + + if (is_uniform_type_compatible && E->get().type == Variant::OBJECT && cached.get_type() == Variant::OBJECT) { + // Check if the Object class (hint string) changed, for example Texture2D sampler to Texture3D. + // Allow inheritance, Texture2D type sampler should also accept CompressedTexture2D. + Object *cached_obj = cached; + if (!cached_obj->is_class(E->get().hint_string)) { + is_uniform_type_compatible = false; + } + } + } + PropertyInfo info = E->get(); info.name = "shader_parameter/" + info.name; - if (!param_cache.has(E->get().name)) { - // Property has never been edited, retrieve with default value. + if (!is_uniform_cached || !is_uniform_type_compatible) { + // Property has never been edited or its type changed, retrieve with default value. Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), E->get().name); param_cache.insert(E->get().name, default_value); remap_cache.insert(info.name, E->get().name); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 6f67d628a92..42db459133e 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -32,6 +32,7 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/resource_loader.h" +#include "servers/rendering/storage/variant_converters.h" #include "texture_storage.h" using namespace RendererRD; @@ -39,26 +40,17 @@ using namespace RendererRD; /////////////////////////////////////////////////////////////////////////// // UBI helper functions -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) { +static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) { switch (type) { case ShaderLanguage::TYPE_BOOL: { uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = (r[i] != 0) ? 1 : 0; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored + PackedInt32Array ba = value; + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { bool v = value; gui[0] = v ? 1 : 0; @@ -68,22 +60,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 2 * p_array_size; - - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i] ? 1 : 0; - gui[j + 1] = r[i + 1] ? 1 : 0; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = v & 1 ? 1 : 0; @@ -94,23 +75,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 3 * p_array_size; - - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i] ? 1 : 0; - gui[j + 1] = r[i + 1] ? 1 : 0; - gui[j + 2] = r[i + 2] ? 1 : 0; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = (v & 1) ? 1 : 0; @@ -122,24 +91,11 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - const PackedInt32Array &ba = value; - int s = ba.size(); - const int *r = ba.ptr(); - int count = 4 * p_array_size; - - for (int i = 0; i < count; i += 4) { - if (i < s) { - gui[i] = r[i] ? 1 : 0; - gui[i + 1] = r[i + 1] ? 1 : 0; - gui[i + 2] = r[i + 2] ? 1 : 0; - gui[i + 3] = r[i + 3] ? 1 : 0; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } + PackedInt32Array ba = convert_array_std140(value); + for (int i = 0; i < ba.size(); i++) { + ba.set(i, ba[i] ? 1 : 0); } + write_array_std140(ba, gui, p_array_size, 4); } else { uint32_t v = value; gui[0] = (v & 1) ? 1 : 0; @@ -152,20 +108,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int32_t *gui = (int32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - const int *r = iv.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = r[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = value; + write_array_std140(iv, gui, p_array_size, 4); } else { int v = value; gui[0] = v; @@ -173,51 +117,24 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_IVEC2: { int32_t *gui = (int32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 2 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector2i v = value; + Vector2i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } } break; case ShaderLanguage::TYPE_IVEC3: { int32_t *gui = (int32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 3 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - gui[j + 2] = r[i + 2]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector3i v = value; + Vector3i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -225,27 +142,12 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_IVEC4: { int32_t *gui = (int32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 4 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0; i < count; i += 4) { - if (i < s) { - gui[i] = r[i]; - gui[i + 1] = r[i + 1]; - gui[i + 2] = r[i + 2]; - gui[i + 3] = r[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector4i v = value; + Vector4i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -256,20 +158,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy uint32_t *gui = (uint32_t *)data; if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - const int *r = iv.ptr(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = r[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedInt32Array &iv = value; + write_array_std140(iv, gui, p_array_size, 4); } else { int v = value; gui[0] = v; @@ -277,51 +167,24 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_UVEC2: { uint32_t *gui = (uint32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 2 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 2, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector2i v = value; + Vector2i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } } break; case ShaderLanguage::TYPE_UVEC3: { uint32_t *gui = (uint32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 3 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0, j = 0; i < count; i += 3, j += 4) { - if (i < s) { - gui[j] = r[i]; - gui[j + 1] = r[i + 1]; - gui[j + 2] = r[i + 2]; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector3i v = value; + Vector3i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -329,27 +192,12 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy } break; case ShaderLanguage::TYPE_UVEC4: { uint32_t *gui = (uint32_t *)data; - if (p_array_size > 0) { - Vector iv = value; - int s = iv.size(); - int count = 4 * p_array_size; - const int *r = iv.ptr(); - for (int i = 0; i < count; i++) { - if (i < s) { - gui[i] = r[i]; - gui[i + 1] = r[i + 1]; - gui[i + 2] = r[i + 2]; - gui[i + 3] = r[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } + if (p_array_size > 0) { + const PackedInt32Array &iv = convert_array_std140(value); + write_array_std140(iv, gui, p_array_size, 4); } else { - Vector4i v = value; + Vector4i v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; gui[2] = v.z; @@ -361,18 +209,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy if (p_array_size > 0) { const PackedFloat32Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i]; - } else { - gui[j] = 0; - } - gui[j + 1] = 0; // ignored - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + write_array_std140(a, gui, p_array_size, 4); } else { float v = value; gui[0] = v; @@ -382,22 +219,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = reinterpret_cast(data); if (p_array_size > 0) { - const PackedVector2Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i].x; - gui[j + 1] = a[i].y; - } else { - gui[j] = 0; - gui[j + 1] = 0; - } - gui[j + 2] = 0; // ignored - gui[j + 3] = 0; // ignored - } + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 4); } else { - Vector2 v = value; + Vector2 v = convert_to_vector(value); gui[0] = v.x; gui[1] = v.y; } @@ -406,147 +231,27 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = reinterpret_cast(data); if (p_array_size > 0) { - if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { - const PackedColorArray &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - Color color = a[i]; - if (p_linear_color) { - color = color.srgb_to_linear(); - } - gui[j] = color.r; - gui[j + 1] = color.g; - gui[j + 2] = color.b; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } - } else { - const PackedVector3Array &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - gui[j] = a[i].x; - gui[j + 1] = a[i].y; - gui[j + 2] = a[i].z; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - } - gui[j + 3] = 0; // ignored - } - } + const PackedFloat32Array &a = convert_array_std140(value, p_linear_color); + write_array_std140(a, gui, p_array_size, 4); } else { - if (value.get_type() == Variant::COLOR) { - Color v = value; - - if (p_linear_color) { - v = v.srgb_to_linear(); - } - - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - } else { - Vector3 v = value; - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - } + Vector3 v = convert_to_vector(value, p_linear_color); + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; } } break; case ShaderLanguage::TYPE_VEC4: { float *gui = reinterpret_cast(data); if (p_array_size > 0) { - if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { - const PackedColorArray &a = value; - int s = a.size(); - - for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { - if (i < s) { - Color color = a[i]; - if (p_linear_color) { - color = color.srgb_to_linear(); - } - gui[j] = color.r; - gui[j + 1] = color.g; - gui[j + 2] = color.b; - gui[j + 3] = color.a; - } else { - gui[j] = 0; - gui[j + 1] = 0; - gui[j + 2] = 0; - gui[j + 3] = 0; - } - } - } else { - const PackedFloat32Array &a = value; - int s = a.size(); - int count = 4 * p_array_size; - - for (int i = 0; i < count; i += 4) { - if (i + 3 < s) { - gui[i] = a[i]; - gui[i + 1] = a[i + 1]; - gui[i + 2] = a[i + 2]; - gui[i + 3] = a[i + 3]; - } else { - gui[i] = 0; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - } - } - } + const PackedFloat32Array &a = convert_array_std140(value, p_linear_color); + write_array_std140(a, gui, p_array_size, 4); } else { - if (value.get_type() == Variant::COLOR) { - Color v = value; - - if (p_linear_color) { - v = v.srgb_to_linear(); - } - - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - gui[3] = v.a; - } else if (value.get_type() == Variant::RECT2) { - Rect2 v = value; - - gui[0] = v.position.x; - gui[1] = v.position.y; - gui[2] = v.size.x; - gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUATERNION) { - Quaternion v = value; - - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else if (value.get_type() == Variant::PLANE) { - Plane v = value; - - gui[0] = v.normal.x; - gui[1] = v.normal.y; - gui[2] = v.normal.z; - gui[3] = v.d; - } else { - Vector4 v = value; - - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } + Vector4 v = convert_to_vector(value, p_linear_color); + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + gui[3] = v.w; } } break; case ShaderLanguage::TYPE_MAT2: { @@ -594,135 +299,42 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy float *gui = reinterpret_cast(data); if (p_array_size > 0) { - const PackedFloat32Array &a = value; - int s = a.size(); + const PackedFloat32Array &a = convert_array_std140(value); + const Basis default_basis; + const int s = a.size(); for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) { if (i + 8 < s) { gui[j] = a[i]; gui[j + 1] = a[i + 1]; gui[j + 2] = a[i + 2]; + gui[j + 3] = 0; // Ignored. gui[j + 4] = a[i + 3]; gui[j + 5] = a[i + 4]; gui[j + 6] = a[i + 5]; + gui[j + 7] = 0; // Ignored. gui[j + 8] = a[i + 6]; gui[j + 9] = a[i + 7]; gui[j + 10] = a[i + 8]; + gui[j + 11] = 0; // Ignored. } else { - gui[j] = 1; - gui[j + 1] = 0; - gui[j + 2] = 0; - - gui[j + 4] = 0; - gui[j + 5] = 1; - gui[j + 6] = 0; - - gui[j + 8] = 0; - gui[j + 9] = 0; - gui[j + 10] = 1; + convert_item_std140(default_basis, gui + j); } - gui[j + 3] = 0; // ignored - gui[j + 7] = 0; // ignored - gui[j + 11] = 0; // ignored } } else { - Basis v = value; - gui[0] = v.rows[0][0]; - gui[1] = v.rows[1][0]; - gui[2] = v.rows[2][0]; - gui[3] = 0; // ignored - - gui[4] = v.rows[0][1]; - gui[5] = v.rows[1][1]; - gui[6] = v.rows[2][1]; - gui[7] = 0; // ignored - - gui[8] = v.rows[0][2]; - gui[9] = v.rows[1][2]; - gui[10] = v.rows[2][2]; - gui[11] = 0; // ignored + convert_item_std140(value, gui); } } break; case ShaderLanguage::TYPE_MAT4: { float *gui = reinterpret_cast(data); if (p_array_size > 0) { - const PackedFloat32Array &a = value; - int s = a.size(); - - for (int i = 0; i < p_array_size * 16; i += 16) { - if (i + 15 < s) { - gui[i] = a[i]; - gui[i + 1] = a[i + 1]; - gui[i + 2] = a[i + 2]; - gui[i + 3] = a[i + 3]; - - gui[i + 4] = a[i + 4]; - gui[i + 5] = a[i + 5]; - gui[i + 6] = a[i + 6]; - gui[i + 7] = a[i + 7]; - - gui[i + 8] = a[i + 8]; - gui[i + 9] = a[i + 9]; - gui[i + 10] = a[i + 10]; - gui[i + 11] = a[i + 11]; - - gui[i + 12] = a[i + 12]; - gui[i + 13] = a[i + 13]; - gui[i + 14] = a[i + 14]; - gui[i + 15] = a[i + 15]; - } else { - gui[i] = 1; - gui[i + 1] = 0; - gui[i + 2] = 0; - gui[i + 3] = 0; - - gui[i + 4] = 0; - gui[i + 5] = 1; - gui[i + 6] = 0; - gui[i + 7] = 0; - - gui[i + 8] = 0; - gui[i + 9] = 0; - gui[i + 10] = 1; - gui[i + 11] = 0; - - gui[i + 12] = 0; - gui[i + 13] = 0; - gui[i + 14] = 0; - gui[i + 15] = 1; - } - } - } else if (value.get_type() == Variant::TRANSFORM3D) { - Transform3D v = value; - gui[0] = v.basis.rows[0][0]; - gui[1] = v.basis.rows[1][0]; - gui[2] = v.basis.rows[2][0]; - gui[3] = 0; - - gui[4] = v.basis.rows[0][1]; - gui[5] = v.basis.rows[1][1]; - gui[6] = v.basis.rows[2][1]; - gui[7] = 0; - - gui[8] = v.basis.rows[0][2]; - gui[9] = v.basis.rows[1][2]; - gui[10] = v.basis.rows[2][2]; - gui[11] = 0; - - gui[12] = v.origin.x; - gui[13] = v.origin.y; - gui[14] = v.origin.z; - gui[15] = 1; + const PackedFloat32Array &a = convert_array_std140(value); + write_array_std140(a, gui, p_array_size, 16); } else { - Projection v = value; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - gui[i * 4 + j] = v.columns[i][j]; - } - } + convert_item_std140(value, gui); } } break; default: { @@ -1820,7 +1432,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC2: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector2i v = p_value; + Vector2i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -1828,7 +1440,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC3: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector3i v = p_value; + Vector3i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -1836,11 +1448,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_IVEC4: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector v = p_value; - bv.x = v.size() >= 1 ? v[0] : 0; - bv.y = v.size() >= 2 ? v[1] : 0; - bv.z = v.size() >= 3 ? v[2] : 0; - bv.w = v.size() >= 4 ? v[3] : 0; + Vector4i v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_RECT2I: { GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index]; @@ -1860,7 +1472,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC2: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector2i v = p_value; + Vector2i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -1868,7 +1480,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC3: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector3i v = p_value; + Vector3i v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -1876,11 +1488,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_UVEC4: { GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index]; - Vector v = p_value; - bv.x = v.size() >= 1 ? v[0] : 0; - bv.y = v.size() >= 2 ? v[1] : 0; - bv.z = v.size() >= 3 ? v[2] : 0; - bv.w = v.size() >= 4 ? v[3] : 0; + Vector4i v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_FLOAT: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; @@ -1892,7 +1504,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC2: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Vector2 v = p_value; + Vector2 v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = 0; @@ -1900,7 +1512,7 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC3: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Vector3 v = p_value; + Vector3 v = convert_to_vector(p_value); bv.x = v.x; bv.y = v.y; bv.z = v.z; @@ -1908,11 +1520,11 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS } break; case RS::GLOBAL_VAR_TYPE_VEC4: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; - Plane v = p_value; - bv.x = v.normal.x; - bv.y = v.normal.y; - bv.z = v.normal.z; - bv.w = v.d; + Vector4 v = convert_to_vector(p_value); + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = v.w; } break; case RS::GLOBAL_VAR_TYPE_COLOR: { GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index]; @@ -1958,92 +1570,25 @@ void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS case RS::GLOBAL_VAR_TYPE_MAT3: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Basis v = p_value; - bv[0].x = v.rows[0][0]; - bv[0].y = v.rows[1][0]; - bv[0].z = v.rows[2][0]; - bv[0].w = 0; - - bv[1].x = v.rows[0][1]; - bv[1].y = v.rows[1][1]; - bv[1].z = v.rows[2][1]; - bv[1].w = 0; - - bv[2].x = v.rows[0][2]; - bv[2].y = v.rows[1][2]; - bv[2].z = v.rows[2][2]; - bv[2].w = 0; + convert_item_std140(v, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_MAT4: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; - - Vector m2 = p_value; - if (m2.size() < 16) { - m2.resize(16); - } - - bv[0].x = m2[0]; - bv[0].y = m2[1]; - bv[0].z = m2[2]; - bv[0].w = m2[3]; - - bv[1].x = m2[4]; - bv[1].y = m2[5]; - bv[1].z = m2[6]; - bv[1].w = m2[7]; - - bv[2].x = m2[8]; - bv[2].y = m2[9]; - bv[2].z = m2[10]; - bv[2].w = m2[11]; - - bv[3].x = m2[12]; - bv[3].y = m2[13]; - bv[3].z = m2[14]; - bv[3].w = m2[15]; + Projection m = p_value; + convert_item_std140(m, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Transform2D v = p_value; - bv[0].x = v.columns[0][0]; - bv[0].y = v.columns[0][1]; - bv[0].z = 0; - bv[0].w = 0; - - bv[1].x = v.columns[1][0]; - bv[1].y = v.columns[1][1]; - bv[1].z = 0; - bv[1].w = 0; - - bv[2].x = v.columns[2][0]; - bv[2].y = v.columns[2][1]; - bv[2].z = 1; - bv[2].w = 0; + convert_item_std140(v, &bv->x); } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index]; Transform3D v = p_value; - bv[0].x = v.basis.rows[0][0]; - bv[0].y = v.basis.rows[1][0]; - bv[0].z = v.basis.rows[2][0]; - bv[0].w = 0; - - bv[1].x = v.basis.rows[0][1]; - bv[1].y = v.basis.rows[1][1]; - bv[1].z = v.basis.rows[2][1]; - bv[1].w = 0; - - bv[2].x = v.basis.rows[0][2]; - bv[2].y = v.basis.rows[1][2]; - bv[2].z = v.basis.rows[2][2]; - bv[2].w = 0; - - bv[3].x = v.origin.x; - bv[3].y = v.origin.y; - bv[3].z = v.origin.z; - bv[3].w = 1; + convert_item_std140(v, &bv->x); } break; default: { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index df23386037c..ca41cc8d51f 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3790,7 +3790,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector +#include + +template +struct VariantConverterStd140 { + // Generic base template for all Vector2/3/4(i) classes. + static constexpr int Elements = T::AXIS_COUNT; + + template + static void convert(const T &p_v, P *p_write, bool p_compact) { + for (int i = 0; i < Elements; i++) { + p_write[i] = p_v[i]; + } + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 1; + + template + static void convert(float p_v, P *p_write, bool p_compact) { + p_write[0] = p_v; + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 1; + + template + static void convert(int32_t p_v, P *p_write, bool p_compact) { + p_write[0] = p_v; + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 1; + + template + static void convert(uint32_t p_v, P *p_write, bool p_compact) { + p_write[0] = p_v; + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 9; + + template + static void convert(const Basis &p_v, P *p_write, bool p_compact) { + // Basis can have compact 9 floats or std140 layout 12 floats. + int i = 0; + + p_write[i++] = p_v.rows[0][0]; + p_write[i++] = p_v.rows[1][0]; + p_write[i++] = p_v.rows[2][0]; + if (!p_compact) { + p_write[i++] = 0; + } + + p_write[i++] = p_v.rows[0][1]; + p_write[i++] = p_v.rows[1][1]; + p_write[i++] = p_v.rows[2][1]; + if (!p_compact) { + p_write[i++] = 0; + } + + p_write[i++] = p_v.rows[0][2]; + p_write[i++] = p_v.rows[1][2]; + p_write[i++] = p_v.rows[2][2]; + if (!p_compact) { + p_write[i++] = 0; + } + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 12; + + template + static void convert(const Transform2D &p_v, P *p_write, bool p_compact) { + p_write[0] = p_v.columns[0][0]; + p_write[1] = p_v.columns[0][1]; + p_write[2] = 0; + p_write[3] = 0; + + p_write[4] = p_v.columns[1][0]; + p_write[5] = p_v.columns[1][1]; + p_write[6] = 0; + p_write[7] = 0; + + p_write[8] = p_v.columns[2][0]; + p_write[9] = p_v.columns[2][1]; + p_write[10] = 1; + p_write[11] = 0; + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 16; + + template + static void convert(const Transform3D &p_v, P *p_write, bool p_compact) { + p_write[0] = p_v.basis.rows[0][0]; + p_write[1] = p_v.basis.rows[1][0]; + p_write[2] = p_v.basis.rows[2][0]; + p_write[3] = 0; + + p_write[4] = p_v.basis.rows[0][1]; + p_write[5] = p_v.basis.rows[1][1]; + p_write[6] = p_v.basis.rows[2][1]; + p_write[7] = 0; + + p_write[8] = p_v.basis.rows[0][2]; + p_write[9] = p_v.basis.rows[1][2]; + p_write[10] = p_v.basis.rows[2][2]; + p_write[11] = 0; + + p_write[12] = p_v.origin.x; + p_write[13] = p_v.origin.y; + p_write[14] = p_v.origin.z; + p_write[15] = 1; + } +}; + +template <> +struct VariantConverterStd140 { + static constexpr int Elements = 16; + + template + static void convert(const Projection &p_v, P *p_write, bool p_compact) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + p_write[i * 4 + j] = p_v.columns[i][j]; + } + } + } +}; + +template +T construct_vector(const std::initializer_list

&values) { + T vector{}; + int index = 0; + for (P v : values) { + vector[index++] = v; + if (index >= T::AXIS_COUNT) { + break; + } + } + return vector; +} + +// Compatibility converter, tries to convert certain Variant types into a Vector2/3/4(i). + +template +T convert_to_vector(const Variant &p_variant, bool p_linear_color = false) { + const Variant::Type type = p_variant.get_type(); + + if (type == Variant::QUATERNION) { + Quaternion quat = p_variant; + return construct_vector({ quat.x, quat.y, quat.z, quat.w }); + } else if (type == Variant::PLANE) { + Plane p = p_variant; + return construct_vector({ p.normal.x, p.normal.y, p.normal.z, p.d }); + } else if (type == Variant::RECT2 || type == Variant::RECT2I) { + Rect2 r = p_variant; + return construct_vector({ r.position.x, r.position.y, r.size.x, r.size.y }); + } else if (type == Variant::COLOR) { + Color c = p_variant; + if (p_linear_color) { + c = c.srgb_to_linear(); + } + return construct_vector({ c.r, c.g, c.b, c.a }); + } else if (p_variant.is_array()) { + const Array &array = p_variant; + const int size = MIN(array.size(), T::AXIS_COUNT); + T vector{}; + for (int i = 0; i < size; i++) { + vector[i] = array.get(i); + } + return vector; + } + + return p_variant; // Default Variant conversion, covers all Vector2/3/4(i) types. +} + +inline bool is_number_array(const Array &p_array) { + const int size = p_array.size(); + for (int i = 0; i < size; i++) { + if (!p_array.get(i).is_num()) { + return false; + } + } + return true; +} + +inline bool is_convertible_array(Variant::Type type) { + return type == Variant::ARRAY || + type == Variant::PACKED_VECTOR2_ARRAY || + type == Variant::PACKED_VECTOR3_ARRAY || + type == Variant::PACKED_COLOR_ARRAY; +} + +template +struct is_vector_type : std::false_type {}; + +template +struct is_vector_type> : std::true_type {}; + +template +void convert_item_std140(const T &p_item, P *p_write, bool p_compact = false) { + VariantConverterStd140::template convert

(p_item, p_write, p_compact); +} + +template +Vector

convert_array_std140(const Variant &p_variant, [[maybe_unused]] bool p_linear_color = false) { + if (is_convertible_array(p_variant.get_type())) { + // Slow path, convert Variant arrays and some packed arrays manually into primitive types. + const Array &array = p_variant; + if (is_number_array(array)) { + // Already flattened and converted (or empty) array, usually coming from saved resources. + return p_variant; + } + + const int items = array.size(); + constexpr int elements = VariantConverterStd140::Elements; + + Vector

result; + result.resize(items * elements); + P *write = result.ptrw(); + + for (int i = 0; i < items; i++) { + const Variant &item = array.get(i); + P *offset = write + (i * elements); + + if constexpr (is_vector_type::value) { + const T &vec = convert_to_vector(item, p_linear_color); + convert_item_std140(vec, offset, true); + } else { + convert_item_std140(item.operator T(), offset, true); + } + } + return result; + + } else if (p_variant.is_array()) { + // Fast path, return the packed array directly. + return p_variant; + } + + // Not an array type. Usually happens with uninitialized null shader resource parameters. + // Just return an empty array, uniforms will be default initialized later. + + return Vector

(); +} + +template +void write_array_std140(const Vector &p_values, To *p_write, int p_array_size, int p_stride) { + constexpr int elements = VariantConverterStd140::Elements; + const int src_count = p_values.size(); + const int dst_count = elements * p_array_size; + const int stride_count = p_stride * p_array_size; + const From *read = p_values.ptr(); + const T default_value{}; + + memset(p_write, 0, sizeof(To) * stride_count); + + for (int i = 0, j = 0; i < dst_count; i += elements, j += p_stride) { + if (i + elements - 1 < src_count) { + // Only copy full items with all elements, no partial or missing data. + for (int e = 0; e < elements; e++) { + DEV_ASSERT(j + e < stride_count && i + e < src_count); + p_write[j + e] = read[i + e]; + } + } else { + // If not enough source data was passed in, write default values. + convert_item_std140(default_value, p_write + j); + } + } +} + +#endif // VARIANT_CONVERTERS_H