summaryrefslogtreecommitdiff
path: root/servers/visual
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2019-07-21 11:31:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2020-02-11 11:53:29 +0100
commit8bbbb973361f367a4888629c571fb6f43581269d (patch)
tree89724be2ee4a81111bedd383668665e0ae3bf276 /servers/visual
parent50e9befb888480a3d6cb2fa46b58c0753b69bd86 (diff)
Completed material/2D shader support (missing SCREEN_TEXTURE)
Diffstat (limited to 'servers/visual')
-rw-r--r--servers/visual/rasterizer/rasterizer.cpp25
-rw-r--r--servers/visual/rasterizer/rasterizer.h77
-rw-r--r--servers/visual/rasterizer/rasterizer_canvas_rd.cpp811
-rw-r--r--servers/visual/rasterizer/rasterizer_canvas_rd.h93
-rw-r--r--servers/visual/rasterizer/rasterizer_rd.cpp4
-rw-r--r--servers/visual/rasterizer/rasterizer_rd.h2
-rw-r--r--servers/visual/rasterizer/rasterizer_storage_rd.cpp1056
-rw-r--r--servers/visual/rasterizer/rasterizer_storage_rd.h227
-rw-r--r--servers/visual/rasterizer/shader_compiler_rd.cpp1003
-rw-r--r--servers/visual/rasterizer/shader_compiler_rd.h92
-rw-r--r--servers/visual/rasterizer/shader_rd.cpp8
-rw-r--r--servers/visual/rasterizer/shaders/canvas.glsl60
-rw-r--r--servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl31
-rw-r--r--servers/visual/shader_language.cpp305
-rw-r--r--servers/visual/shader_language.h43
-rw-r--r--servers/visual/shader_types.cpp26
-rw-r--r--servers/visual/visual_server_raster.h1
-rw-r--r--servers/visual/visual_server_scene.cpp93
-rw-r--r--servers/visual/visual_server_scene.h22
-rw-r--r--servers/visual/visual_server_wrap_mt.h1
20 files changed, 3520 insertions, 460 deletions
diff --git a/servers/visual/rasterizer/rasterizer.cpp b/servers/visual/rasterizer/rasterizer.cpp
index 647908c75f..64b5c88699 100644
--- a/servers/visual/rasterizer/rasterizer.cpp
+++ b/servers/visual/rasterizer/rasterizer.cpp
@@ -35,6 +35,31 @@
Rasterizer *(*Rasterizer::_create_func)() = NULL;
+void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) {
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependency_changed(p_aabb, p_dependencies);
+ }
+}
+void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) {
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependency_deleted(p_deleted);
+ }
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependencies.erase(this);
+ }
+}
+
+RasterizerScene::InstanceDependency::~InstanceDependency() {
+#ifdef DEBUG_ENABLED
+ if (instances.size()) {
+ WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing.");
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependencies.erase(this);
+ }
+ }
+#endif
+}
+
Rasterizer *Rasterizer::create() {
return _create_func();
diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer/rasterizer.h
index 7ee7107fab..c8b756fb4a 100644
--- a/servers/visual/rasterizer/rasterizer.h
+++ b/servers/visual/rasterizer/rasterizer.h
@@ -34,6 +34,7 @@
#include "core/math/camera_matrix.h"
#include "servers/visual_server.h"
+#include "core/pair.h"
#include "core/self_list.h"
class RasterizerScene {
@@ -85,6 +86,20 @@ public:
virtual VS::EnvironmentBG environment_get_background(RID p_env) = 0;
virtual int environment_get_canvas_max_layer(RID p_env) = 0;
+ struct InstanceBase;
+
+ struct InstanceDependency {
+
+ void instance_notify_changed(bool p_aabb, bool p_dependencies);
+ void instance_notify_deleted(RID p_deleted);
+
+ ~InstanceDependency();
+
+ private:
+ friend class InstanceBase;
+ Map<InstanceBase *, uint32_t> instances;
+ };
+
struct InstanceBase {
VS::InstanceType base_type;
@@ -97,6 +112,7 @@ public:
int depth_layer;
uint32_t layer_mask;
+ uint32_t instance_version;
//RID sampled_light;
@@ -124,8 +140,48 @@ public:
RID lightmap;
Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
- virtual void base_removed() = 0;
- virtual void base_changed(bool p_aabb, bool p_materials) = 0;
+ virtual void dependency_deleted(RID p_dependency) = 0;
+ virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
+
+ Set<InstanceDependency *> dependencies;
+
+ void instance_increase_version() {
+ instance_version++;
+ }
+
+ void update_dependency(InstanceDependency *p_dependency) {
+ dependencies.insert(p_dependency);
+ p_dependency->instances[this] = instance_version;
+ }
+
+ void clean_up_dependencies() {
+ List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> > to_clean_up;
+ for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+ InstanceDependency *dep = E->get();
+ Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this);
+ ERR_CONTINUE(!F);
+ if (F->get() != instance_version) {
+ Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p;
+ p.first = dep;
+ p.second = F;
+ to_clean_up.push_back(p);
+ }
+ }
+
+ while (to_clean_up.size()) {
+ to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second);
+ to_clean_up.pop_front();
+ }
+ }
+
+ void clear_dependencies() {
+ for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+ InstanceDependency *dep = E->get();
+ dep->instances.erase(this);
+ }
+ dependencies.clear();
+ }
+
InstanceBase() :
dependency_item(this) {
@@ -135,10 +191,15 @@ public:
visible = true;
depth_layer = 0;
layer_mask = 1;
+ instance_version = 0;
baked_light = false;
redraw_if_visible = false;
lightmap_capture = NULL;
}
+
+ virtual ~InstanceBase() {
+ clear_dependencies();
+ }
};
virtual RID light_instance_create(RID p_light) = 0;
@@ -241,7 +302,6 @@ public:
virtual void material_set_render_priority(RID p_material, int priority) = 0;
virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
- virtual RID material_get_shader(RID p_shader_material) const = 0;
virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
@@ -251,8 +311,7 @@ public:
virtual bool material_is_animated(RID p_material) = 0;
virtual bool material_casts_shadows(RID p_material) = 0;
- virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
- virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
+ virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
/* MESH API */
@@ -413,11 +472,8 @@ public:
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0;
virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
- virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) = 0;
- virtual void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) = 0;
-
- virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
- virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+ virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+ virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
/* GI PROBE API */
@@ -578,6 +634,7 @@ public:
virtual String get_video_adapter_vendor() const = 0;
static RasterizerStorage *base_singleton;
+
RasterizerStorage();
virtual ~RasterizerStorage() {}
};
diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp
index 7e415e6868..d9cd19e0cb 100644
--- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp
+++ b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp
@@ -1,5 +1,7 @@
#include "rasterizer_canvas_rd.h"
#include "core/math/math_funcs.h"
+#include "core/project_settings.h"
+
void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.elements[0][0];
@@ -82,7 +84,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
RID texture = storage->texture_get_rd_texture(p_texture);
if (!texture.is_valid()) {
//use default white texture
- texture = default_textures.white_texture;
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
}
u.ids.push_back(texture);
uniform_set.push_back(u);
@@ -95,7 +97,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
RID texture = storage->texture_get_rd_texture(p_normalmap);
if (!texture.is_valid()) {
//use default normal texture
- texture = default_textures.normal_texture;
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
}
u.ids.push_back(texture);
uniform_set.push_back(u);
@@ -108,7 +110,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
RID texture = storage->texture_get_rd_texture(p_specular);
if (!texture.is_valid()) {
//use default white texture
- texture = default_textures.white_texture;
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
}
u.ids.push_back(texture);
uniform_set.push_back(u);
@@ -118,7 +120,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 4;
- RID sampler = default_samplers.samplers[p_filter][p_repeat];
+ RID sampler = storage->sampler_rd_get_default(p_filter, p_repeat);
ERR_FAIL_COND_V(sampler.is_null(), RID());
u.ids.push_back(sampler);
uniform_set.push_back(u);
@@ -128,7 +130,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
u.binding = 5;
- u.ids.push_back(default_textures.default_multimesh_tb);
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER));
uniform_set.push_back(u);
}
@@ -488,7 +490,7 @@ Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD:
}
////////////////////
-void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights) {
+void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
//create an empty push constant
@@ -566,98 +568,19 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
}
- if (light_count) {
-
- //validate and update lighs if they are being used
- bool invalid_uniform = state_data->light_uniform_set.is_valid() && !RD::get_singleton()->uniform_set_is_valid(state_data->light_uniform_set);
+ {
- if (state_data->light_uniform_set.is_null() || invalid_uniform || light_uniform_set_dirty) {
- //recreate uniform set
- if (state_data->light_uniform_set.is_valid() && !invalid_uniform) {
- RD::get_singleton()->free(state_data->light_uniform_set);
- }
+ RID &canvas_item_state = light_count ? state_data->state_uniform_set_with_light : state_data->state_uniform_set;
- state_data->light_uniform_set = RID();
+ bool invalid_uniform = canvas_item_state.is_valid() && !RD::get_singleton()->uniform_set_is_valid(canvas_item_state);
+ if (canvas_item_state.is_null() || invalid_uniform || (light_count > 0 && light_uniform_set_dirty)) {
+ //re create canvas state
Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(state.lights_uniform_buffer);
- uniforms.push_back(u);
- }
-
- {
-
- RD::Uniform u_lights;
- u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
- u_lights.binding = 1;
-
- RD::Uniform u_shadows;
- u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
- u_shadows.binding = 2;
-
- //lights
- for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
- if (i < light_count) {
-
- CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
- ERR_CONTINUE(!cl);
-
- RID rd_texture;
-
- if (cl->texture.is_valid()) {
- rd_texture = storage->texture_get_rd_texture(cl->texture);
- }
- if (rd_texture.is_valid()) {
- u_lights.ids.push_back(rd_texture);
- } else {
- u_lights.ids.push_back(default_textures.white_texture);
- }
- if (cl->shadow.texture.is_valid()) {
- u_shadows.ids.push_back(cl->shadow.texture);
- } else {
- u_shadows.ids.push_back(default_textures.black_texture);
- }
- } else {
- u_lights.ids.push_back(default_textures.white_texture);
- u_shadows.ids.push_back(default_textures.black_texture);
- }
- }
-
- uniforms.push_back(u_lights);
- uniforms.push_back(u_shadows);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 3;
- u.ids.push_back(state.shadow_sampler);
- uniforms.push_back(u);
- }
-
- state_data->light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 3);
- }
-
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, state_data->light_uniform_set, 3);
- light_mode = PIPELINE_LIGHT_MODE_ENABLED;
- } else {
- light_mode = PIPELINE_LIGHT_MODE_DISABLED;
- }
-
- {
- //state uniform
- bool invalid_uniform = state_data->state_uniform_set.is_valid() && !RD::get_singleton()->uniform_set_is_valid(state_data->state_uniform_set);
-
- if (state_data->state_uniform_set.is_null() || invalid_uniform) {
- if (state_data->state_uniform_set.is_valid() && !invalid_uniform) {
- RD::get_singleton()->free(state_data->state_uniform_set);
+ if (state_data->state_uniform_set_with_light.is_valid() && !invalid_uniform) {
+ RD::get_singleton()->free(canvas_item_state);
}
- state_data->state_uniform_set = RID();
-
- Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
@@ -674,14 +597,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(state.canvas_state_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
u.binding = 1;
u.ids.push_back(shader.default_skeleton_texture_buffer);
@@ -697,19 +612,86 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
}
}
- state_data->state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
+ //validate and update lighs if they are being used
+
+ if (light_count > 0) {
+ //recreate uniform set
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(state.lights_uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+
+ RD::Uniform u_lights;
+ u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
+ u_lights.binding = 4;
+
+ RD::Uniform u_shadows;
+ u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
+ u_shadows.binding = 5;
+
+ //lights
+ for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
+ if (i < light_count) {
+
+ CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
+ ERR_CONTINUE(!cl);
+
+ RID rd_texture;
+
+ if (cl->texture.is_valid()) {
+ rd_texture = storage->texture_get_rd_texture(cl->texture);
+ }
+ if (rd_texture.is_valid()) {
+ u_lights.ids.push_back(rd_texture);
+ } else {
+ u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ }
+ if (cl->shadow.texture.is_valid()) {
+ u_shadows.ids.push_back(cl->shadow.texture);
+ } else {
+ u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ }
+ } else {
+ u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ }
+ }
+
+ uniforms.push_back(u_lights);
+ uniforms.push_back(u_shadows);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(state.shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 2);
+ } else {
+ canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
+ }
}
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, state_data->state_uniform_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, canvas_item_state, 2);
}
- PipelineVariants *pipeline_variants = &shader.pipeline_variants;
+ light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
+
+ PipelineVariants *pipeline_variants = p_pipeline_variants;
bool reclip = false;
const Item::Command *c = p_item->commands;
while (c) {
-
push_constant.flags = base_flags; //reset on each command for sanity
push_constant.specular_shininess = 0xFFFFFFFF;
@@ -1341,6 +1323,10 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
+ RID prev_material;
+
+ PipelineVariants *pipeline_variants = &shader.pipeline_variants;
+
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
@@ -1360,7 +1346,34 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
}
}
- _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights);
+ if (ci->material != prev_material) {
+
+ MaterialData *material_data;
+ if (ci->material.is_valid()) {
+ material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+ print_line("has material data");
+ }
+
+ if (material_data) {
+
+ if (material_data->shader_data->version.is_valid()) {
+ pipeline_variants = &material_data->shader_data->pipeline_variants;
+ if (material_data->uniform_set.is_valid()) {
+ print_line("bound uniform set");
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1);
+ }
+ } else {
+ pipeline_variants = &shader.pipeline_variants;
+ }
+ } else {
+ pipeline_variants = &shader.pipeline_variants;
+ }
+ }
+
+ print_line("go render");
+ _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+
+ prev_material = ci->material;
}
RD::get_singleton()->draw_list_end();
@@ -1397,6 +1410,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
state_buffer.canvas_modulate[2] = p_modulate.b;
state_buffer.canvas_modulate[3] = p_modulate.a;
+ state_buffer.time = state.time;
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
}
@@ -1462,26 +1476,46 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
}
//fill the list until rendering is possible.
+ bool material_screen_texture_found = false;
Item *ci = p_item_list;
+ Rect2 back_buffer_rect;
+ bool backbuffer_copy = false;
+
while (ci) {
- items[item_count++] = ci;
+ if (ci->copy_back_buffer) {
+ backbuffer_copy = true;
- bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE
- if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) {
+ if (ci->copy_back_buffer->full) {
+ back_buffer_rect = Rect2();
+ } else {
+ back_buffer_rect = ci->copy_back_buffer->rect;
+ }
+ }
+
+ if (!material_screen_texture_found && ci->material.is_valid()) {
+ MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+ if (md->shader_data->uses_screen_texture) {
+ backbuffer_copy = true;
+ back_buffer_rect = Rect2();
+ }
+ }
+
+ if (backbuffer_copy) {
+ //render anything pending, including clearing if no items
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
- //then reset
item_count = 0;
- }
- if (ci->copy_back_buffer) {
+ backbuffer_copy = false;
+ material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ }
- if (ci->copy_back_buffer->full) {
+ items[item_count++] = ci;
- //_copy_texscreen(Rect2());
- } else {
- //_copy_texscreen(ci->copy_back_buffer->rect);
- }
+ if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ //then reset
+ item_count = 0;
}
ci = ci->next;
@@ -1734,139 +1768,390 @@ void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::Canv
oc->cull_mode = p_mode;
}
-void RasterizerCanvasRD::update() {
- _dispose_bindings();
-}
+void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
+ //compile
-RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
- storage = p_storage;
+ print_line("shader set code?");
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+ uses_material_samplers = false;
- { //create default textures
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tformat.width = 4;
- tformat.height = 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- tformat.type = RD::TEXTURE_TYPE_2D;
+ ShaderCompilerRD::GeneratedCode gen_code;
- PoolVector<uint8_t> pv;
- pv.resize(16 * 4);
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 255);
- pv.set(i * 4 + 1, 255);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
+ int light_mode = LIGHT_MODE_NORMAL;
+ int blend_mode = BLEND_MODE_MIX;
+ bool uses_screen_texture = false;
+
+ ShaderCompilerRD::IdentifierActions actions;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+ actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
+ actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
+
+ actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED);
+ actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY);
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+
+ actions.uniforms = &uniforms;
+
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+
+ Error err = canvas_singleton->shader.compiler.compile(VS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = canvas_singleton->shader.canvas_shader.version_create();
+ }
+
+ if (gen_code.texture_uniforms.size() || uses_screen_texture) { //requires the samplers
+ gen_code.defines.push_back("\n#define USE_MATERIAL_SAMPLERS\n");
+ uses_material_samplers = true;
+ }
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+ canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //update them pipelines
+
+ RD::PipelineColorBlendState::Attachment attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_DISABLED: {
+
+ // nothing to do here, disabled by default
+
+ } break;
+ case BLEND_MODE_MIX: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+ } break;
+ case BLEND_MODE_SUB: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+ } break;
+ case BLEND_MODE_MUL: {
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+
+ } break;
+ case BLEND_MODE_PMALPHA: {
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ }
+
+ RD::PipelineColorBlendState blend_state;
+ blend_state.attachments.push_back(attachment);
+
+ //update pipelines
+
+ for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
+ for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
+ RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_POINTS,
+ };
+ ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
+ { //non lit
+ SHADER_VARIANT_QUAD,
+ SHADER_VARIANT_NINEPATCH,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE_POINTS,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES_POINTS },
+ { //lit
+ SHADER_VARIANT_QUAD_LIGHT,
+ SHADER_VARIANT_NINEPATCH_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+ };
+
+ RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
+ pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
}
+ }
- {
- Vector<PoolVector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_textures.white_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ valid = true;
+}
+
+void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
}
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerCanvasRD::ShaderData::is_animated() const {
+ return false;
+}
+bool RasterizerCanvasRD::ShaderData::casts_shadows() const {
+ return false;
+}
+Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RasterizerCanvasRD::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+ uses_material_samplers = false;
+}
+
+RasterizerCanvasRD::ShaderData::~ShaderData() {
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+ ERR_FAIL_COND(!canvas_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ canvas_singleton->shader.canvas_shader.version_free(version);
+ }
+}
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 255);
+RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
}
- {
- Vector<PoolVector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_textures.black_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
}
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 128);
- pv.set(i * 4 + 1, 128);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
}
+ }
- {
- Vector<PoolVector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_textures.normal_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
}
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw());
+ }
+
+ if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 255);
- pv.set(i * 4 + 1, 128);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->uses_material_samplers) {
+ //needs samplers for the material (uses custom textures) create them
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 0;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
}
- {
- Vector<PoolVector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_textures.aniso_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
}
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 0);
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
}
+ }
- default_textures.default_multimesh_tb = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), 1);
+}
+RasterizerCanvasRD::MaterialData::~MaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
}
- { //create default samplers
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
- for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::SamplerState sampler_state;
- switch (i) {
- case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.max_lod = 0;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
-
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.max_lod = 0;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
-
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- } break;
- default: {
- }
- }
- switch (j) {
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
-
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-
- } break;
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- } break;
- default: {
- }
- }
+RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_create_material_func(ShaderData *p_shader) {
+ MaterialData *material_data = memnew(MaterialData);
+ material_data->shader_data = p_shader;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
- default_samplers.samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
- }
- }
+void RasterizerCanvasRD::set_time(double p_time) {
+ state.time = p_time;
+}
+
+void RasterizerCanvasRD::update() {
+ _dispose_bindings();
+}
+
+RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
+ storage = p_storage;
+
+ { //create default samplers
default_samplers.default_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
default_samplers.default_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
@@ -1963,6 +2248,66 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
}
}
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["LIGHT_VERTEX"] = "light_vertex";
+ actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
+ actions.renames["UV"] = "uv";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
+ actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["AT_LIGHT_PASS"] = "false";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["NORMALMAP"] = "normal_map";
+ actions.renames["NORMALMAP_DEPTH"] = "normal_depth";
+ actions.renames["TEXTURE"] = "color_texture";
+ actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
+ actions.renames["NORMAL_TEXTURE"] = "normal_texture";
+ actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
+ actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+
+ actions.renames["LIGHT_POSITION"] = "light_pos";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT_ENERGY"] = "light_energy";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
+
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+ actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
+ actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+
+ actions.custom_samplers["TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 2;
+ actions.texture_layout_set = 1;
+ actions.base_uniform_string = "material.";
+
+ shader.compiler.initialize(actions);
+ }
+
{ //shadow rendering
Vector<String> versions;
versions.push_back(String()); //no versions
@@ -2122,6 +2467,12 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT);
}
+ //create functions for shader and material
+ storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs);
+ storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs);
+
+ state.time = 0;
+
ERR_FAIL_COND(sizeof(PushConstant) != 128);
}
@@ -2180,18 +2531,4 @@ RasterizerCanvasRD::~RasterizerCanvasRD() {
RD::get_singleton()->free(shader.quad_index_buffer);
//pipelines don't need freeing, they are all gone after shaders are gone
-
- //samplers
- for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::get_singleton()->free(default_samplers.samplers[i][j]);
- }
- }
-
- //textures
- RD::get_singleton()->free(default_textures.white_texture);
- RD::get_singleton()->free(default_textures.black_texture);
- RD::get_singleton()->free(default_textures.normal_texture);
- RD::get_singleton()->free(default_textures.aniso_texture);
- RD::get_singleton()->free(default_textures.default_multimesh_tb);
}
diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer/rasterizer_canvas_rd.h
index dfeecddfc1..851b891ec4 100644
--- a/servers/visual/rasterizer/rasterizer_canvas_rd.h
+++ b/servers/visual/rasterizer/rasterizer_canvas_rd.h
@@ -4,6 +4,7 @@
#include "servers/visual/rasterizer/rasterizer.h"
#include "servers/visual/rasterizer/rasterizer_storage_rd.h"
#include "servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h"
+#include "servers/visual/rasterizer/shader_compiler_rd.h"
#include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h"
#include "servers/visual/rasterizer/shaders/canvas_occlusion.glsl.gen.h"
#include "servers/visual/rendering_device.h"
@@ -112,8 +113,77 @@ class RasterizerCanvasRD : public RasterizerCanvas {
RID default_skeleton_uniform_buffer;
RID default_skeleton_texture_buffer;
+ ShaderCompilerRD compiler;
} shader;
+ struct ShaderData : public RasterizerStorageRD::ShaderData {
+
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PMALPHA,
+ BLEND_MODE_DISABLED,
+ };
+
+ enum LightMode {
+ LIGHT_MODE_NORMAL,
+ LIGHT_MODE_UNSHADED,
+ LIGHT_MODE_LIGHT_ONLY
+ };
+
+ bool valid;
+ RID version;
+ PipelineVariants pipeline_variants;
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ bool uses_screen_texture;
+ bool uses_material_samplers;
+
+ 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 bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RasterizerStorageRD::ShaderData *_create_shader_func();
+ static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RasterizerStorageRD::MaterialData {
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~MaterialData();
+ };
+
+ RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
+ return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
/**************************/
/**** TEXTURE BINDINGS ****/
/**************************/
@@ -168,18 +238,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
void _dispose_bindings();
- struct {
- RID white_texture;
- RID black_texture;
- RID normal_texture;
- RID aniso_texture;
-
- RID default_multimesh_tb;
-
- } default_textures;
struct {
- RID samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
VS::CanvasItemTextureFilter default_filter;
VS::CanvasItemTextureRepeat default_repeat;
} default_samplers;
@@ -293,7 +353,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
LightCache light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
uint32_t light_cache_count;
- RID light_uniform_set;
+ RID state_uniform_set_with_light;
RID state_uniform_set;
ItemStateData() {
@@ -305,8 +365,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
}
~ItemStateData() {
- if (light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(light_uniform_set)) {
- RD::get_singleton()->free(light_uniform_set);
+ if (state_uniform_set_with_light.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set_with_light)) {
+ RD::get_singleton()->free(state_uniform_set_with_light);
}
if (state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set)) {
RD::get_singleton()->free(state_uniform_set);
@@ -322,6 +382,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
float screen_transform[16];
float canvas_normal_transform[16];
float canvas_modulate[4];
+ float time;
+ float pad[3];
//uint32_t light_count;
//uint32_t pad[3];
};
@@ -334,6 +396,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
uint32_t max_lights_per_render;
uint32_t max_lights_per_item;
+
+ double time;
} state;
struct PushConstant {
@@ -368,7 +432,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
Item *items[MAX_RENDER_ITEMS];
Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags);
- void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights);
+ void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
@@ -401,6 +465,7 @@ public:
void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
+ void set_time(double p_time);
void update();
bool free(RID p_rid);
RasterizerCanvasRD(RasterizerStorageRD *p_storage);
diff --git a/servers/visual/rasterizer/rasterizer_rd.cpp b/servers/visual/rasterizer/rasterizer_rd.cpp
index 62449fafb4..d1c7549409 100644
--- a/servers/visual/rasterizer/rasterizer_rd.cpp
+++ b/servers/visual/rasterizer/rasterizer_rd.cpp
@@ -46,9 +46,12 @@ void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScree
}
void RasterizerRD::begin_frame(double frame_step) {
+ time += frame_step;
+ canvas->set_time(time);
}
void RasterizerRD::end_frame(bool p_swap_buffers) {
+
RD::get_singleton()->finalize_frame();
#warning not swapping buffers likely not an option for now, find another way
OS::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
@@ -130,6 +133,7 @@ void RasterizerRD::finalize() {
}
RasterizerRD::RasterizerRD() {
+ time = 0;
storage = memnew(RasterizerStorageRD);
canvas = memnew(RasterizerCanvasRD(storage));
scene = memnew(RasterizerSceneForwardRD);
diff --git a/servers/visual/rasterizer/rasterizer_rd.h b/servers/visual/rasterizer/rasterizer_rd.h
index b895f48065..2c51dc7300 100644
--- a/servers/visual/rasterizer/rasterizer_rd.h
+++ b/servers/visual/rasterizer/rasterizer_rd.h
@@ -20,6 +20,8 @@ protected:
Map<RID, RID> render_target_descriptors;
+ double time;
+
public:
RasterizerStorage *get_storage() { return storage; }
RasterizerCanvas *get_canvas() { return canvas; }
diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.cpp b/servers/visual/rasterizer/rasterizer_storage_rd.cpp
index 9ec3f26b4d..5783379738 100644
--- a/servers/visual/rasterizer/rasterizer_storage_rd.cpp
+++ b/servers/visual/rasterizer/rasterizer_storage_rd.cpp
@@ -1,5 +1,7 @@
#include "rasterizer_storage_rd.h"
#include "core/engine.h"
+#include "core/project_settings.h"
+#include "servers/visual/shader_language.h"
Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
@@ -775,6 +777,878 @@ Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
return texture_2d_get_size(p_proxy);
}
+/* SHADER API */
+
+RID RasterizerStorageRD::shader_create() {
+
+ Shader shader;
+ shader.data = NULL;
+ shader.type = SHADER_TYPE_MAX;
+
+ return shader_owner.make_rid(shader);
+}
+
+void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ print_line("yey set code?");
+ shader->code = p_code;
+ String mode_string = ShaderLanguage::get_shader_type(p_code);
+
+ ShaderType new_type;
+ if (mode_string == "canvas_item")
+ new_type = SHADER_TYPE_2D;
+ else if (mode_string == "particles")
+ new_type = SHADER_TYPE_PARTICLES;
+ else if (mode_string == "spatial")
+ new_type = SHADER_TYPE_3D;
+ else
+ new_type = SHADER_TYPE_MAX;
+
+ if (new_type != shader->type) {
+ if (shader->data) {
+ memdelete(shader->data);
+ shader->data = NULL;
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+
+ Material *material = E->get();
+ material->shader_type = new_type;
+ if (material->data) {
+ memdelete(material->data);
+ material->data = NULL;
+ }
+ }
+
+ shader->type = new_type;
+
+ if (new_type < SHADER_TYPE_MAX && shader_data_request_func[new_type]) {
+ shader->data = shader_data_request_func[new_type]();
+ } else {
+ shader->type = SHADER_TYPE_MAX; //invalid
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ if (shader->data) {
+ material->data = material_data_request_func[new_type](shader->data);
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ }
+ material->shader_type = new_type;
+ }
+ }
+
+ if (shader->data) {
+ shader->data->set_code(p_code);
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ material->instance_dependency.instance_notify_changed(false, true);
+ _material_queue_update(material, true, true);
+ }
+}
+
+String RasterizerStorageRD::shader_get_code(RID p_shader) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, String());
+ return shader->code;
+}
+void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+ if (shader->data) {
+ return shader->data->get_param_list(p_param_list);
+ }
+}
+
+void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ if (p_texture.is_valid() && texture_owner.owns(p_texture)) {
+ shader->default_texture_parameter[p_name] = p_texture;
+ } else {
+ shader->default_texture_parameter.erase(p_name);
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ _material_queue_update(material, false, true);
+ }
+}
+
+RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, RID());
+ if (shader->default_texture_parameter.has(p_name)) {
+ return shader->default_texture_parameter[p_name];
+ }
+
+ return RID();
+}
+Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, Variant());
+ if (shader->data) {
+ return shader->data->get_default_parameter(p_param);
+ }
+ return Variant();
+}
+void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) {
+ ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+ shader_data_request_func[p_shader_type] = p_function;
+}
+
+/* COMMON MATERIAL API */
+
+RID RasterizerStorageRD::material_create() {
+ Material material;
+ material.data = NULL;
+ material.shader = NULL;
+ material.shader_type = SHADER_TYPE_MAX;
+ material.update_next = NULL;
+ material.update_requested = false;
+ material.uniform_dirty = false;
+ material.texture_dirty = false;
+ material.priority = 0;
+ RID id = material_owner.make_rid(material);
+ {
+ Material *material_ptr = material_owner.getornull(id);
+ material_ptr->self = id;
+ }
+ return id;
+}
+
+void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
+ if (material->update_requested) {
+ return;
+ }
+
+ material->update_next = material_update_list;
+ material_update_list = material;
+ material->update_requested = true;
+ material->uniform_dirty = p_uniform;
+ material->texture_dirty = p_texture;
+}
+
+void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->data) {
+ memdelete(material->data);
+ material->data = NULL;
+ }
+
+ if (material->shader) {
+ material->shader->owners.erase(material);
+ material->shader = NULL;
+ material->shader_type = SHADER_TYPE_MAX;
+ }
+
+ if (p_shader.is_null()) {
+ material->instance_dependency.instance_notify_changed(false, true);
+ return;
+ }
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+ material->shader = shader;
+ material->shader_type = shader->type;
+ shader->owners.insert(material);
+
+ if (shader->type == SHADER_TYPE_MAX) {
+ return;
+ }
+
+ ERR_FAIL_COND(shader->data == NULL);
+
+ material->data = material_data_request_func[shader->type](shader->data);
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ //updating happens later
+ material->instance_dependency.instance_notify_changed(false, true);
+ _material_queue_update(material, true, true);
+}
+
+void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (p_value.get_type() == Variant::NIL) {
+ material->params.erase(p_param);
+ } else {
+ material->params[p_param] = p_value;
+ }
+
+ if (material->shader && material->shader->data) { //shader is valid
+ bool is_texture = material->shader->data->is_param_texture(p_param);
+ _material_queue_update(material, !is_texture, is_texture);
+ } else {
+ _material_queue_update(material, true, true);
+ }
+}
+
+Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, Variant());
+ if (material->params.has(p_param)) {
+ return material->params[p_param];
+ } else {
+ return Variant();
+ }
+}
+
+void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->next_pass == p_next_material) {
+ return;
+ }
+
+ material->next_pass = p_next_material;
+ if (material->data) {
+ material->data->set_next_pass(p_next_material);
+ }
+
+ material->instance_dependency.instance_notify_changed(false, true);
+}
+void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+ material->priority = priority;
+ if (material->data) {
+ material->data->set_render_priority(priority);
+ }
+}
+
+bool RasterizerStorageRD::material_is_animated(RID p_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, false);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->is_animated()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_is_animated(material->next_pass);
+ }
+ }
+ return false; //by default nothing is animated
+}
+bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, true);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->casts_shadows()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_casts_shadows(material->next_pass);
+ }
+ }
+ return true; //by default everything casts shadows
+}
+
+void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+ p_instance->update_dependency(&material->instance_dependency);
+ if (material->next_pass.is_valid()) {
+ material_update_dependency(material->next_pass, p_instance);
+ }
+}
+
+void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) {
+ ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+ material_data_request_func[p_shader_type] = p_function;
+}
+
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+
+ bool v = value;
+
+ uint32_t *gui = (uint32_t *)data;
+ *gui = v ? 1 : 0;
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = v & 1 ? 1 : 0;
+ gui[1] = v & 2 ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ gui[3] = (v & 8) ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+
+ int v = value;
+ int32_t *gui = (int32_t *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 2; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 3; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 4; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 2; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 3; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ PoolVector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ PoolVector<int>::Read r = iv.read();
+
+ for (int i = 0; i < 4; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ float v = value;
+ float *gui = (float *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+ Vector2 v = value;
+ float *gui = (float *)data;
+ gui[0] = v.x;
+ gui[1] = v.y;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+ Vector3 v = value;
+ float *gui = (float *)data;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+
+ float *gui = (float *)data;
+
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
+
+ if (p_linear_color) {
+ v = v.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::QUAT) {
+ Quat 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;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ Transform2D v = value;
+ float *gui = (float *)data;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[0][1];
+ gui[2] = 0;
+ gui[3] = 0;
+ gui[4] = v.elements[1][0];
+ gui[5] = v.elements[1][1];
+ gui[6] = 0;
+ gui[7] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ Basis v = value;
+ float *gui = (float *)data;
+
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[1][0];
+ gui[2] = v.elements[2][0];
+ gui[3] = 0;
+ gui[4] = v.elements[0][1];
+ gui[5] = v.elements[1][1];
+ gui[6] = v.elements[2][1];
+ gui[7] = 0;
+ gui[8] = v.elements[0][2];
+ gui[9] = v.elements[1][2];
+ gui[10] = v.elements[2][2];
+ gui[11] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+
+ Transform v = value;
+ float *gui = (float *)data;
+
+ gui[0] = v.basis.elements[0][0];
+ gui[1] = v.basis.elements[1][0];
+ gui[2] = v.basis.elements[2][0];
+ gui[3] = 0;
+ gui[4] = v.basis.elements[0][1];
+ gui[5] = v.basis.elements[1][1];
+ gui[6] = v.basis.elements[2][1];
+ gui[7] = 0;
+ gui[8] = v.basis.elements[0][2];
+ gui[9] = v.basis.elements[1][2];
+ gui[10] = v.basis.elements[2][2];
+ gui[11] = 0;
+ gui[12] = v.origin.x;
+ gui[13] = v.origin.y;
+ gui[14] = v.origin.z;
+ gui[15] = 1;
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
+
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+
+ uint32_t *gui = (uint32_t *)data;
+ *gui = value[0].boolean ? 1 : 0;
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+ gui[3] = value[3].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+
+ int32_t *gui = (int32_t *)data;
+ gui[0] = value[0].sint;
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].uint;
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].uint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+
+ float *gui = (float *)data;
+ gui[0] = value[0].real;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ float *gui = (float *)data;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = 0;
+ gui[3] = 0;
+ gui[4] = value[2].real;
+ gui[5] = value[3].real;
+ gui[6] = 0;
+ gui[7] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ float *gui = (float *)data;
+
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = value[2].real;
+ gui[3] = 0;
+ gui[4] = value[3].real;
+ gui[5] = value[4].real;
+ gui[6] = value[5].real;
+ gui[7] = 0;
+ gui[8] = value[6].real;
+ gui[9] = value[7].real;
+ gui[10] = value[8].real;
+ gui[11] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 16; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
+
+ switch (type) {
+
+ case ShaderLanguage::TYPE_BOOL:
+ case ShaderLanguage::TYPE_INT:
+ case ShaderLanguage::TYPE_UINT:
+ case ShaderLanguage::TYPE_FLOAT: {
+ zeromem(data, 4);
+ } break;
+ case ShaderLanguage::TYPE_BVEC2:
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_UVEC2:
+ case ShaderLanguage::TYPE_VEC2: {
+ zeromem(data, 8);
+ } break;
+ case ShaderLanguage::TYPE_BVEC3:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_UVEC3:
+ case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_BVEC4:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC4:
+ case ShaderLanguage::TYPE_VEC4: {
+
+ zeromem(data, 16);
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+
+ zeromem(data, 32);
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ zeromem(data, 48);
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+ zeromem(data, 64);
+ } break;
+
+ default: {
+ }
+ }
+}
+
+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) {
+
+ 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
+
+ //regular uniform
+ uint32_t offset = p_uniform_offsets[E->get().order];
+#ifdef DEBUG_ENABLED
+ uint32_t size = ShaderLanguage::get_type_size(E->get().type);
+ ERR_CONTINUE(offset + size > p_buffer_size);
+#endif
+ uint8_t *data = &p_buffer[offset];
+ const Map<StringName, Variant>::Element *V = p_parameters.find(E->key());
+
+ if (V) {
+ //user provided
+ _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color);
+
+ } else if (E->get().default_value.size()) {
+ //default value
+ _fill_std140_ubo_value(E->get().type, E->get().default_value, data);
+ //value=E->get().default_value;
+ } else {
+ //zero because it was not provided
+ if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ //colors must be set as black, with alpha as 1.0
+ _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color);
+ } else {
+ //else just zero it out
+ _fill_std140_ubo_empty(E->get().type, data);
+ }
+ }
+ }
+}
+
+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) {
+
+ RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton;
+
+ 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 (!texture.is_valid()) {
+ const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
+ if (W) {
+ texture = W->get();
+ }
+ }
+
+ RID rd_texture;
+
+ if (texture.is_null()) {
+ //check default usage
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+ } break;
+ default: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ } break;
+ }
+ } else {
+ bool srgb = p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO;
+ rd_texture = singleton->texture_get_rd_texture(texture, srgb);
+ if (rd_texture.is_null()) {
+ //wtf
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ }
+ }
+
+ p_textures[i] = rd_texture;
+ }
+}
+
+void RasterizerStorageRD::_update_queued_materials() {
+ Material *material = material_update_list;
+ while (material) {
+ Material *next = material->update_next;
+
+ if (material->data) {
+ material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
+ }
+ material->update_requested = false;
+ material->texture_dirty = false;
+ material->uniform_dirty = false;
+ material->update_next = NULL;
+ material = next;
+ }
+ material_update_list = NULL;
+}
+
/* RENDER TARGET API */
void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -992,6 +1866,10 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
rt->clear_requested = false;
}
+void RasterizerStorageRD::update_dirty_resources() {
+ _update_queued_materials();
+}
+
bool RasterizerStorageRD::free(RID p_rid) {
if (texture_owner.owns(p_rid)) {
@@ -1014,6 +1892,25 @@ bool RasterizerStorageRD::free(RID p_rid) {
}
texture_owner.free(p_rid);
+ } else if (shader_owner.owns(p_rid)) {
+ Shader *shader = shader_owner.getornull(p_rid);
+ //make material unreference this
+ while (shader->owners.size()) {
+ material_set_shader(shader->owners.front()->get()->self, RID());
+ }
+ //clear data if exists
+ if (shader->data) {
+ memdelete(shader->data);
+ }
+ shader_owner.free(p_rid);
+
+ } else if (material_owner.owns(p_rid)) {
+ Material *material = material_owner.getornull(p_rid);
+ if (material->update_requested) {
+ _update_queued_materials();
+ }
+ material_set_shader(p_rid, RID()); //clean up shader
+ material->instance_dependency.instance_notify_deleted(p_rid);
} else if (render_target_owner.owns(p_rid)) {
RenderTarget *rt = render_target_owner.getornull(p_rid);
@@ -1032,3 +1929,162 @@ bool RasterizerStorageRD::free(RID p_rid) {
return true;
}
+
+RasterizerStorageRD::RasterizerStorageRD() {
+
+ material_update_list = NULL;
+ { //create default textures
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+
+ PoolVector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 255);
+ pv.set(i * 4 + 1, 255);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<PoolVector<uint8_t> > vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<PoolVector<uint8_t> > vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 128);
+ pv.set(i * 4 + 1, 128);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<PoolVector<uint8_t> > vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 255);
+ pv.set(i * 4 + 1, 128);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<PoolVector<uint8_t> > vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ default_rd_textures[DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER] = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
+ }
+
+ //default samplers
+ for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::SamplerState sampler_state;
+ switch (i) {
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.max_lod = 0;
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
+
+ } break;
+ default: {
+ }
+ }
+ switch (j) {
+ case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ } break;
+ case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ } break;
+ default: {
+ }
+ }
+
+ default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+ }
+ }
+}
+
+RasterizerStorageRD::~RasterizerStorageRD() {
+ //def textures
+ for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
+ RD::get_singleton()->free(default_rd_textures[i]);
+ }
+
+ //def samplers
+ for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::get_singleton()->free(default_rd_samplers[i][j]);
+ }
+ }
+}
diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer/rasterizer_storage_rd.h
index c4ed7f56d8..d875738481 100644
--- a/servers/visual/rasterizer/rasterizer_storage_rd.h
+++ b/servers/visual/rasterizer/rasterizer_storage_rd.h
@@ -3,9 +3,52 @@
#include "core/rid_owner.h"
#include "servers/visual/rasterizer/rasterizer.h"
+#include "servers/visual/rasterizer/shader_compiler_rd.h"
#include "servers/visual/rendering_device.h"
class RasterizerStorageRD : public RasterizerStorage {
public:
+ enum ShaderType {
+ SHADER_TYPE_2D,
+ SHADER_TYPE_3D,
+ SHADER_TYPE_PARTICLES,
+ SHADER_TYPE_MAX
+ };
+
+ struct ShaderData {
+ 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 bool is_param_texture(const StringName &p_param) const = 0;
+ virtual bool is_animated() const = 0;
+ virtual bool casts_shadows() const = 0;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
+ virtual ~ShaderData() {}
+ };
+
+ typedef ShaderData *(*ShaderDataRequestFunction)();
+
+ struct MaterialData {
+
+ void 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);
+ void 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);
+
+ 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() {}
+ };
+ typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+
+ enum DefaultRDTexture {
+ DEFAULT_RD_TEXTURE_WHITE,
+ DEFAULT_RD_TEXTURE_BLACK,
+ DEFAULT_RD_TEXTURE_NORMAL,
+ DEFAULT_RD_TEXTURE_ANISO,
+ DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
+ DEFAULT_RD_TEXTURE_MAX
+ };
+
+private:
/* TEXTURE API */
struct Texture {
@@ -68,6 +111,48 @@ public:
Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format);
+ RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
+ RID default_rd_samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+
+ /* SHADER */
+
+ struct Material;
+
+ struct Shader {
+ ShaderData *data;
+ String code;
+ ShaderType type;
+ Map<StringName, RID> default_texture_parameter;
+ Set<Material *> owners;
+ };
+
+ ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
+ mutable RID_Owner<Shader> shader_owner;
+
+ /* Material */
+
+ struct Material {
+ RID self;
+ MaterialData *data;
+ Shader *shader;
+ //shortcut to shader data and type
+ ShaderType shader_type;
+ bool update_requested;
+ bool uniform_dirty;
+ bool texture_dirty;
+ Material *update_next;
+ Map<StringName, Variant> params;
+ int32_t priority;
+ RID next_pass;
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
+ mutable RID_Owner<Material> material_owner;
+
+ Material *material_update_list;
+ void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
+ void _update_queued_materials();
/* RENDER TARGET */
struct RenderTarget {
@@ -164,6 +249,13 @@ public:
return Size2i(tex->width_2d, tex->height_2d);
}
+ _FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
+ return default_rd_textures[p_texture];
+ }
+ _FORCE_INLINE_ RID sampler_rd_get_default(VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat) {
+ return default_rd_samplers[p_filter][p_repeat];
+ }
+
/* SKY API */
struct RDSurface {
@@ -189,63 +281,44 @@ public:
/* SHADER API */
- enum ShaderType {
- SHADER_TYPE_2D,
- SHADER_TYPE_3D,
- SHADER_TYPE_3D_POST_PROCESS,
- SHADER_TYPE_PARTICLES
- };
-
- class ShaderData {
- 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 bool is_animated() const = 0;
- virtual bool casts_shadows() const = 0;
- virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
- virtual ~ShaderData() {}
- };
-
- typedef ShaderData *(ShaderDataRequestFunction)();
+ RID shader_create();
- RID shader_create() { return RID(); }
+ void shader_set_code(RID p_shader, const String &p_code);
+ String shader_get_code(RID p_shader) const;
+ void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
- void shader_set_code(RID p_shader, const String &p_code) {}
- String shader_get_code(RID p_shader) const { return ""; }
- void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {}
-
- void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {}
- RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { return RID(); }
- Variant shader_get_param_default(RID p_material, const StringName &p_param) const { return Variant(); }
+ void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
+ RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+ Variant shader_get_param_default(RID p_shader, const StringName &p_param) const;
+ void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
/* COMMON MATERIAL API */
- struct MaterialData {
+ RID material_create();
- 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) = 0;
- virtual ~MaterialData() {}
- };
- typedef MaterialData *(MaterialDataRequestFunction)(ShaderData *);
+ void material_set_shader(RID p_material, RID p_shader);
- RID material_create() { return RID(); }
+ void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value);
+ Variant material_get_param(RID p_material, const StringName &p_param) const;
- void material_set_shader(RID p_shader_material, RID p_shader) {}
- RID material_get_shader(RID p_shader_material) const { return RID(); }
+ void material_set_next_pass(RID p_material, RID p_next_material);
+ void material_set_render_priority(RID p_material, int priority);
- void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {}
- Variant material_get_param(RID p_material, const StringName &p_param) const { return Variant(); }
+ bool material_is_animated(RID p_material);
+ bool material_casts_shadows(RID p_material);
- void material_set_next_pass(RID p_material, RID p_next_material) {}
- void material_set_render_priority(RID p_material, int priority) {}
+ void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
- bool material_is_animated(RID p_material) { return false; }
- bool material_casts_shadows(RID p_material) { return false; }
+ void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function);
- void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {}
- void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {}
+ _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) {
+ Material *material = material_owner.getornull(p_material);
+ if (material->shader_type != p_shader_type) {
+ return NULL;
+ } else {
+ return material->data;
+ }
+ }
/* MESH API */
@@ -498,11 +571,8 @@ public:
float reflection_probe_get_origin_max_distance(RID p_probe) const { return 0.0; }
bool reflection_probe_renders_shadows(RID p_probe) const { return false; }
- void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
- void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
-
- void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
- void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
+ void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
+ void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
/* GI PROBE API */
@@ -551,59 +621,14 @@ public:
void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {}
/* LIGHTMAP CAPTURE */
- struct Instantiable {
-
- SelfList<RasterizerScene::InstanceBase>::List instance_list;
-
- _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) {
-
- SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
- while (instances) {
-
- instances->self()->base_changed(p_aabb, p_materials);
- instances = instances->next();
- }
- }
-
- _FORCE_INLINE_ void instance_remove_deps() {
- SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
- while (instances) {
-
- SelfList<RasterizerScene::InstanceBase> *next = instances->next();
- instances->self()->base_removed();
- instances = next;
- }
- }
-
- Instantiable() {}
- virtual ~Instantiable() {
- }
- };
-
- struct LightmapCapture : public Instantiable {
-
- PoolVector<LightmapCaptureOctree> octree;
- AABB bounds;
- Transform cell_xform;
- int cell_subdiv;
- float energy;
- LightmapCapture() {
- energy = 1.0;
- cell_subdiv = 1;
- }
- };
- mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner;
void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); }
void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) {}
RID lightmap_capture_create() {
- LightmapCapture *capture = memnew(LightmapCapture);
- return lightmap_capture_data_owner.make_rid(capture);
+ return RID();
}
PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const {
- const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>());
return PoolVector<uint8_t>();
}
void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {}
@@ -613,9 +638,7 @@ public:
void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
- const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, NULL);
- return &capture->octree;
+ return NULL;
}
/* PARTICLES */
@@ -686,7 +709,7 @@ public:
bool has_os_feature(const String &p_feature) const { return false; }
- void update_dirty_resources() {}
+ void update_dirty_resources();
void set_debug_generate_wireframes(bool p_generate) {}
@@ -700,8 +723,8 @@ public:
static RasterizerStorage *base_singleton;
- RasterizerStorageRD(){};
- ~RasterizerStorageRD() {}
+ RasterizerStorageRD();
+ ~RasterizerStorageRD();
};
#endif // RASTERIZER_STORAGE_RD_H
diff --git a/servers/visual/rasterizer/shader_compiler_rd.cpp b/servers/visual/rasterizer/shader_compiler_rd.cpp
new file mode 100644
index 0000000000..789e4ca057
--- /dev/null
+++ b/servers/visual/rasterizer/shader_compiler_rd.cpp
@@ -0,0 +1,1003 @@
+#include "shader_compiler_rd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#define SL ShaderLanguage
+
+static String _mktab(int p_level) {
+
+ String tb;
+ for (int i = 0; i < p_level; i++) {
+ tb += "\t";
+ }
+
+ return tb;
+}
+
+static String _typestr(SL::DataType p_type) {
+
+ String type = ShaderLanguage::get_datatype_name(p_type);
+ if (ShaderLanguage::is_sampler_type(p_type)) {
+ type = type.replace("sampler", "texture"); //we use textures instead of samplers
+ }
+ return type;
+}
+
+static int _get_datatype_size(SL::DataType p_type) {
+
+ switch (p_type) {
+
+ case SL::TYPE_VOID: return 0;
+ case SL::TYPE_BOOL: return 4;
+ case SL::TYPE_BVEC2: return 8;
+ case SL::TYPE_BVEC3: return 12;
+ case SL::TYPE_BVEC4: return 16;
+ case SL::TYPE_INT: return 4;
+ case SL::TYPE_IVEC2: return 8;
+ case SL::TYPE_IVEC3: return 12;
+ case SL::TYPE_IVEC4: return 16;
+ case SL::TYPE_UINT: return 4;
+ case SL::TYPE_UVEC2: return 8;
+ case SL::TYPE_UVEC3: return 12;
+ case SL::TYPE_UVEC4: return 16;
+ case SL::TYPE_FLOAT: return 4;
+ case SL::TYPE_VEC2: return 8;
+ case SL::TYPE_VEC3: return 12;
+ case SL::TYPE_VEC4: return 16;
+ case SL::TYPE_MAT2:
+ return 32; //4 * 4 + 4 * 4
+ case SL::TYPE_MAT3:
+ return 48; // 4 * 4 + 4 * 4 + 4 * 4
+ case SL::TYPE_MAT4: return 64;
+ case SL::TYPE_SAMPLER2D: return 16;
+ case SL::TYPE_ISAMPLER2D: return 16;
+ case SL::TYPE_USAMPLER2D: return 16;
+ case SL::TYPE_SAMPLER2DARRAY: return 16;
+ case SL::TYPE_ISAMPLER2DARRAY: return 16;
+ case SL::TYPE_USAMPLER2DARRAY: return 16;
+ case SL::TYPE_SAMPLER3D: return 16;
+ case SL::TYPE_ISAMPLER3D: return 16;
+ case SL::TYPE_USAMPLER3D: return 16;
+ case SL::TYPE_SAMPLERCUBE: return 16;
+ }
+
+ ERR_FAIL_V(0);
+}
+
+static int _get_datatype_alignment(SL::DataType p_type) {
+
+ switch (p_type) {
+
+ case SL::TYPE_VOID: return 0;
+ case SL::TYPE_BOOL: return 4;
+ case SL::TYPE_BVEC2: return 8;
+ case SL::TYPE_BVEC3: return 16;
+ case SL::TYPE_BVEC4: return 16;
+ case SL::TYPE_INT: return 4;
+ case SL::TYPE_IVEC2: return 8;
+ case SL::TYPE_IVEC3: return 16;
+ case SL::TYPE_IVEC4: return 16;
+ case SL::TYPE_UINT: return 4;
+ case SL::TYPE_UVEC2: return 8;
+ case SL::TYPE_UVEC3: return 16;
+ case SL::TYPE_UVEC4: return 16;
+ case SL::TYPE_FLOAT: return 4;
+ case SL::TYPE_VEC2: return 8;
+ case SL::TYPE_VEC3: return 16;
+ case SL::TYPE_VEC4: return 16;
+ case SL::TYPE_MAT2: return 16;
+ case SL::TYPE_MAT3: return 16;
+ case SL::TYPE_MAT4: return 16;
+ case SL::TYPE_SAMPLER2D: return 16;
+ case SL::TYPE_ISAMPLER2D: return 16;
+ case SL::TYPE_USAMPLER2D: return 16;
+ case SL::TYPE_SAMPLER2DARRAY: return 16;
+ case SL::TYPE_ISAMPLER2DARRAY: return 16;
+ case SL::TYPE_USAMPLER2DARRAY: return 16;
+ case SL::TYPE_SAMPLER3D: return 16;
+ case SL::TYPE_ISAMPLER3D: return 16;
+ case SL::TYPE_USAMPLER3D: return 16;
+ case SL::TYPE_SAMPLERCUBE: return 16;
+ }
+
+ ERR_FAIL_V(0);
+}
+static String _interpstr(SL::DataInterpolation p_interp) {
+
+ switch (p_interp) {
+ case SL::INTERPOLATION_FLAT: return "flat ";
+ case SL::INTERPOLATION_SMOOTH: return "";
+ }
+ return "";
+}
+
+static String _prestr(SL::DataPrecision p_pres) {
+
+ switch (p_pres) {
+ case SL::PRECISION_LOWP: return "lowp ";
+ case SL::PRECISION_MEDIUMP: return "mediump ";
+ case SL::PRECISION_HIGHP: return "highp ";
+ case SL::PRECISION_DEFAULT: return "";
+ }
+ return "";
+}
+
+static String _qualstr(SL::ArgumentQualifier p_qual) {
+
+ switch (p_qual) {
+ case SL::ARGUMENT_QUALIFIER_IN: return "";
+ case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
+ case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
+ }
+ return "";
+}
+
+static String _opstr(SL::Operator p_op) {
+
+ return SL::get_operator_text(p_op);
+}
+
+static String _mkid(const String &p_id) {
+
+ String id = "m_" + p_id;
+ return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
+}
+
+static String f2sp0(float p_float) {
+
+ String num = rtoss(p_float);
+ if (num.find(".") == -1 && num.find("e") == -1) {
+ num += ".0";
+ }
+ return num;
+}
+
+static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
+
+ switch (p_type) {
+ case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false";
+ case SL::TYPE_BVEC2:
+ case SL::TYPE_BVEC3:
+ case SL::TYPE_BVEC4: {
+
+ String text = "bvec" + itos(p_type - SL::TYPE_BOOL + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += p_values[i].boolean ? "true" : "false";
+ }
+ text += ")";
+ return text;
+ }
+
+ case SL::TYPE_INT: return itos(p_values[0].sint);
+ case SL::TYPE_IVEC2:
+ case SL::TYPE_IVEC3:
+ case SL::TYPE_IVEC4: {
+
+ String text = "ivec" + itos(p_type - SL::TYPE_INT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += itos(p_values[i].sint);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ case SL::TYPE_UINT: return itos(p_values[0].uint) + "u";
+ case SL::TYPE_UVEC2:
+ case SL::TYPE_UVEC3:
+ case SL::TYPE_UVEC4: {
+
+ String text = "uvec" + itos(p_type - SL::TYPE_UINT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += itos(p_values[i].uint) + "u";
+ }
+ text += ")";
+ return text;
+ } break;
+ case SL::TYPE_FLOAT: return f2sp0(p_values[0].real);
+ case SL::TYPE_VEC2:
+ case SL::TYPE_VEC3:
+ case SL::TYPE_VEC4: {
+
+ String text = "vec" + itos(p_type - SL::TYPE_FLOAT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += f2sp0(p_values[i].real);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ case SL::TYPE_MAT2:
+ case SL::TYPE_MAT3:
+ case SL::TYPE_MAT4: {
+
+ String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += f2sp0(p_values[i].real);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ default: ERR_FAIL_V(String());
+ }
+}
+
+String ShaderCompilerRD::_get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat) {
+ if (p_filter == ShaderLanguage::FILTER_DEFAULT) {
+ ERR_FAIL_COND_V(actions.default_filter == ShaderLanguage::FILTER_DEFAULT, String());
+ p_filter = actions.default_filter;
+ }
+ if (p_repeat == ShaderLanguage::REPEAT_DEFAULT) {
+ ERR_FAIL_COND_V(actions.default_repeat == ShaderLanguage::REPEAT_DEFAULT, String());
+ p_repeat = actions.default_repeat;
+ }
+ return actions.sampler_array_name + "[" + itos(p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)) + "]";
+}
+
+void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) {
+
+ int fidx = -1;
+
+ for (int i = 0; i < p_node->functions.size(); i++) {
+ if (p_node->functions[i].name == p_for_func) {
+ fidx = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(fidx == -1);
+
+ for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
+
+ if (added.has(E->get())) {
+ continue; //was added already
+ }
+
+ _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
+
+ SL::FunctionNode *fnode = NULL;
+
+ for (int i = 0; i < p_node->functions.size(); i++) {
+ if (p_node->functions[i].name == E->get()) {
+ fnode = p_node->functions[i].function;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(!fnode);
+
+ r_to_add += "\n";
+
+ String header;
+ header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
+ for (int i = 0; i < fnode->arguments.size(); i++) {
+
+ if (i > 0)
+ header += ", ";
+ header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
+ }
+
+ header += ")\n";
+ r_to_add += header;
+ r_to_add += p_func_code[E->get()];
+
+ added.insert(E->get());
+ }
+}
+
+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;
+
+ switch (p_node->type) {
+
+ case SL::Node::TYPE_SHADER: {
+
+ SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
+
+ for (int i = 0; i < pnode->render_modes.size(); i++) {
+
+ if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
+
+ r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]]);
+ used_rmode_defines.insert(pnode->render_modes[i]);
+ }
+
+ if (p_actions.render_mode_flags.has(pnode->render_modes[i])) {
+ *p_actions.render_mode_flags[pnode->render_modes[i]] = true;
+ }
+
+ if (p_actions.render_mode_values.has(pnode->render_modes[i])) {
+ Pair<int *, int> &p = p_actions.render_mode_values[pnode->render_modes[i]];
+ *p.first = p.second;
+ }
+ }
+
+ int max_texture_uniforms = 0;
+ 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))
+ max_texture_uniforms++;
+ else
+ max_uniforms++;
+ }
+
+ r_gen_code.texture_uniforms.resize(max_texture_uniforms);
+
+ Vector<int> uniform_sizes;
+ Vector<int> uniform_alignments;
+ Vector<StringName> uniform_defines;
+ uniform_sizes.resize(max_uniforms);
+ uniform_alignments.resize(max_uniforms);
+ uniform_defines.resize(max_uniforms);
+ bool uses_uniforms = false;
+
+ for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+
+ String ucode;
+
+ 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);
+ ucode += " " + _mkid(E->key());
+ ucode += ";\n";
+ if (SL::is_sampler_type(E->get().type)) {
+ r_gen_code.vertex_global += ucode;
+ r_gen_code.fragment_global += ucode;
+
+ GeneratedCode::Texture texture;
+ texture.name = _mkid(E->key());
+ texture.hint = E->get().hint;
+ texture.type = E->get().type;
+ texture.filter = E->get().filter;
+ texture.repeat = E->get().repeat;
+
+ r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
+ } else {
+ if (!uses_uniforms) {
+
+ r_gen_code.defines.push_back(String("#define USE_MATERIAL_UNIFORMS\n"));
+ 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);
+ }
+
+ p_actions.uniforms->insert(E->key(), E->get());
+ }
+
+ for (int i = 0; i < max_uniforms; i++) {
+ r_gen_code.uniforms += uniform_defines[i];
+ }
+
+#if 1
+ // add up
+ int offset = 0;
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ int align = offset % uniform_alignments[i];
+
+ if (align != 0) {
+ offset += uniform_alignments[i] - align;
+ }
+
+ r_gen_code.uniform_offsets.push_back(offset);
+
+ offset += uniform_sizes[i];
+ }
+
+ r_gen_code.uniform_total_size = offset;
+ print_line("uniform total: " + itos(r_gen_code.uniform_total_size));
+ if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
+ //r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
+ }
+#else
+ // add up
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ if (i > 0) {
+
+ int align = uniform_sizes[i - 1] % uniform_alignments[i];
+ if (align != 0) {
+ uniform_sizes[i - 1] += uniform_alignments[i] - align;
+ }
+
+ uniform_sizes[i] = uniform_sizes[i] + uniform_sizes[i - 1];
+ }
+ }
+ //offset
+ r_gen_code.uniform_offsets.resize(uniform_sizes.size());
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ if (i > 0)
+ r_gen_code.uniform_offsets[i] = uniform_sizes[i - 1];
+ else
+ r_gen_code.uniform_offsets[i] = 0;
+ }
+ /*
+ for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
+
+ if (SL::is_sampler_type(E->get().type)) {
+ continue;
+ }
+
+ }
+
+*/
+ if (uniform_sizes.size()) {
+ r_gen_code.uniform_total_size = uniform_sizes[uniform_sizes.size() - 1];
+ } else {
+ r_gen_code.uniform_total_size = 0;
+ }
+#endif
+
+ for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
+
+ String vcode;
+ String interp_mode = _interpstr(E->get().interpolation);
+ vcode += _prestr(E->get().precision);
+ vcode += _typestr(E->get().type);
+ vcode += " " + _mkid(E->key());
+ vcode += ";\n";
+ r_gen_code.vertex_global += interp_mode + "out " + vcode;
+ r_gen_code.fragment_global += interp_mode + "in " + vcode;
+ }
+
+ for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) {
+ String gcode;
+ gcode += "const ";
+ gcode += _prestr(E->get().precision);
+ gcode += _typestr(E->get().type);
+ gcode += " " + _mkid(E->key());
+ gcode += "=";
+ gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ gcode += ";\n";
+ r_gen_code.vertex_global += gcode;
+ r_gen_code.fragment_global += gcode;
+ }
+
+ Map<StringName, String> function_code;
+
+ //code for functions
+ for (int i = 0; i < pnode->functions.size(); i++) {
+ SL::FunctionNode *fnode = pnode->functions[i].function;
+ current_func_name = fnode->name;
+ function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+
+ //place functions in actual code
+
+ Set<StringName> added_vtx;
+ Set<StringName> added_fragment; //share for light
+
+ for (int i = 0; i < pnode->functions.size(); i++) {
+
+ SL::FunctionNode *fnode = pnode->functions[i].function;
+
+ function = fnode;
+
+ current_func_name = fnode->name;
+
+ if (fnode->name == vertex_name) {
+
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx);
+ r_gen_code.vertex = function_code[vertex_name];
+ }
+
+ if (fnode->name == fragment_name) {
+
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
+ r_gen_code.fragment = function_code[fragment_name];
+ }
+
+ if (fnode->name == light_name) {
+
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
+ r_gen_code.light = function_code[light_name];
+ }
+ function = NULL;
+ }
+
+ //code+=dump_node_code(pnode->body,p_level);
+ } break;
+ case SL::Node::TYPE_FUNCTION: {
+
+ } break;
+ case SL::Node::TYPE_BLOCK: {
+ SL::BlockNode *bnode = (SL::BlockNode *)p_node;
+
+ //variables
+ if (!bnode->single_statement) {
+ code += _mktab(p_level - 1) + "{\n";
+ }
+
+ for (int i = 0; i < bnode->statements.size(); i++) {
+
+ String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) {
+ code += scode; //use directly
+ } else {
+ code += _mktab(p_level) + scode + ";\n";
+ }
+ }
+ if (!bnode->single_statement) {
+ code += _mktab(p_level - 1) + "}\n";
+ }
+
+ } break;
+ case SL::Node::TYPE_VARIABLE_DECLARATION: {
+ SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node;
+
+ String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype);
+ for (int i = 0; i < vdnode->declarations.size(); i++) {
+ if (i > 0) {
+ declaration += ",";
+ } else {
+ declaration += " ";
+ }
+ declaration += _mkid(vdnode->declarations[i].name);
+ if (vdnode->declarations[i].initializer) {
+ declaration += "=";
+ declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+ }
+
+ code += declaration;
+ } break;
+ case SL::Node::TYPE_VARIABLE: {
+ SL::VariableNode *vnode = (SL::VariableNode *)p_node;
+
+ if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) {
+ *p_actions.write_flag_pointers[vnode->name] = true;
+ }
+
+ if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) {
+ String define = p_default_actions.usage_defines[vnode->name];
+ if (define.begins_with("@")) {
+ define = p_default_actions.usage_defines[define.substr(1, define.length())];
+ }
+ r_gen_code.defines.push_back(define);
+ used_name_defines.insert(vnode->name);
+ }
+
+ if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
+ *p_actions.usage_flag_pointers[vnode->name] = true;
+ used_flag_pointers.insert(vnode->name);
+ }
+
+ 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 (vnode->name == time_name) {
+ if (current_func_name == vertex_name) {
+ r_gen_code.uses_vertex_time = true;
+ }
+ if (current_func_name == fragment_name || current_func_name == light_name) {
+ r_gen_code.uses_fragment_time = true;
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_CONSTANT: {
+ SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
+ return get_constant_text(cnode->datatype, cnode->values);
+
+ } break;
+ case SL::Node::TYPE_OPERATOR: {
+ SL::OperatorNode *onode = (SL::OperatorNode *)p_node;
+
+ switch (onode->op) {
+
+ case SL::OP_ASSIGN:
+ case SL::OP_ASSIGN_ADD:
+ case SL::OP_ASSIGN_SUB:
+ case SL::OP_ASSIGN_MUL:
+ case SL::OP_ASSIGN_DIV:
+ case SL::OP_ASSIGN_SHIFT_LEFT:
+ case SL::OP_ASSIGN_SHIFT_RIGHT:
+ case SL::OP_ASSIGN_MOD:
+ case SL::OP_ASSIGN_BIT_AND:
+ case SL::OP_ASSIGN_BIT_OR:
+ case SL::OP_ASSIGN_BIT_XOR:
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ break;
+ case SL::OP_BIT_INVERT:
+ case SL::OP_NEGATE:
+ case SL::OP_NOT:
+ case SL::OP_DECREMENT:
+ case SL::OP_INCREMENT:
+ code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ break;
+ case SL::OP_POST_DECREMENT:
+ case SL::OP_POST_INCREMENT:
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
+ break;
+ case SL::OP_CALL:
+ case SL::OP_CONSTRUCT: {
+
+ ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
+
+ SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
+
+ bool is_texture_func = false;
+ if (onode->op == SL::OP_CONSTRUCT) {
+ code += String(vnode->name);
+ } else {
+
+ if (internal_functions.has(vnode->name)) {
+ code += vnode->name;
+ is_texture_func = texture_functions.has(vnode->name);
+ } else if (p_default_actions.renames.has(vnode->name)) {
+ code += p_default_actions.renames[vnode->name];
+ } else {
+ code += _mkid(vnode->name);
+ }
+ }
+
+ code += "(";
+
+ for (int i = 1; i < onode->arguments.size(); i++) {
+ if (i > 1)
+ code += ", ";
+ String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+
+ //need to map from texture to sampler in order to sample
+ const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+
+ StringName texture_uniform = varnode->name;
+
+ String sampler_name;
+
+ if (actions.custom_samplers.has(texture_uniform)) {
+ sampler_name = actions.custom_samplers[texture_uniform];
+ } else {
+ if (shader->uniforms.has(texture_uniform)) {
+ sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ } else {
+ bool found = false;
+
+ for (int j = 0; j < function->arguments.size(); j++) {
+ if (function->arguments[j].name == texture_uniform) {
+ if (function->arguments[j].tex_builtin_check) {
+ ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
+ sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
+ found = true;
+ break;
+ }
+ if (function->arguments[j].tex_argument_check) {
+ sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ //function was most likely unused, so use anything (compiler will remove it anyway)
+ sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ }
+ }
+ }
+
+ code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ } else {
+ code += node_code;
+ }
+ }
+ code += ")";
+ } break;
+ case SL::OP_INDEX: {
+
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "[";
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+
+ } break;
+ case SL::OP_SELECT_IF: {
+
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "?";
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ":";
+ code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ } break;
+
+ default: {
+
+ code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")";
+ break;
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_CONTROL_FLOW: {
+ SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node;
+ if (cfnode->flow_op == SL::FLOW_OP_IF) {
+
+ code += _mktab(p_level) + "if (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (cfnode->blocks.size() == 2) {
+
+ code += _mktab(p_level) + "else\n";
+ code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+ } else if (cfnode->flow_op == SL::FLOW_OP_WHILE) {
+
+ code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else if (cfnode->flow_op == SL::FLOW_OP_FOR) {
+
+ String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n";
+ code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
+
+ if (cfnode->expressions.size()) {
+ code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ";";
+ } else {
+ code = "return;";
+ }
+ } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
+
+ code = "discard;";
+ } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
+
+ code = "continue;";
+ } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) {
+
+ code = "break;";
+ }
+
+ } break;
+ case SL::Node::TYPE_MEMBER: {
+ SL::MemberNode *mnode = (SL::MemberNode *)p_node;
+ code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
+
+ } break;
+ }
+
+ return code;
+}
+
+Error ShaderCompilerRD::compile(VS::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());
+
+ if (err != OK) {
+
+ Vector<String> shader = p_code.split("\n");
+ for (int i = 0; i < shader.size(); i++) {
+ print_line(itos(i + 1) + " " + shader[i]);
+ }
+
+ _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
+ return err;
+ }
+
+ r_gen_code.defines.clear();
+ r_gen_code.vertex = String();
+ r_gen_code.vertex_global = String();
+ r_gen_code.fragment = String();
+ r_gen_code.fragment_global = String();
+ r_gen_code.light = String();
+ r_gen_code.uses_fragment_time = false;
+ r_gen_code.uses_vertex_time = false;
+
+ used_name_defines.clear();
+ used_rmode_defines.clear();
+ used_flag_pointers.clear();
+
+ shader = parser.get_shader();
+ function = NULL;
+ _dump_node_code(shader, 1, r_gen_code, *p_actions, actions, false);
+
+ return OK;
+}
+
+void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
+ actions = p_actions;
+
+ vertex_name = "vertex";
+ fragment_name = "fragment";
+ light_name = "light";
+ time_name = "TIME";
+
+ List<String> func_list;
+
+ ShaderLanguage::get_builtin_funcs(&func_list);
+
+ for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
+ internal_functions.insert(E->get());
+ }
+ texture_functions.insert("texture");
+ texture_functions.insert("textureProj");
+ texture_functions.insert("textureLod");
+ texture_functions.insert("textureProjLod");
+ texture_functions.insert("textureGrad");
+}
+
+ShaderCompilerRD::ShaderCompilerRD() {
+#if 0
+
+ /** SPATIAL SHADER **/
+
+ actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
+ actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
+ actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
+ actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+ actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
+
+ actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
+ actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
+ actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
+ actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
+ actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position";
+ actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
+ actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
+ actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
+ actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
+ actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID";
+
+ //builtins
+
+ actions[VS::SHADER_SPATIAL].renames["TIME"] = "time";
+ actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
+
+ actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
+ actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
+ actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
+ actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
+ actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
+ actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
+ actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
+ actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
+ actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim";
+ actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
+ actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
+ actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
+ actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
+ actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
+ actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
+ actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
+ actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
+ actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
+ actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
+ actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
+ actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+ //for light
+ actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view";
+ actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
+ actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light";
+ actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
+ actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
+ actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
+ actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
+ actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley");
+
+ if (!force_lambert) {
+ actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
+
+ if (!force_blinn) {
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+
+ /* PARTICLES SHADER */
+
+ actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
+ actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
+ actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass";
+ actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active";
+ actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart";
+ actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom";
+ actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
+ actions[VS::SHADER_PARTICLES].renames["TIME"] = "time";
+ actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
+ actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
+ actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
+ actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index";
+ actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
+ actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
+ actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed";
+
+ actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
+ actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+ actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
+#endif
+}
diff --git a/servers/visual/rasterizer/shader_compiler_rd.h b/servers/visual/rasterizer/shader_compiler_rd.h
new file mode 100644
index 0000000000..3572a73a2d
--- /dev/null
+++ b/servers/visual/rasterizer/shader_compiler_rd.h
@@ -0,0 +1,92 @@
+#ifndef SHADER_COMPILER_RD_H
+#define SHADER_COMPILER_RD_H
+
+#include "core/pair.h"
+#include "servers/visual/shader_language.h"
+#include "servers/visual/shader_types.h"
+#include "servers/visual_server.h"
+
+class ShaderCompilerRD {
+public:
+ struct IdentifierActions {
+
+ Map<StringName, Pair<int *, int> > render_mode_values;
+ Map<StringName, bool *> render_mode_flags;
+ Map<StringName, bool *> usage_flag_pointers;
+ Map<StringName, bool *> write_flag_pointers;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
+ };
+
+ struct GeneratedCode {
+
+ Vector<String> defines;
+ struct Texture {
+ StringName name;
+ ShaderLanguage::DataType type;
+ ShaderLanguage::ShaderNode::Uniform::Hint hint;
+ ShaderLanguage::TextureFilter filter;
+ ShaderLanguage::TextureRepeat repeat;
+ };
+
+ Vector<Texture> texture_uniforms;
+
+ Vector<uint32_t> uniform_offsets;
+ uint32_t uniform_total_size;
+ String uniforms;
+ String vertex_global;
+ String vertex;
+ String fragment_global;
+ String fragment;
+ String light;
+
+ bool uses_fragment_time;
+ bool uses_vertex_time;
+ };
+
+ struct DefaultIdentifierActions {
+
+ Map<StringName, String> renames;
+ Map<StringName, String> render_mode_defines;
+ Map<StringName, String> usage_defines;
+ Map<StringName, String> custom_samplers;
+ ShaderLanguage::TextureFilter default_filter;
+ ShaderLanguage::TextureRepeat default_repeat;
+ String sampler_array_name;
+ int base_texture_binding_index;
+ int texture_layout_set;
+ String base_uniform_string;
+ };
+
+private:
+ ShaderLanguage parser;
+
+ String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat);
+
+ void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added);
+ String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning);
+
+ const ShaderLanguage::ShaderNode *shader;
+ const ShaderLanguage::FunctionNode *function;
+ StringName current_func_name;
+ StringName vertex_name;
+ StringName fragment_name;
+ StringName light_name;
+ StringName time_name;
+ Set<StringName> texture_functions;
+
+ Set<StringName> used_name_defines;
+ Set<StringName> used_flag_pointers;
+ Set<StringName> used_rmode_defines;
+ Set<StringName> internal_functions;
+
+ DefaultIdentifierActions actions;
+
+public:
+ Error compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
+
+ void initialize(DefaultIdentifierActions p_actions);
+ ShaderCompilerRD();
+};
+
+#endif // SHADERCOMPILERRD_H
diff --git a/servers/visual/rasterizer/shader_rd.cpp b/servers/visual/rasterizer/shader_rd.cpp
index 1a62a32c4d..f210908e39 100644
--- a/servers/visual/rasterizer/shader_rd.cpp
+++ b/servers/visual/rasterizer/shader_rd.cpp
@@ -243,7 +243,11 @@ void ShaderRD::_compile_version(Version *p_version) {
RD::ShaderStageSource stage;
stage.shader_source = builder.as_string();
stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
-
+#if 0
+ if (stage.shader_stage == RD::SHADER_STAGE_FRAGMENT && p_version->uniforms.length()) {
+ print_line(stage.shader_source.get_with_code_lines());
+ }
+#endif
stages.push_back(stage);
}
@@ -285,6 +289,8 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S
version->fragment_light = p_fragment_light.utf8();
version->fragment_globals = p_fragment_globals.utf8();
version->fragment_code = p_fragment_code.utf8();
+ version->uniforms = p_uniforms.utf8();
+
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
version->custom_defines.push_back(p_custom_defines[i].utf8());
diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer/shaders/canvas.glsl
index 8d36a2e3ea..00889f7345 100644
--- a/servers/visual/rasterizer/shaders/canvas.glsl
+++ b/servers/visual/rasterizer/shaders/canvas.glsl
@@ -31,10 +31,13 @@ layout(location=3) out vec2 pixel_size_interp;
#endif
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 1, binding = 1, std140) uniform MaterialUniforms {
/* clang-format off */
MATERIAL_UNIFORMS
/* clang-format on */
-
+} material;
+#endif
/* clang-format off */
VERTEX_SHADER_GLOBALS
@@ -207,6 +210,7 @@ VERTEX_SHADER_CODE
#endif
#endif
+
vertex = (canvas_data.canvas_transform * vec4(vertex,0.0,1.0)).xy;
vertex_interp = vertex;
@@ -243,33 +247,41 @@ layout(location=3) in vec2 pixel_size_interp;
layout(location = 0) out vec4 frag_color;
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 1, binding = 1, std140) uniform MaterialUniforms {
/* clang-format off */
MATERIAL_UNIFORMS
/* clang-format on */
+} material;
+#endif
/* clang-format off */
FRAGMENT_SHADER_GLOBALS
/* clang-format on */
+#ifdef LIGHT_SHADER_CODE_USED
-void light_compute(
- inout vec4 light,
- inout vec2 light_vec,
- inout float light_height,
- inout vec4 light_color,
- vec2 light_uv,
- inout vec4 shadow_color,
+vec4 light_compute(
+ vec3 light_vertex,
+ vec3 light_position,
vec3 normal,
- vec2 uv,
+ vec4 light_color,
+ float light_energy,
+ vec4 specular_shininess,
+ inout vec4 shadow_modulate,
vec2 screen_uv,
+ vec2 uv,
vec4 color) {
+ vec4 light = vec4(0.0);
/* clang-format off */
LIGHT_SHADER_CODE
/* clang-format on */
+ return light;
}
+#endif
#ifdef USE_NINEPATCH
@@ -391,8 +403,13 @@ void main() {
#if defined(SCREEN_UV_USED)
vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#else
+ vec2 screen_uv = vec2(0.0);
#endif
+ vec3 light_vertex = vec3(vertex,0.0);
+ vec2 shadow_vertex = vertex;
+
{
float normal_depth = 1.0;
@@ -449,14 +466,25 @@ FRAGMENT_SHADER_CODE
light_base&=0xFF;
vec2 tex_uv = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].matrix[0],light_array.data[light_base].matrix[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
- vec4 light_color = texture(sampler2D(light_textures[i],texture_sampler),tex_uv);
+ vec4 light_color = texture(sampler2D(light_textures[i],texture_sampler),tex_uv);
vec4 light_base_color = light_array.data[light_base].color;
+
+#ifdef LIGHT_SHADER_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ vec3 light_position = vec3(light_array.data[light_base].position,light_array.data[light_base].height);
+
+ light_color.rgb*=light_base_color.rgb;
+ light_color = light_compute(light_vertex,light_position,normal,light_color,light_base_color.a,specular_shininess,shadow_modulate,screen_uv,color,uv);
+#else
+
+
light_color.rgb*=light_base_color.rgb*light_base_color.a;
if (normal_used) {
vec3 light_pos = vec3(light_array.data[light_base].position,light_array.data[light_base].height);
- vec3 pos = vec3(vertex,0.0);
+ vec3 pos = light_vertex;
vec3 light_vec = normalize(light_pos-pos);
float cNdotL = max(0.0,dot(normal,light_vec));
@@ -480,7 +508,7 @@ FRAGMENT_SHADER_CODE
}
}
-
+#endif
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
//if outside the light texture, light color is zero
light_color.a = 0.0;
@@ -488,7 +516,7 @@ FRAGMENT_SHADER_CODE
if (bool(light_array.data[light_base].flags&LIGHT_FLAGS_HAS_SHADOW)) {
- vec2 shadow_pos = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].shadow_matrix[0],light_array.data[light_base].shadow_matrix[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+ vec2 shadow_pos = (vec4(shadow_vertex,0.0,1.0) * mat4(light_array.data[light_base].shadow_matrix[0],light_array.data[light_base].shadow_matrix[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
vec2 pos_abs = abs(pos_norm);
@@ -550,7 +578,11 @@ FRAGMENT_SHADER_CODE
shadow/=13.0;
}
- light_color = mix(light_color,light_array.data[light_base].shadow_color,shadow);
+ vec4 shadow_color = light_array.data[light_base].shadow_color;
+#ifdef LIGHT_SHADER_CODE_USED
+ shadow_color*=shadow_modulate;
+#endif
+ light_color = mix(light_color,shadow_color,shadow);
}
diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl
index 7b2ec81fb1..c8972a34bc 100644
--- a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl
+++ b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl
@@ -59,9 +59,14 @@ layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer;
/* SET1: Is reserved for the material */
-//
-/* SET2: Canvas Item State */
+#ifdef USE_MATERIAL_SAMPLERS
+
+layout(set = 1, binding = 0) uniform sampler material_samplers[12];
+
+#endif
+
+/* SET2: Canvas Item State (including lighting) */
layout(set = 2, binding = 0, std140) uniform CanvasData {
@@ -69,6 +74,9 @@ layout(set = 2, binding = 0, std140) uniform CanvasData {
mat4 screen_transform;
mat4 canvas_normal_transform;
vec4 canvas_modulation;
+ vec2 screen_pixel_size;
+ float time;
+ float time_pad;
//uint light_count;
} canvas_data;
@@ -80,9 +88,6 @@ layout(set = 2, binding = 2, std140) uniform SkeletonData {
} skeleton_data;
-
-/* SET3: Lighting */
-
#ifdef USE_LIGHTING
#define LIGHT_FLAGS_BLEND_MASK (3<<16)
@@ -112,13 +117,21 @@ struct Light {
float pad2;
};
-layout(set = 3, binding = 0, std140) uniform LightData {
+layout(set = 2, binding = 3, std140) uniform LightData {
Light data[MAX_LIGHTS];
} light_array;
-layout(set = 3, binding = 1) uniform texture2D light_textures[MAX_LIGHT_TEXTURES];
-layout(set = 3, binding = 2) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES];
+layout(set = 2, binding = 4) uniform texture2D light_textures[MAX_LIGHT_TEXTURES];
+layout(set = 2, binding = 5) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES];
+
+layout(set = 2, binding = 6) uniform sampler shadow_sampler;
+
+#endif
+
+/* SET3: Render Target Data */
+
+#ifdef SCREEN_TEXTURE_USED
-layout(set = 3, binding = 3) uniform sampler shadow_sampler;
+layout(set = 3, binding = 1) uniform texture2D screen_texture;
#endif
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 98ccfcfc68..c343e23881 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -207,6 +207,14 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"HINT_BLACK_ALBEDO_TEXTURE",
"HINT_COLOR",
"HINT_RANGE",
+ "FILTER_NEAREST",
+ "FILTER_LINEAR",
+ "FILTER_NEAREST_MIPMAP",
+ "FILTER_LINEAR_MIPMAP",
+ "FILTER_NEAREST_MIPMAP_ANISO",
+ "FILTER_LINEAR_MIPMAP_ANISO",
+ "REPEAT_ENABLE",
+ "REPEAT_DISABLE",
"SHADER_TYPE",
"CURSOR",
"ERROR",
@@ -304,8 +312,15 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
{ TK_HINT_COLOR, "hint_color" },
{ TK_HINT_RANGE, "hint_range" },
+ { TK_FILTER_NEAREST, "filter_nearest" },
+ { TK_FILTER_LINEAR, "filter_linear" },
+ { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
+ { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
+ { TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" },
+ { TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" },
+ { TK_REPEAT_ENABLE, "repeat_enable" },
+ { TK_REPEAT_DISABLE, "repeat_disable" },
{ TK_SHADER_TYPE, "shader_type" },
-
{ TK_ERROR, NULL }
};
@@ -2558,6 +2573,132 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
return Variant();
}
+PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform &p_uniform) {
+ PropertyInfo pi;
+ switch (p_uniform.type) {
+ case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break;
+ case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break;
+ case ShaderLanguage::TYPE_BVEC2:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y";
+ break;
+ case ShaderLanguage::TYPE_BVEC3:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z";
+ break;
+ case ShaderLanguage::TYPE_BVEC4:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z,w";
+ break;
+ case ShaderLanguage::TYPE_UINT:
+ case ShaderLanguage::TYPE_INT: {
+ pi.type = Variant::INT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]);
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC2:
+ case ShaderLanguage::TYPE_UVEC3:
+ case ShaderLanguage::TYPE_UVEC4: {
+
+ pi.type = Variant::POOL_INT_ARRAY;
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ pi.type = Variant::REAL;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break;
+ case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break;
+ case ShaderLanguage::TYPE_VEC4: {
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::COLOR;
+ } else {
+ pi.type = Variant::PLANE;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break;
+ case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break;
+ case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break;
+ case ShaderLanguage::TYPE_SAMPLER2D:
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture2D";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "TextureArray";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D: {
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture3D";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "CubeMap";
+ } break;
+ }
+ return pi;
+}
+
+uint32_t ShaderLanguage::get_type_size(DataType p_type) {
+ switch (p_type) {
+ case TYPE_BOOL:
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_FLOAT: return 4;
+ case TYPE_BVEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_VEC2: return 8;
+ case TYPE_BVEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_VEC3: return 12;
+ case TYPE_BVEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_VEC4: return 16;
+ case TYPE_MAT2: return 8;
+ case TYPE_MAT3: return 12;
+ case TYPE_MAT4: return 16;
+ case TYPE_SAMPLER2D:
+ case TYPE_ISAMPLER2D:
+ case TYPE_USAMPLER2D:
+ case TYPE_SAMPLER2DARRAY:
+ case TYPE_ISAMPLER2DARRAY:
+ case TYPE_USAMPLER2DARRAY:
+ case TYPE_SAMPLER3D:
+ case TYPE_ISAMPLER3D:
+ case TYPE_USAMPLER3D:
+ case TYPE_SAMPLERCUBE: return 4; //not really, but useful for indices
+ }
+ return 0;
+}
+
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
Set<String> kws;
@@ -2795,6 +2936,78 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return false;
}
+bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
+ for (int i = 0; shader->functions.size(); i++) {
+ if (shader->functions[i].name == p_name) {
+
+ ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ if (arg->tex_builtin_check) {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ return false;
+ } else if (arg->tex_argument_check) {
+ //was checked, verify that filter and repeat are the same
+ if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) {
+ return true;
+ } else {
+
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting.");
+ return false;
+ }
+ } else {
+
+ arg->tex_argument_check = true;
+ arg->tex_argument_filter = p_filter;
+ arg->tex_argument_repeat = p_repeat;
+ for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+ for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ ERR_FAIL_V(false); //bug? function not found
+}
+bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
+ for (int i = 0; shader->functions.size(); i++) {
+ if (shader->functions[i].name == p_name) {
+
+ ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ if (arg->tex_argument_check) {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ return false;
+ } else if (arg->tex_builtin_check) {
+ //was checked, verify that the built-in is the same
+ if (arg->tex_builtin == p_builtin) {
+ return true;
+ } else {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported.");
+ return false;
+ }
+ } else {
+
+ arg->tex_builtin_check = true;
+ arg->tex_builtin = p_builtin;
+
+ for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+ for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ ERR_FAIL_V(false); //bug? function not found
+}
+
ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
Vector<Expression> expression;
@@ -2944,6 +3157,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
//test if function was parsed first
+ int function_index = -1;
for (int i = 0; i < shader->functions.size(); i++) {
if (shader->functions[i].name == name) {
//add to current function as dependency
@@ -2953,6 +3167,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break;
}
}
+
+ //see if texture arguments must connect
+ function_index = i;
break;
}
}
@@ -2974,6 +3191,71 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
completion_class = TAG_GLOBAL; // reset sub-class
+ if (function_index >= 0) {
+ //connect texture arguments, so we can cache in the
+ //argument what type of filter and repeat to use
+
+ FunctionNode *call_function = shader->functions[function_index].function;
+ if (call_function) {
+
+ //get current base function
+ FunctionNode *base_function = NULL;
+ {
+ BlockNode *b = p_block;
+
+ while (b) {
+
+ if (b->parent_function) {
+ base_function = b->parent_function;
+ break;
+ } else {
+ b = b->parent_block;
+ }
+ }
+ }
+
+ ERR_FAIL_COND_V(!base_function, NULL); //bug, wtf
+
+ for (int i = 0; i < call_function->arguments.size(); i++) {
+ int argidx = i + 1;
+ if (argidx < func->arguments.size() && is_sampler_type(call_function->arguments[i].type)) {
+ //let's see where our argument comes from
+ Node *n = func->arguments[argidx];
+ ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ StringName varname = vn->name;
+ if (shader->uniforms.has(varname)) {
+ //being sampler, this either comes from a uniform
+ ShaderNode::Uniform *u = &shader->uniforms[varname];
+ ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously
+ //propagate
+ if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
+ return NULL;
+ }
+ } else if (p_builtin_types.has(varname)) {
+ //a built-in
+ if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
+ return NULL;
+ }
+ } else {
+ //or this comes from an argument, but nothing else can be a sampler
+ bool found = false;
+ for (int j = 0; j < base_function->arguments.size(); j++) {
+ if (base_function->arguments[j].name == varname) {
+ if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) {
+ base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set<int>();
+ }
+ base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i);
+ found = true;
+ break;
+ }
+ }
+ ERR_CONTINUE(!found);
+ }
+ }
+ }
+ }
+ }
expr = func;
} else {
@@ -4980,7 +5262,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Expected ','");
return ERR_PARSE_ERROR;
}
-
+ } else if (tk.type == TK_FILTER_LINEAR) {
+ uniform2.filter = FILTER_LINEAR;
+ } else if (tk.type == TK_FILTER_NEAREST) {
+ uniform2.filter = FILTER_NEAREST;
+ } else if (tk.type == TK_FILTER_NEAREST_MIPMAP) {
+ uniform2.filter = FILTER_NEAREST_MIPMAP;
+ } else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
+ uniform2.filter = FILTER_LINEAR_MIPMAP;
+ } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) {
+ uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO;
+ } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) {
+ uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO;
+ } else if (tk.type == TK_REPEAT_DISABLE) {
+ uniform2.repeat = REPEAT_DISABLE;
+ } else if (tk.type == TK_REPEAT_ENABLE) {
+ uniform2.repeat = REPEAT_ENABLE;
} else {
_set_error("Expected valid type hint after ':'.");
}
@@ -5293,6 +5590,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
arg.name = pname;
arg.precision = pprecision;
arg.qualifier = qualifier;
+ arg.tex_argument_check = false;
+ arg.tex_builtin_check = false;
+ arg.tex_argument_filter = FILTER_DEFAULT;
+ arg.tex_argument_repeat = REPEAT_DEFAULT;
func_node->arguments.push_back(arg);
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index f7b02ab70b..3a1ded0547 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -155,6 +155,14 @@ public:
TK_HINT_BLACK_ALBEDO_TEXTURE,
TK_HINT_COLOR,
TK_HINT_RANGE,
+ TK_FILTER_NEAREST,
+ TK_FILTER_LINEAR,
+ TK_FILTER_NEAREST_MIPMAP,
+ TK_FILTER_LINEAR_MIPMAP,
+ TK_FILTER_NEAREST_MIPMAP_ANISO,
+ TK_FILTER_LINEAR_MIPMAP_ANISO,
+ TK_REPEAT_ENABLE,
+ TK_REPEAT_DISABLE,
TK_SHADER_TYPE,
TK_CURSOR,
TK_ERROR,
@@ -284,6 +292,22 @@ public:
TAG_ARRAY,
};
+ enum TextureFilter {
+ FILTER_NEAREST,
+ FILTER_LINEAR,
+ FILTER_NEAREST_MIPMAP,
+ FILTER_LINEAR_MIPMAP,
+ FILTER_NEAREST_MIPMAP_ANISO,
+ FILTER_LINEAR_MIPMAP_ANISO,
+ FILTER_DEFAULT,
+ };
+
+ enum TextureRepeat {
+ REPEAT_DISABLE,
+ REPEAT_ENABLE,
+ REPEAT_DEFAULT,
+ };
+
struct Node {
Node *next;
@@ -485,11 +509,20 @@ public:
};
struct FunctionNode : public Node {
+
struct Argument {
ArgumentQualifier qualifier;
StringName name;
DataType type;
DataPrecision precision;
+ //for passing textures as arguments
+ bool tex_argument_check;
+ TextureFilter tex_argument_filter;
+ TextureRepeat tex_argument_repeat;
+ bool tex_builtin_check;
+ StringName tex_builtin;
+
+ Map<StringName, Set<int> > tex_argument_connect;
};
StringName name;
@@ -555,6 +588,8 @@ public:
DataPrecision precision;
Vector<ConstantNode::Value> default_value;
Hint hint;
+ TextureFilter filter;
+ TextureRepeat repeat;
float hint_range[3];
Uniform() :
@@ -562,7 +597,9 @@ public:
texture_order(0),
type(TYPE_VOID),
precision(PRECISION_DEFAULT),
- hint(HINT_NONE) {
+ hint(HINT_NONE),
+ filter(FILTER_DEFAULT),
+ repeat(REPEAT_DEFAULT) {
hint_range[0] = 0.0f;
hint_range[1] = 1.0f;
hint_range[2] = 0.001f;
@@ -631,6 +668,8 @@ public:
static bool is_scalar_type(DataType p_type);
static bool is_sampler_type(DataType p_type);
static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
+ static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
+ static uint32_t get_type_size(DataType p_type);
static void get_keyword_list(List<String> *r_keywords);
static void get_builtin_funcs(List<String> *r_keywords);
@@ -750,6 +789,8 @@ private:
bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type);
bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL);
+ bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
+ bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index b6eb5a74f9..9c7c97ffe5 100644
--- a/servers/visual/shader_types.cpp
+++ b/servers/visual/shader_types.cpp
@@ -202,14 +202,17 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["EXTRA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["CANVAS_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["SCREEN_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
@@ -219,6 +222,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
@@ -229,18 +234,17 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_MODULATE"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VEC"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_VEC"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_HEIGHT"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_COLOR"] = ShaderLanguage::TYPE_VEC4;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index d84fb0b715..08d4b7dc52 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -209,7 +209,6 @@ public:
BIND0R(RID, material_create)
BIND2(material_set_shader, RID, RID)
- BIND1RC(RID, material_get_shader, RID)
BIND3(material_set_param, RID, const StringName &, const Variant &)
BIND2RC(Variant, material_get_param, RID, const StringName &)
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 69ab4a6b9b..e2fb0a6351 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -304,12 +304,12 @@ void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p
/* INSTANCING API */
-void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_materials) {
+void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
if (p_update_aabb)
p_instance->update_aabb = true;
- if (p_update_materials)
- p_instance->update_materials = true;
+ if (p_update_dependencies)
+ p_instance->update_dependencies = true;
if (p_instance->update_item.in_list())
return;
@@ -338,8 +338,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
if (instance->base_type != VS::INSTANCE_NONE) {
//free anything related to that base
- VSG::storage->instance_remove_dependency(instance->base, instance);
-
if (instance->base_type == VS::INSTANCE_GI_PROBE) {
//if gi probe is baking, wait until done baking, else race condition may happen when removing it
//from octree
@@ -421,12 +419,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
}
instance->blend_values.clear();
-
- for (int i = 0; i < instance->materials.size(); i++) {
- if (instance->materials[i].is_valid()) {
- VSG::storage->material_remove_instance_owner(instance->materials[i], instance);
- }
- }
instance->materials.clear();
}
@@ -493,13 +485,13 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
}
}
- VSG::storage->instance_add_dependency(p_base, instance);
-
instance->base = p_base;
- if (scenario)
- _instance_queue_update(instance, true, true);
+ //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
+ VSG::storage->base_update_dependency(p_base, instance);
}
+
+ _instance_queue_update(instance, true, true);
}
void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
@@ -635,21 +627,15 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf
ERR_FAIL_COND(!instance);
if (instance->base_type == VS::INSTANCE_MESH) {
- //may not have been updated yet
- instance->materials.resize(VSG::storage->mesh_get_surface_count(instance->base));
+ //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
+ instance->materials.resize(MAX(p_surface + 1, VSG::storage->mesh_get_surface_count(instance->base)));
}
ERR_FAIL_INDEX(p_surface, instance->materials.size());
- if (instance->materials[p_surface].is_valid()) {
- VSG::storage->material_remove_instance_owner(instance->materials[p_surface], instance);
- }
instance->materials.write[p_surface] = p_material;
- instance->base_changed(false, true);
- if (instance->materials[p_surface].is_valid()) {
- VSG::storage->material_add_instance_owner(instance->materials[p_surface], instance);
- }
+ _instance_queue_update(instance, false, true);
}
void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
@@ -753,17 +739,13 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton)
if (instance->skeleton == p_skeleton)
return;
- if (instance->skeleton.is_valid()) {
- VSG::storage->instance_remove_skeleton(instance->skeleton, instance);
- }
-
instance->skeleton = p_skeleton;
- if (instance->skeleton.is_valid()) {
- VSG::storage->instance_add_skeleton(instance->skeleton, instance);
+ if (p_skeleton.is_valid()) {
+ //update the dependency now, so if cleared, we remove it
+ VSG::storage->skeleton_update_dependency(p_skeleton, instance);
}
-
- _instance_queue_update(instance, true);
+ _instance_queue_update(instance, true, true);
}
void VisualServerScene::instance_set_exterior(RID p_instance, bool p_enabled) {
@@ -875,22 +857,15 @@ void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instanc
ERR_FAIL_COND(!instance);
instance->cast_shadows = p_shadow_casting_setting;
- instance->base_changed(false, true); // to actually compute if shadows are visible or not
+ _instance_queue_update(instance, false, true);
}
void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
- if (instance->material_override.is_valid()) {
- VSG::storage->material_remove_instance_owner(instance->material_override, instance);
- }
instance->material_override = p_material;
- instance->base_changed(false, true);
-
- if (instance->material_override.is_valid()) {
- VSG::storage->material_add_instance_owner(instance->material_override, instance);
- }
+ _instance_queue_update(instance, false, true);
}
void VisualServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
@@ -3291,17 +3266,22 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
_update_instance_aabb(p_instance);
}
- if (p_instance->update_materials) {
+ if (p_instance->update_dependencies) {
+
+ p_instance->instance_increase_version();
+
+ if (p_instance->base.is_valid()) {
+ VSG::storage->base_update_dependency(p_instance->base, p_instance);
+ }
+
+ if (p_instance->material_override.is_valid()) {
+ VSG::storage->material_update_dependency(p_instance->material_override, p_instance);
+ }
if (p_instance->base_type == VS::INSTANCE_MESH) {
//remove materials no longer used and un-own them
int new_mat_count = VSG::storage->mesh_get_surface_count(p_instance->base);
- for (int i = p_instance->materials.size() - 1; i >= new_mat_count; i--) {
- if (p_instance->materials[i].is_valid()) {
- VSG::storage->material_remove_instance_owner(p_instance->materials[i], p_instance);
- }
- }
p_instance->materials.resize(new_mat_count);
int new_blend_shape_count = VSG::storage->mesh_get_blend_shape_count(p_instance->base);
@@ -3348,6 +3328,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
if (VSG::storage->material_is_animated(mat)) {
is_animated = true;
}
+
+ VSG::storage->material_update_dependency(mat, p_instance);
}
}
@@ -3378,6 +3360,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
if (VSG::storage->material_is_animated(mat)) {
is_animated = true;
}
+
+ VSG::storage->material_update_dependency(mat, p_instance);
}
}
@@ -3394,6 +3378,11 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
if (mat.is_valid() && VSG::storage->material_is_animated(mat)) {
is_animated = true;
}
+
+ if (mat.is_valid()) {
+ VSG::storage->material_update_dependency(mat, p_instance);
+ }
+
} else if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
bool cast_shadows = false;
@@ -3422,6 +3411,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
if (VSG::storage->material_is_animated(mat)) {
is_animated = true;
}
+
+ VSG::storage->material_update_dependency(mat, p_instance);
}
}
}
@@ -3444,6 +3435,12 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
geom->material_is_animated = is_animated;
}
+
+ if (p_instance->skeleton.is_valid()) {
+ VSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance);
+ }
+
+ p_instance->clean_up_dependencies();
}
_instance_update_list.remove(&p_instance->update_item);
@@ -3451,7 +3448,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
_update_instance(p_instance);
p_instance->update_aabb = false;
- p_instance->update_materials = false;
+ p_instance->update_dependencies = false;
}
void VisualServerScene::update_dirty_instances() {
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index 61fdfd0861..a4c3499359 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -151,7 +151,7 @@ public:
//aabb stuff
bool update_aabb;
- bool update_materials;
+ bool update_dependencies;
SelfList<Instance> update_item;
@@ -174,14 +174,18 @@ public:
InstanceBaseData *base_data;
- virtual void base_removed() {
-
- singleton->instance_set_base(self, RID());
+ virtual void dependency_deleted(RID p_dependency) {
+ if (p_dependency == base) {
+ singleton->instance_set_base(self, RID());
+ } else if (p_dependency == skeleton) {
+ singleton->instance_attach_skeleton(self, RID());
+ } else {
+ singleton->_instance_queue_update(this, false, true);
+ }
}
- virtual void base_changed(bool p_aabb, bool p_materials) {
-
- singleton->_instance_queue_update(this, p_aabb, p_materials);
+ virtual void dependency_changed(bool p_aabb, bool p_dependencies) {
+ singleton->_instance_queue_update(this, p_aabb, p_dependencies);
}
Instance() :
@@ -192,7 +196,7 @@ public:
scenario = NULL;
update_aabb = false;
- update_materials = false;
+ update_dependencies = false;
extra_margin = 0;
@@ -222,7 +226,7 @@ public:
};
SelfList<Instance>::List _instance_update_list;
- void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_materials = false);
+ void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false);
struct InstanceGeometryData : public InstanceBaseData {
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 610aa9c305..c2e7f659ab 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -140,7 +140,6 @@ public:
FUNCRID(material)
FUNC2(material_set_shader, RID, RID)
- FUNC1RC(RID, material_get_shader, RID)
FUNC3(material_set_param, RID, const StringName &, const Variant &)
FUNC2RC(Variant, material_get_param, RID, const StringName &)