Merge pull request #74937 from bitsawer/fix_uniform_storage

Fix shader uniform storage conversions and crash
This commit is contained in:
Rémi Verschelde 2023-06-09 11:04:16 +02:00
commit 166643df32
No known key found for this signature in database
GPG key ID: C3336907360768E1
7 changed files with 560 additions and 1148 deletions

View file

@ -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<int32_t>(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<Vector2i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector2i>(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<Vector3i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector3i>(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<Vector4i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector4i>(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<int> 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<int32_t>(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<int> 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<Vector2i, int32_t>(value);
write_array_std140<Vector2i>(iv, gui, p_array_size, 4);
} else {
Vector2i v = value;
Vector2i v = convert_to_vector<Vector2i>(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<int> 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<Vector3i, int32_t>(value);
write_array_std140<Vector3i>(iv, gui, p_array_size, 4);
} else {
Vector3i v = value;
Vector3i v = convert_to_vector<Vector3i>(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<int> 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<Vector4i, int32_t>(value);
write_array_std140<Vector4i>(iv, gui, p_array_size, 4);
} else {
Vector4i v = value;
Vector4i v = convert_to_vector<Vector4i>(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<int> 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<uint32_t>(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<int> 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<Vector2i, int32_t>(value);
write_array_std140<Vector2i>(iv, gui, p_array_size, 4);
} else {
Vector2i v = value;
Vector2i v = convert_to_vector<Vector2i>(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<int> 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<Vector3i, int32_t>(value);
write_array_std140<Vector3i>(iv, gui, p_array_size, 4);
} else {
Vector3i v = value;
Vector3i v = convert_to_vector<Vector3i>(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<int> 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<Vector4i, int32_t>(value);
write_array_std140<Vector4i>(iv, gui, p_array_size, 4);
} else {
Vector4i v = value;
Vector4i v = convert_to_vector<Vector4i>(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<float>(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<Vector2, float>(value);
write_array_std140<Vector2>(a, gui, p_array_size, 4);
} else {
Vector2 v = value;
Vector2 v = convert_to_vector<Vector2>(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<Vector3, float>(value);
write_array_std140<Vector3>(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<Vector3>(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<Vector4, float>(value);
write_array_std140<Vector4>(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<Vector4>(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<Basis, float>(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<Basis>(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<Projection, float>(value);
write_array_std140<Projection>(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<Projection>(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<Vector2i>(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<Vector3i>(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<int32_t> 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<Vector4i>(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<Vector2i>(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<Vector3i>(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<int32_t> 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<Vector4i>(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<Vector2>(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<Vector3>(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<Vector4>(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<Basis>(v, &bv->x);
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
Vector<float> 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<Projection>(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<Transform2D>(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<Transform3D>(v, &bv->x);
} break;
default: {

View file

@ -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<int> 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<int> 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<real_t> xform;
Vector<float> 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<real_t> 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 "";

View file

@ -128,7 +128,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *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<PropertyInfo> *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<PropertyInfo> *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;

View file

@ -310,10 +310,34 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
vgroups.push_back(Pair<String, LocalVector<String>>("<None>", { "<None>" }));
}
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);

View file

@ -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<int32_t>(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<Vector2i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector2i>(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<Vector3i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector3i>(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<Vector4i, int32_t>(value);
for (int i = 0; i < ba.size(); i++) {
ba.set(i, ba[i] ? 1 : 0);
}
write_array_std140<Vector4i>(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<int> 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<int32_t>(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<int> 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<Vector2i, int32_t>(value);
write_array_std140<Vector2i>(iv, gui, p_array_size, 4);
} else {
Vector2i v = value;
Vector2i v = convert_to_vector<Vector2i>(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<int> 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<Vector3i, int32_t>(value);
write_array_std140<Vector3i>(iv, gui, p_array_size, 4);
} else {
Vector3i v = value;
Vector3i v = convert_to_vector<Vector3i>(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<int> 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<Vector4i, int32_t>(value);
write_array_std140<Vector4i>(iv, gui, p_array_size, 4);
} else {
Vector4i v = value;
Vector4i v = convert_to_vector<Vector4i>(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<int> 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<uint32_t>(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<int> 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<Vector2i, int32_t>(value);
write_array_std140<Vector2i>(iv, gui, p_array_size, 4);
} else {
Vector2i v = value;
Vector2i v = convert_to_vector<Vector2i>(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<int> 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<Vector3i, int32_t>(value);
write_array_std140<Vector3i>(iv, gui, p_array_size, 4);
} else {
Vector3i v = value;
Vector3i v = convert_to_vector<Vector3i>(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<int> 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<Vector4i, int32_t>(value);
write_array_std140<Vector4i>(iv, gui, p_array_size, 4);
} else {
Vector4i v = value;
Vector4i v = convert_to_vector<Vector4i>(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<float>(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<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<Vector2, float>(value);
write_array_std140<Vector2>(a, gui, p_array_size, 4);
} else {
Vector2 v = value;
Vector2 v = convert_to_vector<Vector2>(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<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];
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<Vector3, float>(value, p_linear_color);
write_array_std140<Vector3>(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<Vector3>(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<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];
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<Vector4, float>(value, p_linear_color);
write_array_std140<Vector4>(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<Vector4>(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<float *>(data);
if (p_array_size > 0) {
const PackedFloat32Array &a = value;
int s = a.size();
const PackedFloat32Array &a = convert_array_std140<Basis, float>(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<Basis>(value, gui);
}
} break;
case ShaderLanguage::TYPE_MAT4: {
float *gui = reinterpret_cast<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<Projection, float>(value);
write_array_std140<Projection>(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<Projection>(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<Vector2i>(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<Vector3i>(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<int32_t> 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<Vector4i>(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<Vector2i>(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<Vector3i>(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<int32_t> 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<Vector4i>(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<Vector2>(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<Vector3>(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<Vector4>(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<Basis>(v, &bv->x);
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
Vector<float> 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<Projection>(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<Transform2D>(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<Transform3D>(v, &bv->x);
} break;
default: {

View file

@ -3790,7 +3790,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
value = Variant(Vector2i(p_value[0].sint, p_value[1].sint));
}
break;
case ShaderLanguage::TYPE_IVEC3:
@ -3803,7 +3803,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
value = Variant(Vector3i(p_value[0].sint, p_value[1].sint, p_value[2].sint));
}
break;
case ShaderLanguage::TYPE_IVEC4:
@ -3816,7 +3816,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Quaternion(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
value = Variant(Vector4i(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
}
break;
case ShaderLanguage::TYPE_UINT:
@ -3840,7 +3840,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
value = Variant(Vector2i(p_value[0].uint, p_value[1].uint));
}
break;
case ShaderLanguage::TYPE_UVEC3:
@ -3853,7 +3853,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
value = Variant(Vector3i(p_value[0].uint, p_value[1].uint, p_value[2].uint));
}
break;
case ShaderLanguage::TYPE_UVEC4:
@ -3866,7 +3866,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
value = Variant(Quaternion(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
value = Variant(Vector4i(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
}
break;
case ShaderLanguage::TYPE_FLOAT:
@ -3942,7 +3942,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
} else {
value = Variant(Quaternion(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
value = Variant(Vector4(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
}
}
break;

View file

@ -0,0 +1,322 @@
/**************************************************************************/
/* variant_converters.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef VARIANT_CONVERTERS_H
#define VARIANT_CONVERTERS_H
#include "core/error/error_macros.h"
#include "core/variant/array.h"
#include "core/variant/variant.h"
#include <initializer_list>
#include <type_traits>
template <typename T>
struct VariantConverterStd140 {
// Generic base template for all Vector2/3/4(i) classes.
static constexpr int Elements = T::AXIS_COUNT;
template <typename P>
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<float> {
static constexpr int Elements = 1;
template <typename P>
static void convert(float p_v, P *p_write, bool p_compact) {
p_write[0] = p_v;
}
};
template <>
struct VariantConverterStd140<int32_t> {
static constexpr int Elements = 1;
template <typename P>
static void convert(int32_t p_v, P *p_write, bool p_compact) {
p_write[0] = p_v;
}
};
template <>
struct VariantConverterStd140<uint32_t> {
static constexpr int Elements = 1;
template <typename P>
static void convert(uint32_t p_v, P *p_write, bool p_compact) {
p_write[0] = p_v;
}
};
template <>
struct VariantConverterStd140<Basis> {
static constexpr int Elements = 9;
template <typename P>
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<Transform2D> {
static constexpr int Elements = 12;
template <typename P>
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<Transform3D> {
static constexpr int Elements = 16;
template <typename P>
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<Projection> {
static constexpr int Elements = 16;
template <typename P>
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 <typename T, typename P>
T construct_vector(const std::initializer_list<P> &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 <typename T>
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<T>({ quat.x, quat.y, quat.z, quat.w });
} else if (type == Variant::PLANE) {
Plane p = p_variant;
return construct_vector<T>({ 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<T>({ 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<T>({ 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 <class, class = void>
struct is_vector_type : std::false_type {};
template <class T>
struct is_vector_type<T, std::void_t<decltype(T::AXIS_COUNT)>> : std::true_type {};
template <typename T, typename P>
void convert_item_std140(const T &p_item, P *p_write, bool p_compact = false) {
VariantConverterStd140<T>::template convert<P>(p_item, p_write, p_compact);
}
template <typename T, typename P>
Vector<P> 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<T>::Elements;
Vector<P> 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<T>::value) {
const T &vec = convert_to_vector<T>(item, p_linear_color);
convert_item_std140<T, P>(vec, offset, true);
} else {
convert_item_std140<T, P>(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<P>();
}
template <typename T, typename From, typename To>
void write_array_std140(const Vector<From> &p_values, To *p_write, int p_array_size, int p_stride) {
constexpr int elements = VariantConverterStd140<T>::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