1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-04 17:04:49 +00:00

Implement global and per instance shader uniforms.

Adds two keywords to shader language for uniforms:
-'global'
-'instance'

This allows them to reference values outside the material.
This commit is contained in:
Juan Linietsky
2020-04-16 23:52:00 -03:00
parent 30ab5c9baa
commit 0e1c66d9fc
49 changed files with 3124 additions and 69 deletions

View File

@@ -618,6 +618,14 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
}
}
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 7;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
//validate and update lighs if they are being used
if (light_count > 0) {
@@ -2012,6 +2020,9 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -2027,6 +2038,23 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_
}
}
void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RasterizerStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E->get());
p.info.name = E->key(); //supply name
p.index = E->get().instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
p_param_list->push_back(p);
}
}
bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -2366,6 +2394,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
actions.base_varying_index = 4;
actions.global_buffer_array_variable = "global_variables.data";
shader.compiler.initialize(actions);
}

View File

@@ -185,6 +185,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;

View File

@@ -378,6 +378,10 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -393,6 +397,23 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_
}
}
void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RasterizerStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E->get());
p.info.name = E->key(); //supply name
p.index = E->get().instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
p_param_list->push_back(p);
}
}
bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -828,6 +849,7 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,
store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
id.flags = 0;
id.mask = e->instance->layer_mask;
id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0;
if (e->instance->base_type == RS::INSTANCE_MULTIMESH) {
id.flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -2701,6 +2723,14 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 16;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
}
}
@@ -3077,6 +3107,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_variables.data";
actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
shader.compiler.initialize(actions);
}

View File

@@ -152,6 +152,8 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
@@ -361,7 +363,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float transform[16];
float normal_transform[16];
uint32_t flags;
uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer
uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer
uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap)
uint32_t mask;
};

View File

@@ -926,6 +926,10 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -941,6 +945,23 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para
}
}
void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RasterizerStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E->get());
p.info.name = E->key(); //supply name
p.index = E->get().instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
p_param_list->push_back(p);
}
}
bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -4217,6 +4238,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_variables.data";
sky_shader.compiler.initialize(actions);
}
@@ -4254,6 +4276,14 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
uniforms.push_back(u);
}
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
}

View File

@@ -189,6 +189,7 @@ private:
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;

View File

@@ -31,6 +31,7 @@
#include "rasterizer_storage_rd.h"
#include "core/engine.h"
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
#include "servers/rendering/shader_language.h"
@@ -921,6 +922,7 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
Material *material = E->get();
if (shader->data) {
material->data = material_data_request_func[new_type](shader->data);
material->data->self = material->self;
material->data->set_next_pass(material->next_pass);
material->data->set_render_priority(material->priority);
}
@@ -1021,8 +1023,8 @@ void RasterizerStorageRD::_material_queue_update(Material *material, bool p_unif
material->update_next = material_update_list;
material_update_list = material;
material->update_requested = true;
material->uniform_dirty = p_uniform;
material->texture_dirty = p_texture;
material->uniform_dirty = material->uniform_dirty || p_uniform;
material->texture_dirty = material->texture_dirty || p_texture;
}
void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
@@ -1059,6 +1061,7 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
ERR_FAIL_COND(shader->data == nullptr);
material->data = material_data_request_func[shader->type](shader->data);
material->data->self = p_material;
material->data->set_next_pass(material->next_pass);
material->data->set_render_priority(material->priority);
//updating happens later
@@ -1144,6 +1147,19 @@ bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
Material *material = material_owner.getornull(p_material);
ERR_FAIL_COND(!material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
if (material->next_pass.is_valid()) {
material_get_instance_shader_parameters(material->next_pass, r_parameters);
}
}
}
void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
Material *material = material_owner.getornull(p_material);
ERR_FAIL_COND(!material);
@@ -1631,11 +1647,36 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
bool uses_global_buffer = false;
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
if (E->get().order < 0)
continue; // texture, does not go here
if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue; //instance uniforms don't appear in the bufferr
}
if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
//this is a global variable, get the index to it
RasterizerStorageRD *rs = base_singleton;
GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key());
uint32_t index = 0;
if (gv) {
index = gv->buffer_index;
} else {
WARN_PRINT("Shader uses global uniform '" + E->key() + "', but it was removed at some point. Material will not display correctly.");
}
uint32_t offset = p_uniform_offsets[E->get().order];
uint32_t *intptr = (uint32_t *)&p_buffer[offset];
*intptr = index;
uses_global_buffer = true;
continue;
}
//regular uniform
uint32_t offset = p_uniform_offsets[E->get().order];
#ifdef DEBUG_ENABLED
@@ -1664,6 +1705,38 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa
}
}
}
if (uses_global_buffer != (global_buffer_E != nullptr)) {
RasterizerStorageRD *rs = base_singleton;
if (uses_global_buffer) {
global_buffer_E = rs->global_variables.materials_using_buffer.push_back(self);
} else {
rs->global_variables.materials_using_buffer.erase(global_buffer_E);
global_buffer_E = nullptr;
}
}
}
RasterizerStorageRD::MaterialData::~MaterialData() {
if (global_buffer_E) {
//unregister global buffers
RasterizerStorageRD *rs = base_singleton;
rs->global_variables.materials_using_buffer.erase(global_buffer_E);
}
if (global_texture_E) {
//unregister global textures
RasterizerStorageRD *rs = base_singleton;
for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) {
GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key());
if (v) {
v->texture_materials.erase(self);
}
}
//unregister material from those using global textures
rs->global_variables.materials_using_texture.erase(global_texture_E);
}
}
void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
@@ -1675,22 +1748,57 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va
Texture *normal_detect_texture = nullptr;
#endif
bool uses_global_textures = false;
global_textures_pass++;
for (int i = 0; i < p_texture_uniforms.size(); i++) {
const StringName &uniform_name = p_texture_uniforms[i].name;
RID texture;
const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
if (V) {
texture = V->get();
}
if (p_texture_uniforms[i].global) {
if (!texture.is_valid()) {
const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
if (W) {
RasterizerStorageRD *rs = base_singleton;
texture = W->get();
uses_global_textures = true;
GlobalVariables::Variable *v = rs->global_variables.variables.getptr(uniform_name);
if (v) {
if (v->buffer_index >= 0) {
WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
} else {
Map<StringName, uint64_t>::Element *E = used_global_textures.find(uniform_name);
if (!E) {
E = used_global_textures.insert(uniform_name, global_textures_pass);
v->texture_materials.insert(self);
} else {
E->get() = global_textures_pass;
}
texture = v->override.get_type() != Variant::NIL ? v->override : v->value;
}
} else {
WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
}
} else {
if (!texture.is_valid()) {
const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
if (V) {
texture = V->get();
}
}
if (!texture.is_valid()) {
const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
if (W) {
texture = W->get();
}
}
}
@@ -1753,6 +1861,36 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va
roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
#endif
{
//for textures no longer used, unregister them
List<Map<StringName, uint64_t>::Element *> to_delete;
RasterizerStorageRD *rs = base_singleton;
for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) {
if (E->get() != global_textures_pass) {
to_delete.push_back(E);
GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key());
if (v) {
v->texture_materials.erase(self);
}
}
}
while (to_delete.front()) {
used_global_textures.erase(to_delete.front()->get());
to_delete.pop_front();
}
//handle registering/unregistering global textures
if (uses_global_textures != (global_texture_E != nullptr)) {
if (uses_global_textures) {
global_texture_E = rs->global_variables.materials_using_texture.push_back(self);
} else {
rs->global_variables.materials_using_texture.erase(global_texture_E);
global_texture_E = nullptr;
}
}
}
}
void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
@@ -4627,7 +4765,685 @@ void RasterizerStorageRD::_update_decal_atlas() {
}
}
int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) {
int32_t idx = 0;
while (idx + p_elements <= global_variables.buffer_size) {
if (global_variables.buffer_usage[idx].elements == 0) {
bool valid = true;
for (uint32_t i = 1; i < p_elements; i++) {
if (global_variables.buffer_usage[idx + i].elements > 0) {
valid = false;
idx += i + global_variables.buffer_usage[idx + i].elements;
break;
}
}
if (!valid) {
continue; //if not valid, idx is in new position
}
return idx;
} else {
idx += global_variables.buffer_usage[idx].elements;
}
}
return -1;
}
void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
bool b = p_value;
bv.x = b ? 1.0 : 0.0;
bv.y = 0.0;
bv.z = 0.0;
bv.w = 0.0;
} break;
case RS::GLOBAL_VAR_TYPE_BVEC2: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
uint32_t bvec = p_value;
bv.x = (bvec & 1) ? 1.0 : 0.0;
bv.y = (bvec & 2) ? 1.0 : 0.0;
bv.z = 0.0;
bv.w = 0.0;
} break;
case RS::GLOBAL_VAR_TYPE_BVEC3: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
uint32_t bvec = p_value;
bv.x = (bvec & 1) ? 1.0 : 0.0;
bv.y = (bvec & 2) ? 1.0 : 0.0;
bv.z = (bvec & 4) ? 1.0 : 0.0;
bv.w = 0.0;
} break;
case RS::GLOBAL_VAR_TYPE_BVEC4: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
uint32_t bvec = p_value;
bv.x = (bvec & 1) ? 1.0 : 0.0;
bv.y = (bvec & 2) ? 1.0 : 0.0;
bv.z = (bvec & 4) ? 1.0 : 0.0;
bv.w = (bvec & 8) ? 1.0 : 0.0;
} break;
case RS::GLOBAL_VAR_TYPE_INT: {
GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
int32_t v = p_value;
bv.x = v;
bv.y = 0;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC2: {
GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
Vector2i v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC3: {
GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
Vector3i v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = v.z;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC4: {
GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.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;
} break;
case RS::GLOBAL_VAR_TYPE_RECT2I: {
GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
Rect2i v = p_value;
bv.x = v.position.x;
bv.y = v.position.y;
bv.z = v.size.x;
bv.w = v.size.y;
} break;
case RS::GLOBAL_VAR_TYPE_UINT: {
GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
uint32_t v = p_value;
bv.x = v;
bv.y = 0;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC2: {
GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
Vector2i v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC3: {
GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
Vector3i v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = v.z;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC4: {
GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.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;
} break;
case RS::GLOBAL_VAR_TYPE_FLOAT: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
float v = p_value;
bv.x = v;
bv.y = 0;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_VEC2: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
Vector2 v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = 0;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_VEC3: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
Vector3 v = p_value;
bv.x = v.x;
bv.y = v.y;
bv.z = v.z;
bv.w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_VEC4: {
GlobalVariables::Value &bv = global_variables.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;
} break;
case RS::GLOBAL_VAR_TYPE_COLOR: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
Color v = p_value;
bv.x = v.r;
bv.y = v.g;
bv.z = v.b;
bv.w = v.a;
GlobalVariables::Value &bv_linear = global_variables.buffer_values[p_index + 1];
v = v.to_linear();
bv_linear.x = v.r;
bv_linear.y = v.g;
bv_linear.z = v.b;
bv_linear.w = v.a;
} break;
case RS::GLOBAL_VAR_TYPE_RECT2: {
GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
Rect2 v = p_value;
bv.x = v.position.x;
bv.y = v.position.y;
bv.z = v.size.x;
bv.w = v.size.y;
} break;
case RS::GLOBAL_VAR_TYPE_MAT2: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
Vector<float> m2 = p_value;
if (m2.size() < 4) {
m2.resize(4);
}
bv[0].x = m2[0];
bv[0].y = m2[1];
bv[0].z = 0;
bv[0].w = 0;
bv[1].x = m2[2];
bv[1].y = m2[3];
bv[1].z = 0;
bv[1].w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_MAT3: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
Basis v = p_value;
bv[0].x = v.elements[0][0];
bv[0].y = v.elements[1][0];
bv[0].z = v.elements[2][0];
bv[0].w = 0;
bv[1].x = v.elements[0][1];
bv[1].y = v.elements[1][1];
bv[1].z = v.elements[2][1];
bv[1].w = 0;
bv[2].x = v.elements[0][2];
bv[2].y = v.elements[1][2];
bv[2].z = v.elements[2][2];
bv[2].w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
GlobalVariables::Value *bv = &global_variables.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];
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
Transform2D v = p_value;
bv[0].x = v.elements[0][0];
bv[0].y = v.elements[0][1];
bv[0].z = 0;
bv[0].w = 0;
bv[1].x = v.elements[1][0];
bv[1].y = v.elements[1][1];
bv[1].z = 0;
bv[1].w = 0;
bv[2].x = v.elements[2][0];
bv[2].y = v.elements[2][1];
bv[2].z = 1;
bv[2].w = 0;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
Transform v = p_value;
bv[0].x = v.basis.elements[0][0];
bv[0].y = v.basis.elements[1][0];
bv[0].z = v.basis.elements[2][0];
bv[0].w = 0;
bv[1].x = v.basis.elements[0][1];
bv[1].y = v.basis.elements[1][1];
bv[1].z = v.basis.elements[2][1];
bv[1].w = 0;
bv[2].x = v.basis.elements[0][2];
bv[2].y = v.basis.elements[1][2];
bv[2].z = v.basis.elements[2][2];
bv[2].w = 0;
bv[2].x = v.origin.x;
bv[2].y = v.origin.y;
bv[2].z = v.origin.z;
bv[2].w = 1;
} break;
default: {
ERR_FAIL();
}
}
}
void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) {
int32_t prev_chunk = -1;
for (int32_t i = 0; i < p_elements; i++) {
int32_t chunk = (p_index + i) / GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
if (chunk != prev_chunk) {
if (!global_variables.buffer_dirty_regions[chunk]) {
global_variables.buffer_dirty_regions[chunk] = true;
global_variables.buffer_dirty_region_count++;
}
}
prev_chunk = chunk;
}
}
void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) {
ERR_FAIL_COND(global_variables.variables.has(p_name));
GlobalVariables::Variable gv;
gv.type = p_type;
gv.value = p_value;
gv.buffer_index = -1;
if (p_type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
//is texture
global_variables.must_update_texture_materials = true; //normally ther are no
} else {
gv.buffer_elements = 1;
if (p_type == RS::GLOBAL_VAR_TYPE_COLOR || p_type == RS::GLOBAL_VAR_TYPE_MAT2) {
//color needs to elements to store srgb and linear
gv.buffer_elements = 2;
}
if (p_type == RS::GLOBAL_VAR_TYPE_MAT3 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM_2D) {
//color needs to elements to store srgb and linear
gv.buffer_elements = 3;
}
if (p_type == RS::GLOBAL_VAR_TYPE_MAT4 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM) {
//color needs to elements to store srgb and linear
gv.buffer_elements = 4;
}
//is vector, allocate in buffer and update index
gv.buffer_index = _global_variable_allocate(gv.buffer_elements);
ERR_FAIL_COND_MSG(gv.buffer_index < 0, vformat("Failed allocating global variable '%s' out of buffer memory. Consider increasing it in the Project Settings.", String(p_name)));
global_variables.buffer_usage[gv.buffer_index].elements = gv.buffer_elements;
_global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
global_variables.must_update_buffer_materials = true; //normally ther are no
}
global_variables.variables[p_name] = gv;
}
void RasterizerStorageRD::global_variable_remove(const StringName &p_name) {
if (!global_variables.variables.has(p_name)) {
return;
}
GlobalVariables::Variable &gv = global_variables.variables[p_name];
if (gv.buffer_index >= 0) {
global_variables.buffer_usage[gv.buffer_index].elements = 0;
global_variables.must_update_buffer_materials = true;
} else {
global_variables.must_update_texture_materials = true;
}
global_variables.variables.erase(p_name);
}
Vector<StringName> RasterizerStorageRD::global_variable_get_list() const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
}
const StringName *K = NULL;
Vector<StringName> names;
while ((K = global_variables.variables.next(K))) {
names.push_back(*K);
}
names.sort_custom<StringName::AlphCompare>();
return names;
}
void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND(!global_variables.variables.has(p_name));
GlobalVariables::Variable &gv = global_variables.variables[p_name];
gv.value = p_value;
if (gv.override.get_type() == Variant::NIL) {
if (gv.buffer_index >= 0) {
//buffer
_global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
} else {
//texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material);
_material_queue_update(material, false, true);
}
}
}
}
void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) {
if (!global_variables.variables.has(p_name)) {
return; //variable may not exist
}
GlobalVariables::Variable &gv = global_variables.variables[p_name];
gv.override = p_value;
if (gv.buffer_index >= 0) {
//buffer
if (gv.override.get_type() == Variant::NIL) {
_global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
} else {
_global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.override);
}
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
} else {
//texture
//texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material);
_material_queue_update(material, false, true);
}
}
}
Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance.");
}
if (!global_variables.variables.has(p_name)) {
return Variant();
}
return global_variables.variables[p_name].value;
}
RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(const StringName &p_name) const {
if (!global_variables.variables.has(p_name)) {
return RS::GLOBAL_VAR_TYPE_MAX;
}
return global_variables.variables[p_name].type;
}
RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance.");
}
return global_variable_get_type_internal(p_name);
}
void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) {
List<PropertyInfo> settings;
ProjectSettings::get_singleton()->get_property_list(&settings);
for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) {
if (E->get().name.begins_with("shader_globals/")) {
StringName name = E->get().name.get_slice("/", 1);
Dictionary d = ProjectSettings::get_singleton()->get(E->get().name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
String type = d["type"];
static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
"bool",
"bvec2",
"bvec3",
"bvec4",
"int",
"ivec2",
"ivec3",
"ivec4",
"rect2i",
"uint",
"uvec2",
"uvec3",
"uvec4",
"float",
"vec2",
"vec3",
"vec4",
"color",
"rect2",
"mat2",
"mat3",
"mat4",
"transform_2d",
"transform",
"sampler2D",
"sampler2DArray",
"sampler3D",
"samplerCube",
};
RS::GlobalVariableType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
if (global_var_type_names[i] == type) {
gvtype = RS::GlobalVariableType(i);
break;
}
}
ERR_CONTINUE(gvtype == RS::GLOBAL_VAR_TYPE_MAX); //type invalid
Variant value = d["value"];
if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
//textire
if (!p_load_textures) {
value = RID();
continue;
}
String path = value;
RES resource = ResourceLoader::load(path);
ERR_CONTINUE(resource.is_null());
value = resource;
}
if (global_variables.variables.has(name)) {
//has it, update it
global_variable_set(name, value);
} else {
global_variable_add(name, gvtype, value);
}
}
}
}
void RasterizerStorageRD::global_variables_clear() {
global_variables.variables.clear(); //not right but for now enough
}
RID RasterizerStorageRD::global_variables_get_storage_buffer() const {
return global_variables.buffer;
}
int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) {
ERR_FAIL_COND_V(global_variables.instance_buffer_pos.has(p_instance), -1);
int32_t pos = _global_variable_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
global_variables.instance_buffer_pos[p_instance] = pos; //save anyway
ERR_FAIL_COND_V_MSG(pos < 0, -1, "Too many instances using shader instance variables. Increase buffer size in Project Settings.");
global_variables.buffer_usage[pos].elements = ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES;
return pos;
}
void RasterizerStorageRD::global_variables_instance_free(RID p_instance) {
ERR_FAIL_COND(!global_variables.instance_buffer_pos.has(p_instance));
int32_t pos = global_variables.instance_buffer_pos[p_instance];
if (pos >= 0) {
global_variables.buffer_usage[pos].elements = 0;
}
global_variables.instance_buffer_pos.erase(p_instance);
}
void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) {
if (!global_variables.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
int32_t pos = global_variables.instance_buffer_pos[p_instance];
if (pos < 0) {
return; //again, not allocated, ignore
}
ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
ShaderLanguage::TYPE_MAX, //nil
ShaderLanguage::TYPE_BOOL, //bool
ShaderLanguage::TYPE_INT, //int
ShaderLanguage::TYPE_FLOAT, //float
ShaderLanguage::TYPE_MAX, //string
ShaderLanguage::TYPE_VEC2, //vec2
ShaderLanguage::TYPE_IVEC2, //vec2i
ShaderLanguage::TYPE_VEC4, //rect2
ShaderLanguage::TYPE_IVEC4, //rect2i
ShaderLanguage::TYPE_VEC3, // vec3
ShaderLanguage::TYPE_IVEC3, //vec3i
ShaderLanguage::TYPE_MAX, //xform2d not supported here
ShaderLanguage::TYPE_VEC4, //plane
ShaderLanguage::TYPE_VEC4, //quat
ShaderLanguage::TYPE_MAX, //aabb not supported here
ShaderLanguage::TYPE_MAX, //basis not supported here
ShaderLanguage::TYPE_MAX, //xform not supported here
ShaderLanguage::TYPE_VEC4 //color
};
ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
pos += p_index;
_fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
_global_variable_mark_buffer_dirty(pos, 1);
}
void RasterizerStorageRD::_update_global_variables() {
if (global_variables.buffer_dirty_region_count > 0) {
uint32_t total_regions = global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
if (total_regions / global_variables.buffer_dirty_region_count <= 4) {
// 25% of regions dirty, just update all buffer
RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values);
zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions);
} else {
uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
for (uint32_t i = 0; i < total_regions; i++) {
if (global_variables.buffer_dirty_regions[i]) {
RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, global_variables.buffer_values);
global_variables.buffer_dirty_regions[i] = false;
}
}
}
global_variables.buffer_dirty_region_count = 0;
}
if (global_variables.must_update_buffer_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, true, false);
}
global_variables.must_update_buffer_materials = false;
}
if (global_variables.must_update_texture_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, false, true);
print_line("update material texture?");
}
global_variables.must_update_texture_materials = false;
}
}
void RasterizerStorageRD::update_dirty_resources() {
_update_global_variables(); //must do before materials, so it can queue them for update
_update_queued_materials();
_update_dirty_multimeshes();
_update_dirty_skeletons();
@@ -4806,12 +5622,27 @@ String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const
return RD::get_singleton()->get_captured_timestamp_name(p_index);
}
RasterizerStorageRD *RasterizerStorageRD::base_singleton = nullptr;
RasterizerStorageRD::RasterizerStorageRD() {
base_singleton = this;
for (int i = 0; i < SHADER_TYPE_MAX; i++) {
shader_data_request_func[i] = nullptr;
}
static_assert(sizeof(GlobalVariables::Value) == 16);
global_variables.buffer_size = GLOBAL_GET("rendering/high_end/global_shader_variables_buffer_size");
global_variables.buffer_size = MAX(4096, global_variables.buffer_size);
global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size);
zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size);
global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size);
material_update_list = nullptr;
{ //create default textures
@@ -5165,6 +5996,11 @@ RasterizerStorageRD::RasterizerStorageRD() {
RasterizerStorageRD::~RasterizerStorageRD() {
memdelete_arr(global_variables.buffer_values);
memdelete_arr(global_variables.buffer_usage);
memdelete_arr(global_variables.buffer_dirty_regions);
RD::get_singleton()->free(global_variables.buffer);
//def textures
for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
RD::get_singleton()->free(default_rd_textures[i]);

View File

@@ -52,6 +52,8 @@ public:
virtual void set_code(const String &p_Code) = 0;
virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
virtual void get_instance_param_list(List<InstanceShaderParam> *p_param_list) const = 0;
virtual bool is_param_texture(const StringName &p_param) const = 0;
virtual bool is_animated() const = 0;
virtual bool casts_shadows() const = 0;
@@ -69,7 +71,15 @@ public:
virtual void set_render_priority(int p_priority) = 0;
virtual void set_next_pass(RID p_pass) = 0;
virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
virtual ~MaterialData() {}
virtual ~MaterialData();
private:
friend class RasterizerStorageRD;
RID self;
List<RID>::Element *global_buffer_E = nullptr;
List<RID>::Element *global_texture_E = nullptr;
uint64_t global_textures_pass = 0;
Map<StringName, uint64_t> used_global_textures;
};
typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
@@ -555,6 +565,73 @@ private:
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
/* GLOBAL SHADER VARIABLES */
struct GlobalVariables {
enum {
BUFFER_DIRTY_REGION_SIZE = 1024
};
struct Variable {
Set<RID> texture_materials; // materials using this
RS::GlobalVariableType type;
Variant value;
Variant override;
int32_t buffer_index; //for vectors
int32_t buffer_elements; //for vectors
};
HashMap<StringName, Variable> variables;
struct Value {
float x;
float y;
float z;
float w;
};
struct ValueInt {
int32_t x;
int32_t y;
int32_t z;
int32_t w;
};
struct ValueUInt {
uint32_t x;
uint32_t y;
uint32_t z;
uint32_t w;
};
struct ValueUsage {
uint32_t elements = 0;
};
List<RID> materials_using_buffer;
List<RID> materials_using_texture;
RID buffer;
Value *buffer_values;
ValueUsage *buffer_usage;
bool *buffer_dirty_regions;
uint32_t buffer_dirty_region_count = 0;
uint32_t buffer_size;
bool must_update_texture_materials = false;
bool must_update_buffer_materials = false;
HashMap<RID, int32_t> instance_buffer_pos;
} global_variables;
int32_t _global_variable_allocate(uint32_t p_elements);
void _global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value);
void _global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
void _update_global_variables();
/* EFFECTS */
RasterizerEffectsRD effects;
@@ -675,6 +752,8 @@ public:
bool material_is_animated(RID p_material);
bool material_casts_shadows(RID p_material);
void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters);
void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
void material_force_update_textures(RID p_material, ShaderType p_shader_type);
@@ -1246,6 +1325,27 @@ public:
virtual bool particles_is_inactive(RID p_particles) const { return false; }
/* GLOBAL VARIABLES API */
virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value);
virtual void global_variable_remove(const StringName &p_name);
virtual Vector<StringName> global_variable_get_list() const;
virtual void global_variable_set(const StringName &p_name, const Variant &p_value);
virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value);
virtual Variant global_variable_get(const StringName &p_name) const;
virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const;
RS::GlobalVariableType global_variable_get_type_internal(const StringName &p_name) const;
virtual void global_variables_load_settings(bool p_load_textures = true);
virtual void global_variables_clear();
virtual int32_t global_variables_instance_allocate(RID p_instance);
virtual void global_variables_instance_free(RID p_instance);
virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value);
RID global_variables_get_storage_buffer() const;
/* RENDER TARGET API */
RID render_target_create();
@@ -1295,7 +1395,7 @@ public:
virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
virtual String get_captured_timestamp_name(uint32_t p_index) const;
static RasterizerStorage *base_singleton;
static RasterizerStorageRD *base_singleton;
RasterizerEffectsRD *get_effects();

View File

@@ -32,6 +32,8 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "rasterizer_storage_rd.h"
#include "servers/rendering_server.h"
#define SL ShaderLanguage
@@ -91,6 +93,9 @@ static int _get_datatype_size(SL::DataType p_type) {
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
case SL::TYPE_STRUCT: return 0;
case SL::TYPE_MAX: {
ERR_FAIL_V(0);
};
}
ERR_FAIL_V(0);
@@ -131,6 +136,9 @@ static int _get_datatype_alignment(SL::DataType p_type) {
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
case SL::TYPE_STRUCT: return 0;
case SL::TYPE_MAX: {
ERR_FAIL_V(0);
}
}
ERR_FAIL_V(0);
@@ -341,6 +349,71 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
}
}
static String _get_global_variable_from_type_and_index(const String &p_buffer, const String &p_index, ShaderLanguage::DataType p_type) {
switch (p_type) {
case ShaderLanguage::TYPE_BOOL: {
return "(" + p_buffer + "[" + p_index + "].x != 0.0)";
}
case ShaderLanguage::TYPE_BVEC2: {
return "(" + p_buffer + "[" + p_index + "].xy != vec2(0.0))";
}
case ShaderLanguage::TYPE_BVEC3: {
return "(" + p_buffer + "[" + p_index + "].xyz != vec3(0.0))";
}
case ShaderLanguage::TYPE_BVEC4: {
return "(" + p_buffer + "[" + p_index + "].xyzw != vec4(0.0))";
}
case ShaderLanguage::TYPE_INT: {
return "floatBitsToInt(" + p_buffer + "[" + p_index + "].x)";
}
case ShaderLanguage::TYPE_IVEC2: {
return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xy)";
}
case ShaderLanguage::TYPE_IVEC3: {
return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyz)";
}
case ShaderLanguage::TYPE_IVEC4: {
return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyzw)";
}
case ShaderLanguage::TYPE_UINT: {
return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].x)";
}
case ShaderLanguage::TYPE_UVEC2: {
return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xy)";
}
case ShaderLanguage::TYPE_UVEC3: {
return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyz)";
}
case ShaderLanguage::TYPE_UVEC4: {
return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyzw)";
}
case ShaderLanguage::TYPE_FLOAT: {
return "(" + p_buffer + "[" + p_index + "].x)";
}
case ShaderLanguage::TYPE_VEC2: {
return "(" + p_buffer + "[" + p_index + "].xy)";
}
case ShaderLanguage::TYPE_VEC3: {
return "(" + p_buffer + "[" + p_index + "].xyz)";
}
case ShaderLanguage::TYPE_VEC4: {
return "(" + p_buffer + "[" + p_index + "].xyzw)";
}
case ShaderLanguage::TYPE_MAT2: {
return "mat2(" + p_buffer + "[" + p_index + "].xy," + p_buffer + "[" + p_index + "+1].xy)";
}
case ShaderLanguage::TYPE_MAT3: {
return "mat3(" + p_buffer + "[" + p_index + "].xyz," + p_buffer + "[" + p_index + "+1].xyz," + p_buffer + "[" + p_index + "+2].xyz)";
}
case ShaderLanguage::TYPE_MAT4: {
return "mat4(" + p_buffer + "[" + p_index + "].xyzw," + p_buffer + "[" + p_index + "+1].xyzw," + p_buffer + "[" + p_index + "+2].xyzw," + p_buffer + "[" + p_index + "+3].xyzw)";
}
default: {
ERR_FAIL_V("void");
}
}
}
String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
String code;
@@ -408,10 +481,17 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
int max_uniforms = 0;
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
if (SL::is_sampler_type(E->get().type))
if (SL::is_sampler_type(E->get().type)) {
max_texture_uniforms++;
else
} else {
if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue; //instances are indexed directly, dont need index uniforms
}
max_uniforms++;
}
}
r_gen_code.texture_uniforms.resize(max_texture_uniforms);
@@ -428,12 +508,25 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
String ucode;
if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
//insert, but don't generate any code.
p_actions.uniforms->insert(E->key(), E->get());
continue; //instances are indexed directly, dont need index uniforms
}
if (SL::is_sampler_type(E->get().type)) {
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
}
ucode += _prestr(E->get().precision);
ucode += _typestr(E->get().type);
bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
if (is_buffer_global) {
//this is an integer to index the global table
ucode += _typestr(ShaderLanguage::TYPE_UINT);
} else {
ucode += _prestr(E->get().precision);
ucode += _typestr(E->get().type);
}
ucode += " " + _mkid(E->key());
ucode += ";\n";
if (SL::is_sampler_type(E->get().type)) {
@@ -446,6 +539,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
texture.type = E->get().type;
texture.filter = E->get().filter;
texture.repeat = E->get().repeat;
texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
if (texture.global) {
r_gen_code.uses_global_textures = true;
}
r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
} else {
@@ -455,8 +552,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uses_uniforms = true;
}
uniform_defines.write[E->get().order] = ucode;
uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
if (is_buffer_global) {
//globals are indices into the global table
uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
} else {
uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
}
}
p_actions.uniforms->insert(E->key(), E->get());
@@ -690,9 +793,29 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (p_default_actions.renames.has(vnode->name))
code = p_default_actions.renames[vnode->name];
else {
code = _mkid(vnode->name);
if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) {
code = actions.base_uniform_string + code;
if (shader->uniforms.has(vnode->name)) {
//its a uniform!
const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name];
if (u.texture_order >= 0) {
code = _mkid(vnode->name); //texture, use as is
} else {
//a scalar or vector
if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
code = actions.base_uniform_string + _mkid(vnode->name); //texture, use as is
//global variable, this means the code points to an index to the global table
code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
} else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
//instance variable, index it as such
code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")";
code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
} else {
//regular uniform, index from UBO
code = actions.base_uniform_string + _mkid(vnode->name);
}
}
} else {
code = _mkid(vnode->name); //its something else (local var most likely) use as is
}
}
@@ -1037,9 +1160,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
return code;
}
ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &p_type) {
RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RasterizerStorage::base_singleton))->global_variable_get_type_internal(p_type);
return RS::global_variable_type_get_shader_datatype(gvt);
}
Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types());
Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
if (err != OK) {
@@ -1060,6 +1188,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
r_gen_code.light = String();
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
used_name_defines.clear();
used_rmode_defines.clear();

View File

@@ -57,6 +57,7 @@ public:
ShaderLanguage::ShaderNode::Uniform::Hint hint;
ShaderLanguage::TextureFilter filter;
ShaderLanguage::TextureRepeat repeat;
bool global;
};
Vector<Texture> texture_uniforms;
@@ -70,6 +71,7 @@ public:
String fragment;
String light;
bool uses_global_textures;
bool uses_fragment_time;
bool uses_vertex_time;
};
@@ -86,6 +88,8 @@ public:
int base_texture_binding_index = 0;
int texture_layout_set = 0;
String base_uniform_string;
String global_buffer_array_variable;
String instance_uniform_index_variable;
uint32_t base_varying_index = 0;
};
@@ -113,6 +117,8 @@ private:
DefaultIdentifierActions actions;
static ShaderLanguage::DataType _get_variable_type(const StringName &p_type);
public:
Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);

View File

@@ -132,6 +132,11 @@ layout(set = 2, binding = 6) uniform sampler shadow_sampler;
#endif
layout(set = 2, binding = 7, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
/* SET3: Render Target Data */
#ifdef SCREEN_TEXTURE_USED

View File

@@ -134,7 +134,7 @@ struct InstanceData {
mat4 transform;
mat4 normal_transform;
uint flags;
uint instance_ofs; //instance_offset in instancing/skeleton buffer
uint instance_uniforms_ofs; //base offset in global buffer for instance variables
uint gi_offset; //GI information when using lightmapping (VCT or lightmap)
uint layer_mask;
};
@@ -287,6 +287,11 @@ cluster_data;
layout(set = 0, binding = 15) uniform texture2D directional_shadow_atlas;
layout(set = 0, binding = 16, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
// decal atlas
/* Set 1, Radiance */

View File

@@ -58,6 +58,11 @@ params;
layout(set = 0, binding = 0) uniform sampler material_samplers[12];
layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
#ifdef USE_MATERIAL_UNIFORMS
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
/* clang-format off */