diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-07-21 11:31:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:29 +0100 |
commit | 8bbbb973361f367a4888629c571fb6f43581269d (patch) | |
tree | 89724be2ee4a81111bedd383668665e0ae3bf276 /servers/visual | |
parent | 50e9befb888480a3d6cb2fa46b58c0753b69bd86 (diff) |
Completed material/2D shader support (missing SCREEN_TEXTURE)
Diffstat (limited to 'servers/visual')
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 *¤t_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 *¤t_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 *¤t_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 *¤t_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 &) |