diff options
Diffstat (limited to 'servers/rendering')
-rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_rd.cpp | 10 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl | 18 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl | 18 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/skeleton.glsl | 64 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp | 36 | ||||
-rw-r--r-- | servers/rendering/renderer_viewport.cpp | 52 | ||||
-rw-r--r-- | servers/rendering/renderer_viewport.h | 15 | ||||
-rw-r--r-- | servers/rendering/rendering_device_binds.h | 6 | ||||
-rw-r--r-- | servers/rendering/shader_preprocessor.cpp | 214 | ||||
-rw-r--r-- | servers/rendering/shader_preprocessor.h | 15 |
10 files changed, 354 insertions, 94 deletions
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 6c219933b0..d8499681ad 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -2868,7 +2868,9 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet."); } - light_data.shadow_opacity = p_using_shadows && light_storage->light_has_shadow(base) ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) : 0.0; + light_data.shadow_opacity = (p_using_shadows && light_storage->light_has_shadow(base)) + ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) + : 0.0; float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); if (angular_diameter > 0.0) { @@ -3122,7 +3124,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.projector_rect[3] = 0; } - const bool needs_shadow = shadow_atlas && shadow_atlas->shadow_owners.has(li->self); + const bool needs_shadow = + shadow_atlas && + shadow_atlas->shadow_owners.has(li->self) && + p_using_shadows && + light_storage->light_has_shadow(base); bool in_shadow_range = true; if (needs_shadow && light_storage->light_is_distance_fade_enabled(li->light)) { diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e9515c7670..6b4e4a5a16 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -15,11 +15,11 @@ layout(location = 0) in vec3 vertex_attrib; //only for pure render depth when normal is not used #ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; +layout(location = 1) in vec2 normal_attrib; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; +layout(location = 2) in vec2 tangent_attrib; #endif #if defined(COLOR_USED) @@ -58,6 +58,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +vec3 oct_to_vec3(vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return v; +} + /* Varyings */ layout(location = 0) out vec3 vertex_interp; @@ -231,12 +238,13 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc vec3 vertex = vertex_attrib; #ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; + vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; + vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + float binormalf = sign(signed_tangent_attrib.y); vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 6548793bee..0960533917 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -16,11 +16,11 @@ layout(location = 0) in vec3 vertex_attrib; //only for pure render depth when normal is not used #ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; +layout(location = 1) in vec2 normal_attrib; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; +layout(location = 2) in vec2 tangent_attrib; #endif #if defined(COLOR_USED) @@ -59,6 +59,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +vec3 oct_to_vec3(vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return v; +} + /* Varyings */ layout(location = 0) highp out vec3 vertex_interp; @@ -229,12 +236,13 @@ void main() { vec3 vertex = vertex_attrib; #ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; + vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec3 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; + vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + float binormalf = sign(signed_tangent_attrib.y); vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index a893a66c94..75bea9300b 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -54,14 +54,54 @@ layout(push_constant, std430) uniform Params { } params; -vec4 decode_abgr_2_10_10_10(uint base) { - uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3); - return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0; +vec2 uint_to_vec2(uint base) { + uvec2 decode = (uvec2(base) >> uvec2(0, 16)) & uvec2(0xFFFF, 0xFFFF); + return vec2(decode) / vec2(65535.0, 65535.0) * 2.0 - 1.0; } -uint encode_abgr_2_10_10_10(vec4 base) { - uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30); - return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w; +vec3 oct_to_vec3(vec2 oct) { + vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return v; +} + +vec3 decode_uint_oct_to_norm(uint base) { + return oct_to_vec3(uint_to_vec2(base)); +} + +vec4 decode_uint_oct_to_tang(uint base) { + vec2 oct_sign_encoded = uint_to_vec2(base); + // Binormal sign encoded in y component + vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0); + return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y)); +} + +vec2 signNotZero(vec2 v) { + return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0))); +} + +uint vec2_to_uint(vec2 base) { + uvec2 enc = uvec2(clamp(ivec2(base * vec2(65535, 65535)), ivec2(0), ivec2(0xFFFF, 0xFFFF))) << uvec2(0, 16); + return enc.x | enc.y; +} + +vec2 vec3_to_oct(vec3 e) { + e /= abs(e.x) + abs(e.y) + abs(e.z); + vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy); + return oct * 0.5f + 0.5f; +} + +uint encode_norm_to_uint_oct(vec3 base) { + return vec2_to_uint(vec3_to_oct(base)); +} + +uint encode_tang_to_uint_oct(vec4 base) { + vec2 oct = vec3_to_oct(base.xyz); + // Encode binormal sign in y component + oct.y = oct.y * 0.5f + 0.5f; + oct.y = base.w >= 0.0f ? oct.y : 1 - oct.y; + return vec2_to_uint(oct); } void main() { @@ -131,12 +171,12 @@ void main() { src_offset += 3; if (params.has_normal) { - normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb; + normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]); src_offset++; } if (params.has_tangent) { - tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]); + tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]); } if (params.has_blend_shape) { @@ -155,12 +195,12 @@ void main() { base_offset += 3; if (params.has_normal) { - blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w; base_offset++; } if (params.has_tangent) { - blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w; } blend_total += w; @@ -234,12 +274,12 @@ void main() { dst_offset += 3; if (params.has_normal) { - dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0)); + dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal); dst_offset++; } if (params.has_tangent) { - dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent); + dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent); } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 585c42b2d8..49d7198ec2 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -327,8 +327,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0); - s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage); - s->vertex_buffer_size = p_surface.vertex_data.size(); + if (p_surface.vertex_data.size()) { + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage); + s->vertex_buffer_size = p_surface.vertex_data.size(); + } if (p_surface.attribute_data.size()) { s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data); @@ -345,7 +347,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } if (p_surface.index_count) { - bool is_index_16 = p_surface.vertex_count <= 65536; + bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0; s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false); s->index_count = p_surface.index_count; @@ -364,6 +366,8 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } } + ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both"); + s->aabb = p_surface.aabb; s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them. @@ -377,7 +381,11 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) RD::Uniform u; u.binding = 0; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(s->vertex_buffer); + if (s->vertex_buffer.is_valid()) { + u.append_id(s->vertex_buffer); + } else { + u.append_id(default_rd_storage_buffer); + } uniforms.push_back(u); } { @@ -470,6 +478,7 @@ void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, i ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); ERR_FAIL_COND(p_data.size() == 0); + ERR_FAIL_COND(mesh->surfaces[p_surface]->vertex_buffer.is_null()); uint64_t data_size = p_data.size(); const uint8_t *r = p_data.ptr(); @@ -527,7 +536,9 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { RS::SurfaceData sd; sd.format = s.format; - sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + if (s.vertex_buffer.is_valid()) { + sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + } if (s.attribute_buffer.is_valid()) { sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer); } @@ -705,7 +716,9 @@ void MeshStorage::mesh_clear(RID p_mesh) { ERR_FAIL_COND(!mesh); for (uint32_t i = 0; i < mesh->surface_count; i++) { Mesh::Surface &s = *mesh->surfaces[i]; - RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions + if (s.vertex_buffer.is_valid()) { + RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions + } if (s.attribute_buffer.is_valid()) { RD::get_singleton()->free(s.attribute_buffer); } @@ -851,7 +864,7 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3 } MeshInstance::Surface s; - if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) { + if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) { //surface warrants transform s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true); @@ -1060,10 +1073,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_NORMAL: { vd.offset = stride; + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + stride += sizeof(uint16_t) * 2; - vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; - - stride += sizeof(uint32_t); if (mis) { buffer = mis->vertex_buffer; } else { @@ -1072,9 +1084,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_TANGENT: { vd.offset = stride; + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + stride += sizeof(uint16_t) * 2; - vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; - stride += sizeof(uint32_t); if (mis) { buffer = mis->vertex_buffer; } else { diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 73b03966c5..bfb81925bc 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -72,6 +72,41 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, return xf; } +Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() { + // We need to sort the viewports in a "topological order", + // children first and parents last, we use the Kahn's algorithm to achieve that. + + Vector<Viewport *> result; + List<Viewport *> nodes; + + for (Viewport *viewport : active_viewports) { + if (viewport->parent.is_valid()) { + continue; + } + + nodes.push_back(viewport); + } + + while (!nodes.is_empty()) { + Viewport *node = nodes[0]; + nodes.pop_front(); + + result.insert(0, node); + + for (Viewport *child : active_viewports) { + if (child->parent != node->self) { + continue; + } + + if (!nodes.find(child)) { + nodes.push_back(child); + } + } + } + + return result; +} + void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { if (p_viewport->render_buffers.is_valid()) { if (p_viewport->size.width == 0 || p_viewport->size.height == 0) { @@ -548,8 +583,10 @@ void RendererViewport::draw_viewports() { set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); } - //sort viewports - active_viewports.sort_custom<ViewportSort>(); + if (sorted_active_viewports_dirty) { + sorted_active_viewports = _sort_active_viewports(); + sorted_active_viewports_dirty = false; + } HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list; //draw viewports @@ -558,9 +595,9 @@ void RendererViewport::draw_viewports() { //determine what is visible draw_viewports_pass++; - for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order + for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order - Viewport *vp = active_viewports[i]; + Viewport *vp = sorted_active_viewports[i]; if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) { continue; @@ -621,8 +658,8 @@ void RendererViewport::draw_viewports() { int objects_drawn = 0; int draw_calls_used = 0; - for (int i = 0; i < active_viewports.size(); i++) { - Viewport *vp = active_viewports[i]; + for (int i = 0; i < sorted_active_viewports.size(); i++) { + Viewport *vp = sorted_active_viewports[i]; if (vp->last_pass != draw_viewports_pass) { continue; //should not draw @@ -814,6 +851,8 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { } else { active_viewports.erase(viewport); } + + sorted_active_viewports_dirty = true; } void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { @@ -1243,6 +1282,7 @@ bool RendererViewport::free(RID p_rid) { viewport_set_scenario(p_rid, RID()); active_viewports.erase(viewport); + sorted_active_viewports_dirty = true; if (viewport->use_occlusion_culling) { RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 5e37c96336..ab4893a908 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -185,25 +185,16 @@ public: mutable RID_Owner<Viewport, true> viewport_owner; - struct ViewportSort { - _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const { - bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2(); - bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2(); - - if (left_to_screen == right_to_screen) { - return p_right->parent == p_left->self; - } - return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1); - } - }; - Vector<Viewport *> active_viewports; + Vector<Viewport *> sorted_active_viewports; + bool sorted_active_viewports_dirty = false; int total_objects_drawn = 0; int total_vertices_drawn = 0; int total_draw_calls_used = 0; private: + Vector<Viewport *> _sort_active_viewports(); void _configure_3d_render_buffers(Viewport *p_viewport); void _draw_3d(Viewport *p_viewport); void _draw_viewport(Viewport *p_viewport); diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 8bdd3deea1..a56b7eb241 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -443,8 +443,8 @@ public: void add_id(const RID &p_id) { base.append_id(p_id); } void clear_ids() { base.clear_ids(); } - Array get_ids() const { - Array ids; + TypedArray<RID> get_ids() const { + TypedArray<RID> ids; for (uint32_t i = 0; i < base.get_id_count(); i++) { ids.push_back(base.get_id(i)); } @@ -452,7 +452,7 @@ public: } protected: - void _set_ids(const Array &p_ids) { + void _set_ids(const TypedArray<RID> &p_ids) { base.clear_ids(); for (int i = 0; i < p_ids.size(); i++) { RID id = p_ids[i]; diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 8755ee61cc..3766477070 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -434,7 +434,12 @@ void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) { return; } - Error error = expand_macros(body, line, body); + Error error = expand_condition(body, line, body); + if (error != OK) { + return; + } + + error = expand_macros(body, line, body); if (error != OK) { return; } @@ -528,7 +533,12 @@ void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) { return; } - Error error = expand_macros(body, line, body); + Error error = expand_condition(body, line, body); + if (error != OK) { + return; + } + + error = expand_macros(body, line, body); if (error != OK) { return; } @@ -777,47 +787,173 @@ void ShaderPreprocessor::expand_output_macros(int p_start, int p_line_number) { add_to_output(line); } -Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) { - Vector<Pair<String, Define *>> active_defines; - active_defines.resize(state->defines.size()); - int index = 0; - for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { - active_defines.set(index++, Pair<String, Define *>(E->key(), E->get())); +Error ShaderPreprocessor::expand_condition(const String &p_string, int p_line, String &r_expanded) { + // Checks bracket count to be even + check the cursor position. + { + int bracket_start_count = 0; + int bracket_end_count = 0; + + for (int i = 0; i < p_string.size(); i++) { + switch (p_string[i]) { + case CURSOR: + state->completion_type = COMPLETION_TYPE_CONDITION; + break; + case '(': + bracket_start_count++; + break; + case ')': + bracket_end_count++; + break; + } + } + if (bracket_start_count > bracket_end_count) { + _set_expected_error(")", p_line); + return FAILED; + } + if (bracket_end_count > bracket_start_count) { + _set_expected_error("(", p_line); + return FAILED; + } } - return expand_macros(p_string, p_line, active_defines, r_expanded); + String result = p_string; + + int index = 0; + int index_start = 0; + int index_end = 0; + + while (find_match(result, "defined", index, index_start)) { + bool open_bracket = false; + bool found_word = false; + bool word_completed = false; + + LocalVector<char32_t> text; + int post_bracket_index = -1; + int size = result.size(); + + for (int i = (index_start - 1); i < size; i++) { + char32_t c = result[i]; + if (c == 0) { + if (found_word) { + word_completed = true; + } + break; + } + char32_t cs[] = { c, '\0' }; + String s = String(cs); + bool is_space = is_char_space(c); + + if (word_completed) { + if (c == ')') { + continue; + } + if (c == '|' || c == '&') { + if (open_bracket) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + break; + } else if (!is_space) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + } else if (is_space) { + if (found_word && !open_bracket) { + index_end = i; + word_completed = true; + } + } else if (c == '(') { + if (open_bracket) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + open_bracket = true; + } else if (c == ')') { + if (open_bracket) { + if (!found_word) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + open_bracket = false; + post_bracket_index = i + 1; + } else { + index_end = i; + } + word_completed = true; + } else if (is_char_word(c)) { + text.push_back(c); + found_word = true; + } else { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + } + + if (word_completed) { + if (open_bracket) { + _set_expected_error(")", p_line); + return FAILED; + } + if (post_bracket_index != -1) { + index_end = post_bracket_index; + } + + String body = state->defines.has(vector_to_string(text)) ? "true" : "false"; + String temp = result; + + result = result.substr(0, index) + body; + index_start = result.length(); + if (index_end > 0) { + result += temp.substr(index_end); + } + } else { + set_error(RTR("Invalid macro name."), p_line); + return FAILED; + } + } + r_expanded = result; + return OK; } -Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_expanded) { - r_expanded = p_string; - // When expanding macros we must only evaluate them once. - // Later we continue expanding but with the already - // evaluated macros removed. - for (int i = 0; i < p_defines.size(); i++) { - Pair<String, Define *> define_pair = p_defines[i]; - - Error error = expand_macros_once(r_expanded, p_line, define_pair, r_expanded); - if (error != OK) { - return error; +Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) { + String iterative = p_string; + int pass_count = 0; + bool expanded = true; + + while (expanded) { + expanded = false; + + // As long as we find something to expand, keep going. + for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { + if (expand_macros_once(iterative, p_line, E, iterative)) { + expanded = true; + } } - // Remove expanded macro and recursively replace remaining. - p_defines.remove_at(i); - return expand_macros(r_expanded, p_line, p_defines, r_expanded); + pass_count++; + if (pass_count > 50) { + set_error(RTR("Macro expansion limit exceeded."), p_line); + break; + } } + r_expanded = iterative; + + if (!state->error.is_empty()) { + return FAILED; + } return OK; } -Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded) { +bool ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, const RBMap<String, Define *>::Element *p_define_pair, String &r_expanded) { String result = p_line; - const String &key = p_define_pair.first; - const Define *define = p_define_pair.second; + const String &key = p_define_pair->key(); + const Define *define = p_define_pair->value(); int index_start = 0; int index = 0; - while (find_match(result, key, index, index_start)) { + if (find_match(result, key, index, index_start)) { String body = define->body; if (define->arguments.size() > 0) { // Complex macro with arguments. @@ -825,14 +961,14 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu int args_end = p_line.find(")", args_start); if (args_start == -1 || args_end == -1) { set_error(RTR("Missing macro argument parenthesis."), p_line_number); - return FAILED; + return false; } String values = result.substr(args_start + 1, args_end - (args_start + 1)); Vector<String> args = values.split(","); if (args.size() != define->arguments.size()) { set_error(RTR("Invalid macro argument count."), p_line_number); - return FAILED; + return false; } // Insert macro arguments into the body. @@ -854,11 +990,13 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu // Manually reset index_start to where the body value of the define finishes. // This ensures we don't skip another instance of this macro in the string. index_start = index + body.length() + 1; - break; } + + r_expanded = result; + return true; } - r_expanded = result; - return OK; + + return false; } bool ShaderPreprocessor::find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start) { @@ -1064,7 +1202,7 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen switch (pp_state.completion_type) { case COMPLETION_TYPE_DIRECTIVE: { List<String> options; - get_keyword_list(&options, true); + get_keyword_list(&options, true, true); for (const String &E : options) { ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -1083,6 +1221,11 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen } } break; + case COMPLETION_TYPE_CONDITION: { + ScriptLanguage::CodeCompletionOption option("defined", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); + r_completion_options->push_back(option); + + } break; case COMPLETION_TYPE_INCLUDE_PATH: { if (p_include_completion_func && r_completion_options) { p_include_completion_func(r_completion_options); @@ -1096,8 +1239,11 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen return err; } -void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) { +void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords) { r_keywords->push_back("define"); + if (!p_ignore_context_keywords) { + r_keywords->push_back("defined"); + } r_keywords->push_back("elif"); if (p_include_shader_keywords) { r_keywords->push_back("else"); diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h index 71dd9a6ca8..b4e7c7199f 100644 --- a/servers/rendering/shader_preprocessor.h +++ b/servers/rendering/shader_preprocessor.h @@ -50,6 +50,7 @@ public: COMPLETION_TYPE_DIRECTIVE, COMPLETION_TYPE_PRAGMA_DIRECTIVE, COMPLETION_TYPE_PRAGMA, + COMPLETION_TYPE_CONDITION, COMPLETION_TYPE_INCLUDE_PATH, }; @@ -175,6 +176,14 @@ private: static String vector_to_string(const LocalVector<char32_t> &p_v, int p_start = 0, int p_end = -1); static String tokens_to_string(const LocalVector<Token> &p_tokens); + void _set_expected_error(const String &p_what, int p_line) { + set_error(vformat(RTR("Expected a '%s'."), p_what), p_line); + } + + void _set_unexpected_token_error(const String &p_what, int p_line) { + set_error(vformat(RTR("Unexpected token '%s'."), p_what), p_line); + } + void process_directive(Tokenizer *p_tokenizer); void process_define(Tokenizer *p_tokenizer); void process_elif(Tokenizer *p_tokenizer); @@ -190,10 +199,10 @@ private: void add_region(int p_line, bool p_enabled, Region *p_parent_region); void start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue = false); + Error expand_condition(const String &p_string, int p_line, String &r_result); void expand_output_macros(int p_start, int p_line); Error expand_macros(const String &p_string, int p_line, String &r_result); - Error expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_result); - Error expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded); + bool expand_macros_once(const String &p_line, int p_line_number, const RBMap<String, Define *>::Element *p_define_pair, String &r_expanded); bool find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start); String next_directive(Tokenizer *p_tokenizer, const Vector<String> &p_directives); @@ -211,7 +220,7 @@ public: Error preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text = nullptr, List<FilePosition> *r_error_position = nullptr, List<Region> *r_regions = nullptr, HashSet<Ref<ShaderInclude>> *r_includes = nullptr, List<ScriptLanguage::CodeCompletionOption> *r_completion_options = nullptr, IncludeCompletionFunction p_include_completion_func = nullptr); - static void get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords); + static void get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords = false); static void get_pragma_list(List<String> *r_pragmas); ShaderPreprocessor(); |