diff options
Diffstat (limited to 'servers/rendering')
71 files changed, 1353 insertions, 692 deletions
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h index 7640afc711..6205193d9a 100644 --- a/servers/rendering/dummy/rasterizer_dummy.h +++ b/servers/rendering/dummy/rasterizer_dummy.h @@ -66,14 +66,14 @@ protected: RasterizerSceneDummy scene; public: - RendererUtilities *get_utilities() override { return &utilities; }; - RendererLightStorage *get_light_storage() override { return &light_storage; }; - RendererMaterialStorage *get_material_storage() override { return &material_storage; }; - RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; }; - RendererParticlesStorage *get_particles_storage() override { return &particles_storage; }; - RendererTextureStorage *get_texture_storage() override { return &texture_storage; }; - RendererGI *get_gi() override { return &gi; }; - RendererFog *get_fog() override { return &fog; }; + RendererUtilities *get_utilities() override { return &utilities; } + RendererLightStorage *get_light_storage() override { return &light_storage; } + RendererMaterialStorage *get_material_storage() override { return &material_storage; } + RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; } + RendererParticlesStorage *get_particles_storage() override { return &particles_storage; } + RendererTextureStorage *get_texture_storage() override { return &texture_storage; } + RendererGI *get_gi() override { return &gi; } + RendererFog *get_fog() override { return &fog; } RendererCanvasRender *get_canvas() override { return &canvas; } RendererSceneRender *get_scene() override { return &scene; } diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index c3b63cdbf6..d25523753c 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -78,6 +78,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override {} virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override {} virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {} + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override {} + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override { return 0xFFFFFFFF; } virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {} virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {} diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h index e4c58474e2..74ae71cba6 100644 --- a/servers/rendering/dummy/storage/material_storage.h +++ b/servers/rendering/dummy/storage/material_storage.h @@ -92,7 +92,7 @@ public: virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); } virtual Variant shader_get_parameter_default(RID p_material, const StringName &p_param) const override { return Variant(); } - virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }; + virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); } /* MATERIAL API */ virtual RID material_allocate() override { return RID(); } diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index b0953b5dce..855336c71f 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -64,7 +64,7 @@ public: /* MESH API */ - bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); }; + bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); } virtual RID mesh_allocate() override; virtual void mesh_initialize(RID p_rid) override; diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 6735f6bcda..63eb441915 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -53,7 +53,7 @@ public: /* Canvas Texture API */ - virtual RID canvas_texture_allocate() override { return RID(); }; + virtual RID canvas_texture_allocate() override { return RID(); } virtual void canvas_texture_initialize(RID p_rid) override {} virtual void canvas_texture_free(RID p_rid) override {} @@ -65,13 +65,13 @@ public: /* Texture API */ - bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); }; + bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); } virtual RID texture_allocate() override { DummyTexture *texture = memnew(DummyTexture); ERR_FAIL_NULL_V(texture, RID()); return texture_owner.make_rid(texture); - }; + } virtual void texture_free(RID p_rid) override { // delete the texture @@ -79,13 +79,13 @@ public: ERR_FAIL_NULL(texture); texture_owner.free(p_rid); memdelete(texture); - }; + } virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override { DummyTexture *t = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL(t); t->image = p_image->duplicate(); - }; + } virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {} virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override {} virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override {} @@ -107,15 +107,15 @@ public: DummyTexture *t = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL_V(t, Ref<Image>()); return t->image; - }; - virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); }; - virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }; + } + virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); } + virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); } - virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); }; + virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); } virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} virtual void texture_set_path(RID p_texture, const String &p_path) override {} - virtual String texture_get_path(RID p_texture) const override { return String(); }; + virtual String texture_get_path(RID p_texture) const override { return String(); } virtual Image::Format texture_get_format(RID p_texture) const override { return Image::FORMAT_MAX; } @@ -127,11 +127,11 @@ public: virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {} - virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); }; + virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); } virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override {} - virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); }; - virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; }; + virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); } + virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; } /* DECAL API */ virtual RID decal_allocate() override { return RID(); } diff --git a/servers/rendering/dummy/storage/utilities.h b/servers/rendering/dummy/storage/utilities.h index ae83547afd..4e20dee640 100644 --- a/servers/rendering/dummy/storage/utilities.h +++ b/servers/rendering/dummy/storage/utilities.h @@ -124,7 +124,7 @@ public: virtual RenderingDevice::DeviceType get_video_adapter_type() const override { return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; } virtual String get_video_adapter_api_version() const override { return String(); } - virtual Size2i get_maximum_viewport_size() const override { return Size2i(); }; + virtual Size2i get_maximum_viewport_size() const override { return Size2i(); } }; } // namespace RendererDummy diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 701b4da8f8..d01976acf2 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -612,8 +612,9 @@ void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p uint32_t RendererCanvasCull::canvas_item_get_visibility_layer(RID p_item) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); - if (!canvas_item) + if (!canvas_item) { return 0; + } return canvas_item->visibility_layer; } diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index a585c9430b..dbc8f155bf 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -106,7 +106,7 @@ public: virtual double get_total_time() const = 0; virtual bool can_create_resources_async() const = 0; - static bool is_low_end() { return low_end; }; + static bool is_low_end() { return low_end; } virtual bool is_xr_enabled() const; static RendererCompositor *get_singleton() { return singleton; } diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index c7a7532d76..808c82f712 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -1002,15 +1002,19 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); + Rect2i screen_rect; + float atlas_width = p_dst_size.width / p_rect.size.width; + float atlas_height = p_dst_size.height / p_rect.size.height; + screen_rect.position.x = (int32_t)(Math::round(p_rect.position.x * atlas_width)); + screen_rect.position.y = (int32_t)(Math::round(p_rect.position.y * atlas_height)); + screen_rect.size.width = (int32_t)(Math::round(p_dst_size.width)); + screen_rect.size.height = (int32_t)(Math::round(p_dst_size.height)); + CopyToDPPushConstant push_constant; - push_constant.screen_rect[0] = p_rect.position.x; - push_constant.screen_rect[1] = p_rect.position.y; - push_constant.screen_rect[2] = p_rect.size.width; - push_constant.screen_rect[3] = p_rect.size.height; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; - push_constant.texel_size[0] = 1.0f / p_dst_size.x; - push_constant.texel_size[1] = 1.0f / p_dst_size.y; + push_constant.texel_size[0] = 1.0f / p_dst_size.width; + push_constant.texel_size[1] = 1.0f / p_dst_size.height; push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign // setup our uniforms @@ -1021,7 +1025,7 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0f, 0, screen_rect); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index 014f78e2b9..b6fc95d0f1 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -217,7 +217,6 @@ private: float z_far; float z_near; float texel_size[2]; - float screen_rect[4]; }; struct CopyToDP { diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 2dfcd67411..090eab384f 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -157,7 +157,7 @@ RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_func() { RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_funcs() { return Fog::get_singleton()->_create_fog_shader_func(); -}; +} RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_func(FogShaderData *p_shader) { FogMaterialData *material_data = memnew(FogMaterialData); @@ -168,7 +168,7 @@ RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_func(FogSha RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) { return Fog::get_singleton()->_create_fog_material_func(static_cast<FogShaderData *>(p_shader)); -}; +} //////////////////////////////////////////////////////////////////////////////// // FOG VOLUMES INSTANCE @@ -622,6 +622,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); bool any_uses_time = false; + Vector3 cam_position = p_cam_transform.get_origin(); for (int i = 0; i < (int)p_fog_volumes.size(); i++) { FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]); @@ -652,41 +653,68 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P any_uses_time |= shader_data->uses_time; - Vector3i min; - Vector3i max; + Vector3i froxel_min; + Vector3i froxel_max; Vector3i kernel_size; - Vector3 position = fog_volume_instance->transform.get_origin(); + Vector3 fog_position = fog_volume_instance->transform.get_origin(); RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume); Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_size(fog_volume) / 2; if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { // Local fog volume. - Vector3i points[8]; Vector3 fog_size = Vector3(fog->width, fog->height, fog->depth); float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env); - points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - - min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1); - max = Vector3i(1, 1, 1); - + Vector3 corners[8]{ + fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)) + }; + Vector3i froxels[8]; + Vector3 corner_min = corners[0]; + Vector3 corner_max = corners[0]; for (int j = 0; j < 8; j++) { - min = min.min(points[j]); - max = max.max(points[j]); + froxels[j] = _point_get_position_in_froxel_volume(corners[j], fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); + corner_min = corner_min.min(corners[j]); + corner_max = corner_max.max(corners[j]); + } + + froxel_min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1); + froxel_max = Vector3i(1, 1, 1); + + // Tracking just the corners of the fog volume can result in missing some fog: + // when the camera's near plane is inside the fog, we must always consider the entire screen + Vector3 near_plane_corner(frustum_near_size.x, frustum_near_size.y, z_near); + float expand = near_plane_corner.length(); + if (cam_position.x > (corner_min.x - expand) && cam_position.x < (corner_max.x + expand) && + cam_position.y > (corner_min.y - expand) && cam_position.y < (corner_max.y + expand) && + cam_position.z > (corner_min.z - expand) && cam_position.z < (corner_max.z + expand)) { + froxel_min.x = 0; + froxel_min.y = 0; + froxel_min.z = 0; + froxel_max.x = int32_t(fog->width); + froxel_max.y = int32_t(fog->height); + for (int j = 0; j < 8; j++) { + froxel_max.z = MAX(froxel_max.z, froxels[j].z); + } + } else { + // Camera is guaranteed to be outside the fog volume + for (int j = 0; j < 8; j++) { + froxel_min = froxel_min.min(froxels[j]); + froxel_max = froxel_max.max(froxels[j]); + } } - kernel_size = max - min; + kernel_size = froxel_max - froxel_min; } else { // Volume type global runs on all cells extents = Vector3(fog->width, fog->height, fog->depth); - min = Vector3i(0, 0, 0); + froxel_min = Vector3i(0, 0, 0); kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->depth)); } @@ -695,15 +723,15 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P } VolumetricFogShader::FogPushConstant push_constant; - push_constant.position[0] = position.x; - push_constant.position[1] = position.y; - push_constant.position[2] = position.z; + push_constant.position[0] = fog_position.x; + push_constant.position[1] = fog_position.y; + push_constant.position[2] = fog_position.z; push_constant.size[0] = extents.x * 2; push_constant.size[1] = extents.y * 2; push_constant.size[2] = extents.z * 2; - push_constant.corner[0] = min.x; - push_constant.corner[1] = min.y; - push_constant.corner[2] = min.z; + push_constant.corner[0] = froxel_min.x; + push_constant.corner[1] = froxel_min.y; + push_constant.corner[2] = froxel_min.z; push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume)); RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform); diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 75b9c563f7..23de97a268 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -233,7 +233,7 @@ public: /* FOG VOLUMES */ - bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); }; + bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); } virtual RID fog_volume_allocate() override; virtual void fog_volume_initialize(RID p_rid) override; @@ -250,7 +250,7 @@ public: /* FOG VOLUMES INSTANCE */ - bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); }; + bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); } RID fog_volume_instance_create(RID p_fog_volume); void fog_instance_free(RID p_rid); diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 12ff28d7b0..235aa9f828 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -350,7 +350,7 @@ bool GI::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { bool GI::voxel_gi_is_interior(RID p_voxel_gi) const { VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); - ERR_FAIL_NULL_V(voxel_gi, 0); + ERR_FAIL_NULL_V(voxel_gi, false); return voxel_gi->interior; } diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index f6f9ab4f75..f34bbde6f0 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -467,7 +467,7 @@ public: /* VOXEL GI API */ - bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); }; + bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); } virtual RID voxel_gi_allocate() override; virtual void voxel_gi_free(RID p_voxel_gi) override; @@ -524,14 +524,14 @@ public: VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe); ERR_FAIL_NULL_V(voxel_gi, RID()); return voxel_gi->texture; - }; + } _FORCE_INLINE_ void voxel_gi_instance_set_render_index(RID p_probe, uint32_t p_index) { VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe); ERR_FAIL_NULL(voxel_gi); voxel_gi->render_index = p_index; - }; + } bool voxel_gi_instance_owns(RID p_rid) const { return voxel_gi_instance_owner.owns(p_rid); diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 2087989102..63956a7918 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -701,7 +701,7 @@ RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_func() { RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_funcs() { // !BAS! Why isn't _create_sky_shader_func not just static too? return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func(); -}; +} RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_func(SkyShaderData *p_shader) { SkyMaterialData *material_data = memnew(SkyMaterialData); @@ -713,7 +713,7 @@ RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_func(SkyS RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) { // !BAS! same here, we could just make _create_sky_material_func static? return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); -}; +} SkyRD::SkyRD() { roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 76d8972ad9..eb73a9d7e6 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -395,6 +395,10 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p RID xforms_uniform_set = surf->owner->transforms_uniform_set; SceneShaderForwardClustered::ShaderSpecialization pipeline_specialization = p_params->base_specialization; + pipeline_specialization.multimesh = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH); + pipeline_specialization.multimesh_format_2d = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D); + pipeline_specialization.multimesh_has_color = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR); + pipeline_specialization.multimesh_has_custom_data = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA); if constexpr (p_pass_mode == PASS_MODE_COLOR) { pipeline_specialization.use_light_soft_shadows = element_info.uses_softshadow; @@ -1961,7 +1965,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this); } else { - sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this); + Projection projection = p_render_data->scene_data->cam_projection; + if (p_render_data->scene_data->cam_frustum) { + // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip. + projection[2].y = -projection[2].y; + } + + sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this); } sky_energy_multiplier *= bg_energy_multiplier; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 53982af590..00a70e3690 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -374,6 +374,10 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; specialization_constants.push_back(sc); + sc.constant_id = 1; + sc.int_value = p_pipeline_key.shader_specialization.packed_1; + specialization_constants.push_back(sc); + RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.color_pass_flags, p_pipeline_key.ubershader); ERR_FAIL_COND(shader_rid.is_null()); @@ -610,6 +614,8 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["PI"] = _MKSTR(Math_PI); actions.renames["TAU"] = _MKSTR(Math_TAU); actions.renames["E"] = _MKSTR(Math_E); + actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; + actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR"; actions.renames["VIEWPORT_SIZE"] = "read_viewport_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; @@ -649,8 +655,6 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["CUSTOM1"] = "custom1_attrib"; actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; - actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR"; actions.renames["LIGHT_VERTEX"] = "light_vertex"; actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz"; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 136514588a..e1ed85779e 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -108,16 +108,26 @@ public: uint32_t projector_use_mipmaps : 1; uint32_t use_depth_fog : 1; uint32_t use_lightmap_bicubic_filter : 1; - uint32_t soft_shadow_samples : 4; - uint32_t penumbra_shadow_samples : 4; - uint32_t directional_soft_shadow_samples : 4; - uint32_t directional_penumbra_shadow_samples : 4; + uint32_t soft_shadow_samples : 6; + uint32_t penumbra_shadow_samples : 6; + uint32_t directional_soft_shadow_samples : 6; + uint32_t directional_penumbra_shadow_samples : 6; }; uint32_t packed_0; }; - uint32_t packed_1; + union { + struct { + uint32_t multimesh : 1; + uint32_t multimesh_format_2d : 1; + uint32_t multimesh_has_color : 1; + uint32_t multimesh_has_custom_data : 1; + }; + + uint32_t packed_1; + }; + uint32_t packed_2; }; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 978ce097d3..5ad92bd211 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -911,14 +911,19 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color Color clear_color = p_default_bg_color; bool load_color = false; bool copy_canvas = false; + bool use_ambient_cubemap = false; + bool use_reflection_cubemap = false; if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black } else if (is_environment(p_render_data->environment)) { + RS::EnvironmentAmbientSource ambient_source = environment_get_ambient_source(p_render_data->environment); RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment); float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment); bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment); RS::EnvironmentReflectionSource reflection_source = environment_get_reflection_source(p_render_data->environment); + use_ambient_cubemap = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY; + use_reflection_cubemap = (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY; if (p_render_data->camera_attributes.is_valid()) { bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); @@ -963,7 +968,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); @@ -976,7 +981,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this); } else { - sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this); + Projection projection = p_render_data->scene_data->cam_projection; + if (p_render_data->scene_data->cam_frustum) { + // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip. + projection[2].y = -projection[2].y; + } + + sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this); } sky_energy_multiplier *= bg_energy_multiplier; @@ -1008,13 +1019,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color SceneShaderForwardMobile::ShaderSpecialization base_specialization = scene_shader.default_specialization; { - //figure out spec constants - - if (p_render_data->directional_light_count > 0) { - base_specialization.use_directional_soft_shadows = p_render_data->directional_light_soft_shadows; - } else { - base_specialization.disable_directional_lights = true; - } + base_specialization.use_directional_soft_shadows = p_render_data->directional_light_count > 0 ? p_render_data->directional_light_soft_shadows : false; + base_specialization.directional_lights = p_render_data->directional_light_count; if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) { base_specialization.disable_fog = true; @@ -1023,6 +1029,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) { base_specialization.use_depth_fog = true; } + + base_specialization.scene_use_ambient_cubemap = use_ambient_cubemap; + base_specialization.scene_use_reflection_cubemap = use_reflection_cubemap; + base_specialization.scene_roughness_limiter_enabled = p_render_data->render_buffers.is_valid() && screen_space_roughness_limiter_is_active(); } { @@ -2144,7 +2154,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr } SceneShaderForwardMobile::ShaderSpecialization pipeline_specialization = p_params->base_specialization; - pipeline_specialization.is_multimesh = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH); + pipeline_specialization.multimesh = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH); + pipeline_specialization.multimesh_format_2d = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D); + pipeline_specialization.multimesh_has_color = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR); + pipeline_specialization.multimesh_has_custom_data = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA); SceneState::PushConstant push_constant; push_constant.base_index = i + p_params->element_offset; @@ -2165,10 +2178,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr } else { pipeline_specialization.use_light_projector = inst->use_projector; pipeline_specialization.use_light_soft_shadows = inst->use_soft_shadow; - pipeline_specialization.disable_omni_lights = inst->omni_light_count == 0; - pipeline_specialization.disable_spot_lights = inst->spot_light_count == 0; - pipeline_specialization.disable_reflection_probes = inst->reflection_probe_count == 0; - pipeline_specialization.disable_decals = inst->decals_count == 0; + pipeline_specialization.omni_lights = inst->omni_light_count; + pipeline_specialization.spot_lights = inst->spot_light_count; + pipeline_specialization.reflection_probes = inst->reflection_probe_count; + pipeline_specialization.decals = inst->decals_count; #ifdef DEBUG_ENABLED if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) { diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 69f084f4c0..4525b50b6e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -237,6 +237,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli "VERSION:", p_pipeline_key.version, "SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0, "SPEC PACKED #1:", p_pipeline_key.shader_specialization.packed_1, + "SPEC PACKED #2:", p_pipeline_key.shader_specialization.packed_2, "RENDER PASS:", p_pipeline_key.render_pass, "WIREFRAME:", p_pipeline_key.wireframe); #endif @@ -322,7 +323,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli specialization_constants.push_back(sc); sc.constant_id = 1; - sc.float_value = p_pipeline_key.shader_specialization.packed_1; + sc.int_value = p_pipeline_key.shader_specialization.packed_1; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + specialization_constants.push_back(sc); + + sc.constant_id = 2; + sc.float_value = p_pipeline_key.shader_specialization.packed_2; sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; specialization_constants.push_back(sc); @@ -521,6 +527,8 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["PI"] = _MKSTR(Math_PI); actions.renames["TAU"] = _MKSTR(Math_TAU); actions.renames["E"] = _MKSTR(Math_E); + actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; + actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR"; actions.renames["VIEWPORT_SIZE"] = "read_viewport_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; @@ -560,8 +568,6 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["CUSTOM1"] = "custom1_attrib"; actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; - actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR"; actions.renames["LIGHT_VERTEX"] = "light_vertex"; actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index c1095d29dc..f0afeebe79 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -65,31 +65,42 @@ public: uint32_t use_directional_soft_shadows : 1; uint32_t decal_use_mipmaps : 1; uint32_t projector_use_mipmaps : 1; - uint32_t disable_omni_lights : 1; - uint32_t disable_spot_lights : 1; - uint32_t disable_reflection_probes : 1; - uint32_t disable_directional_lights : 1; - uint32_t disable_decals : 1; uint32_t disable_fog : 1; uint32_t use_depth_fog : 1; - uint32_t is_multimesh : 1; uint32_t use_lightmap_bicubic_filter : 1; - uint32_t pad : 2; - uint32_t soft_shadow_samples : 4; - uint32_t penumbra_shadow_samples : 4; - uint32_t directional_soft_shadow_samples : 4; - uint32_t directional_penumbra_shadow_samples : 4; + uint32_t multimesh : 1; + uint32_t multimesh_format_2d : 1; + uint32_t multimesh_has_color : 1; + uint32_t multimesh_has_custom_data : 1; + uint32_t scene_use_ambient_cubemap : 1; + uint32_t scene_use_reflection_cubemap : 1; + uint32_t scene_roughness_limiter_enabled : 1; + uint32_t padding : 5; + uint32_t soft_shadow_samples : 6; + uint32_t penumbra_shadow_samples : 6; }; uint32_t packed_0; }; union { - float luminance_multiplier; - float packed_1; + struct { + uint32_t directional_soft_shadow_samples : 6; + uint32_t directional_penumbra_shadow_samples : 6; + uint32_t omni_lights : 4; + uint32_t spot_lights : 4; + uint32_t reflection_probes : 4; + uint32_t directional_lights : 4; + uint32_t decals : 4; + }; + + uint32_t packed_1; }; - uint32_t packed_2; + union { + float luminance_multiplier; + float packed_2; + }; }; struct UbershaderConstants { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 979f590c4c..0dcdb90948 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -911,7 +911,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p RenderingServerDefault::redraw_request(); } - state.current_data_buffer_index = (state.current_data_buffer_index + 1) % state.canvas_instance_data_buffers.size(); + state.current_data_buffer_index = (state.current_data_buffer_index + 1) % BATCH_DATA_BUFFER_COUNT; state.current_instance_buffer_index = 0; } @@ -993,36 +993,43 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, Vector<Color> cc; cc.push_back(Color(p_far, p_far, p_far, 1.0)); - for (int i = 0; i < 4; i++) { - //make sure it remains orthogonal, makes easy to read angle later + Projection projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; - Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } - Projection projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; + // Precomputed: + // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); + const Projection projections[4] = { + projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; + projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } + projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), + + projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)) + + }; - Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + for (int i = 0; i < 4; i++) { + Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); ShadowRenderPushConstant push_constant; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { - push_constant.projection[y * 4 + x] = projection.columns[y][x]; + push_constant.projection[y * 4 + x] = projections[i].columns[y][x]; } } static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; @@ -1647,6 +1654,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { default_samplers.default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; } + // preallocate 5 slots for uniform set 3 + state.batch_texture_uniforms.resize(5); + { //shader variants String global_defines; @@ -1974,15 +1984,18 @@ void fragment() { } { + uint32_t cache_size = uint32_t(GLOBAL_GET("rendering/2d/batching/uniform_set_cache_size")); + rid_set_to_uniform_set.set_capacity(cache_size); + } + + { state.max_instances_per_buffer = uint32_t(GLOBAL_GET("rendering/2d/batching/item_buffer_size")); state.max_instance_buffer_size = state.max_instances_per_buffer * sizeof(InstanceData); - state.canvas_instance_data_buffers.resize(3); state.canvas_instance_batches.reserve(200); - for (int i = 0; i < 3; i++) { - DataBuffer db; + for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) { + DataBuffer &db = state.canvas_instance_data_buffers[i]; db.instance_buffers.push_back(RD::get_singleton()->storage_buffer_create(state.max_instance_buffer_size)); - state.canvas_instance_data_buffers[i] = db; } state.instance_data_array = memnew_arr(InstanceData, state.max_instances_per_buffer); } @@ -2159,7 +2172,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors, 1, 0, Rect2(), RDD::BreadcrumbMarker::UI_PASS); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); @@ -2203,14 +2216,47 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target RD::get_singleton()->draw_list_end(); + texture_info_map.clear(); state.current_batch_index = 0; state.canvas_instance_batches.clear(); state.last_instance_index += instance_index; } +RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info) { + InstanceData *instance_data = &state.instance_data_array[p_index]; + // Zero out most fields. + for (int i = 0; i < 4; i++) { + instance_data->modulation[i] = 0.0; + instance_data->ninepatch_margins[i] = 0.0; + instance_data->src_rect[i] = 0.0; + instance_data->dst_rect[i] = 0.0; + } + + instance_data->pad[0] = 0.0; + instance_data->pad[1] = 0.0; + + instance_data->lights[0] = p_lights[0]; + instance_data->lights[1] = p_lights[1]; + instance_data->lights[2] = p_lights[2]; + instance_data->lights[3] = p_lights[3]; + + for (int i = 0; i < 6; i++) { + instance_data->world[i] = p_world[i]; + } + + instance_data->flags = p_base_flags | p_info->flags; // Reset on each command for safety, keep canvas texture binding config. + + instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width; + instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height; + + instance_data->pad1 = 0; + + return instance_data; +} + void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch) { - RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter; - RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat; + const RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter; + const RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat; Transform2D base_transform = p_base_transform; @@ -2241,7 +2287,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar light_count++; - if (light_count == state.max_lights_per_item - 1) { + if (light_count == MAX_LIGHTS_PER_ITEM - 1) { break; } } @@ -2258,38 +2304,6 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->use_lighting = use_lighting; } - // new_instance_data should be called after the current_batch is set. - auto new_instance_data = [&]() -> InstanceData * { - InstanceData *instance_data = &state.instance_data_array[r_index]; - // Zero out most fields. - for (int i = 0; i < 4; i++) { - instance_data->modulation[i] = 0.0; - instance_data->ninepatch_margins[i] = 0.0; - instance_data->src_rect[i] = 0.0; - instance_data->dst_rect[i] = 0.0; - } - - instance_data->pad[0] = 0.0; - instance_data->pad[1] = 0.0; - - instance_data->lights[0] = lights[0]; - instance_data->lights[1] = lights[1]; - instance_data->lights[2] = lights[2]; - instance_data->lights[3] = lights[3]; - - for (int i = 0; i < 6; i++) { - instance_data->world[i] = world[i]; - } - - instance_data->flags = base_flags | r_current_batch->tex_info.flags; // Reset on each command for safety, keep canvas texture binding config. - - instance_data->color_texture_pixel_size[0] = r_current_batch->tex_info.texpixel_size.width; - instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height; - instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess; - - return instance_data; - }; - const Item::Command *c = p_item->commands; while (c) { if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) { @@ -2311,17 +2325,9 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; } + RenderingServer::CanvasItemTextureRepeat rect_repeat = texture_repeat; if (bool(rect->flags & CANVAS_RECT_TILE)) { - texture_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; - } - - bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF); - TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors); - - if (tex_state != r_current_batch->tex_info.state) { - r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, rect->texture); + rect_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; } Color modulated = rect->modulate * base_color; @@ -2340,12 +2346,25 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; } - InstanceData *instance_data = new_instance_data(); + bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF); + TextureState tex_state(rect->texture, texture_filter, rect_repeat, has_msdf, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(rect->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Rect2 src_rect; Rect2 dst_rect; if (rect->texture.is_valid()) { - src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_info.texpixel_size, rect->source.size * r_current_batch->tex_info.texpixel_size) : Rect2(0, 0, 1, 1); + src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * tex_info->texpixel_size, rect->source.size * tex_info->texpixel_size) : Rect2(0, 0, 1, 1); dst_rect = Rect2(rect->rect.position, rect->rect.size); if (dst_rect.size.width < 0) { @@ -2431,13 +2450,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar } TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(np->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, np->texture); + r_current_batch->tex_info = tex_info; } - InstanceData *instance_data = new_instance_data(); + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Rect2 src_rect; Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); @@ -2446,7 +2470,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar src_rect = Rect2(0, 0, 1, 1); } else { if (np->source != Rect2()) { - src_rect = Rect2(np->source.position.x * r_current_batch->tex_info.texpixel_size.width, np->source.position.y * r_current_batch->tex_info.texpixel_size.height, np->source.size.x * r_current_batch->tex_info.texpixel_size.width, np->source.size.y * r_current_batch->tex_info.texpixel_size.height); + src_rect = Rect2(np->source.position.x * tex_info->texpixel_size.width, np->source.position.y * tex_info->texpixel_size.height, np->source.size.x * tex_info->texpixel_size.width, np->source.size.y * tex_info->texpixel_size.height); instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width; instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height; } else { @@ -2500,10 +2524,15 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->command = c; TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(polygon->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, polygon->texture); + r_current_batch->tex_info = tex_info; } // pipeline variant @@ -2513,7 +2542,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->render_primitive = _primitive_type_to_render_primitive(polygon->primitive); } - InstanceData *instance_data = new_instance_data(); + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); Color color = base_color; if (use_linear_colors) { @@ -2557,17 +2586,22 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar default: // Unknown point count. break; - }; - - TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_info.state) { - r_current_batch = _new_batch(r_batch_broken); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, primitive->texture); } } - InstanceData *instance_data = new_instance_data(); + TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(primitive->texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) { instance_data->points[j * 2 + 0] = primitive->points[j].x; @@ -2585,7 +2619,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar _add_to_batch(r_index, r_batch_broken, r_current_batch); if (primitive->point_count == 4) { - instance_data = new_instance_data(); + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); for (uint32_t j = 0; j < 3; j++) { int offset = j == 0 ? 0 : 1; @@ -2594,7 +2628,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar instance_data->points[j * 2 + 1] = primitive->points[j + offset].y; instance_data->uvs[j * 2 + 0] = primitive->uvs[j + offset].x; instance_data->uvs[j * 2 + 1] = primitive->uvs[j + offset].y; - Color col = primitive->colors[j] * base_color; + Color col = primitive->colors[j + offset] * base_color; if (use_linear_colors) { col = col.srgb_to_linear(); } @@ -2621,9 +2655,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar if (c->type == Item::Command::TYPE_MESH) { const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c); TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, m->texture); - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(m->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); r_current_batch->mesh_instance_count = 1; _update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, instance_data->world); @@ -2644,9 +2682,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar } TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, mm->texture); - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(mm->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); instance_data->flags |= 1; // multimesh, trails disabled @@ -2662,10 +2704,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c); TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->tex_info.state = tex_state; - _prepare_batch_texture_info(r_current_batch, pt->texture); - - instance_data = new_instance_data(); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(pt->texture, tex_state, tex_info); + } + r_current_batch->tex_info = tex_info; + instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); uint32_t divisor = 1; r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor); @@ -2747,36 +2792,137 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_batch_broken = false; } +#ifdef DEBUG_ENABLED + if (debug_redraw && p_item->debug_redraw_time > 0.0) { + Color dc = debug_redraw_color; + dc.a *= p_item->debug_redraw_time / debug_redraw_time; + + // 1: If commands are different, start a new batch. + if (r_current_batch->command_type != Item::Command::TYPE_RECT) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->command_type = Item::Command::TYPE_RECT; + // it is ok to be null for a TYPE_RECT + r_current_batch->command = nullptr; + // default variant + r_current_batch->shader_variant = SHADER_VARIANT_QUAD; + r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES; + } + + // 2: If the current batch has lighting, start a new batch. + if (r_current_batch->use_lighting) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->use_lighting = false; + } + + // 3: If the current batch has blend, start a new batch. + if (r_current_batch->has_blend) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->has_blend = false; + } + + TextureState tex_state(default_canvas_texture, texture_filter, texture_repeat, false, use_linear_colors); + TextureInfo *tex_info = texture_info_map.getptr(tex_state); + if (!tex_info) { + tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value; + _prepare_batch_texture_info(default_canvas_texture, tex_state, tex_info); + } + + if (r_current_batch->tex_info != tex_info) { + r_current_batch = _new_batch(r_batch_broken); + r_current_batch->tex_info = tex_info; + } + + InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info); + + Rect2 src_rect; + Rect2 dst_rect; + + dst_rect = Rect2(Vector2(), p_item->rect.size); + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + src_rect = Rect2(0, 0, 1, 1); + + instance_data->modulation[0] = dc.r; + instance_data->modulation[1] = dc.g; + instance_data->modulation[2] = dc.b; + instance_data->modulation[3] = dc.a; + + instance_data->src_rect[0] = src_rect.position.x; + instance_data->src_rect[1] = src_rect.position.y; + instance_data->src_rect[2] = src_rect.size.width; + instance_data->src_rect[3] = src_rect.size.height; + + instance_data->dst_rect[0] = dst_rect.position.x; + instance_data->dst_rect[1] = dst_rect.position.y; + instance_data->dst_rect[2] = dst_rect.size.width; + instance_data->dst_rect[3] = dst_rect.size.height; + + _add_to_batch(r_index, r_batch_broken, r_current_batch); + + p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time(); + + RenderingServerDefault::redraw_request(); + + r_batch_broken = false; + } +#endif + if (r_current_clip && reclip) { // will make it re-enable clipping if needed afterwards r_current_clip = nullptr; } } -void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) { - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); - ERR_FAIL_NULL(uniform_set_cache); +void RendererCanvasRenderRD::_before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid) { + RD::get_singleton()->uniform_set_set_invalidation_callback(p_rid, nullptr, nullptr); + RD::get_singleton()->free(p_rid); +} - ERR_FAIL_NULL(p_batch->command); +void RendererCanvasRenderRD::_uniform_set_invalidation_callback(void *p_userdata) { + const RIDSetKey *key = static_cast<RIDSetKey *>(p_userdata); + static_cast<RendererCanvasRenderRD *>(singleton)->rid_set_to_uniform_set.erase(*key); +} +void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) { { - RD::Uniform u_diffuse(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info.diffuse); - RD::Uniform u_normal(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info.normal); - RD::Uniform u_specular(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info.specular); - RD::Uniform u_sampler(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info.sampler); - RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); - - RID uniform_set = uniform_set_cache->get_cache(shader.default_version_rd_shader, BATCH_UNIFORM_SET, u_diffuse, u_normal, u_specular, u_sampler, u_instance_data); + RIDSetKey key( + p_batch->tex_info->state, + state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); + + const RID *uniform_set = rid_set_to_uniform_set.getptr(key); + if (uniform_set == nullptr) { + state.batch_texture_uniforms.write[0] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info->diffuse); + state.batch_texture_uniforms.write[1] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info->normal); + state.batch_texture_uniforms.write[2] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info->specular); + state.batch_texture_uniforms.write[3] = RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info->sampler); + state.batch_texture_uniforms.write[4] = RD::Uniform(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); + + RID rid = RD::get_singleton()->uniform_set_create(state.batch_texture_uniforms, shader.default_version_rd_shader, BATCH_UNIFORM_SET); + ERR_FAIL_COND_MSG(rid.is_null(), "Failed to create uniform set for batch."); + + const RIDCache::Pair *iter = rid_set_to_uniform_set.insert(key, rid); + uniform_set = &iter->data; + RD::get_singleton()->uniform_set_set_invalidation_callback(rid, RendererCanvasRenderRD::_uniform_set_invalidation_callback, (void *)&iter->key); + } - if (state.current_batch_uniform_set != uniform_set) { - state.current_batch_uniform_set = uniform_set; - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, BATCH_UNIFORM_SET); + if (state.current_batch_uniform_set != *uniform_set) { + state.current_batch_uniform_set = *uniform_set; + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, *uniform_set, BATCH_UNIFORM_SET); } } + PushConstant push_constant; + push_constant.base_instance_index = p_batch->start; + push_constant.specular_shininess = p_batch->tex_info->specular_shininess; RID pipeline; PipelineKey pipeline_key; - PushConstant push_constant; pipeline_key.framebuffer_format_id = p_framebuffer_format; pipeline_key.variant = p_batch->shader_variant; pipeline_key.render_primitive = p_batch->render_primitive; @@ -2792,7 +2938,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, p_batch->modulate); } - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count); @@ -2805,6 +2950,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha } break; case Item::Command::TYPE_POLYGON: { + ERR_FAIL_NULL(p_batch->command); + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(p_batch->command); PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id); @@ -2814,7 +2961,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array); if (pb->indices.is_valid()) { @@ -2830,12 +2976,13 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha } break; case Item::Command::TYPE_PRIMITIVE: { + ERR_FAIL_NULL(p_batch->command); + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(p_batch->command); pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]); uint32_t instance_count = p_batch->instance_count; @@ -2852,6 +2999,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha case Item::Command::TYPE_MESH: case Item::Command::TYPE_MULTIMESH: case Item::Command::TYPE_PARTICLES: { + ERR_FAIL_NULL(p_batch->command); + RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton(); @@ -2912,7 +3061,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant, mesh_instance, surface, j, &vertex_array); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RID index_array = mesh_storage->mesh_surface_get_index_array(surface, 0); @@ -2994,7 +3142,7 @@ void RendererCanvasRenderRD::_allocate_instance_buffer() { state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(buf); } -void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const { +void RendererCanvasRenderRD::_prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info) { if (p_texture.is_null()) { p_texture = default_canvas_texture; } @@ -3002,38 +3150,38 @@ void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RendererRD::TextureStorage::CanvasTextureInfo info = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info( p_texture, - p_current_batch->tex_info.state.texture_filter(), - p_current_batch->tex_info.state.texture_repeat(), - p_current_batch->tex_info.state.linear_colors(), - p_current_batch->tex_info.state.texture_is_data()); - + p_state.texture_filter(), + p_state.texture_repeat(), + p_state.linear_colors(), + p_state.texture_is_data()); // something odd happened if (info.is_null()) { - _prepare_batch_texture_info(p_current_batch, default_canvas_texture); + _prepare_batch_texture_info(default_canvas_texture, p_state, p_info); return; } - p_current_batch->tex_info.diffuse = info.diffuse; - p_current_batch->tex_info.normal = info.normal; - p_current_batch->tex_info.specular = info.specular; - p_current_batch->tex_info.sampler = info.sampler; + p_info->state = p_state; + p_info->diffuse = info.diffuse; + p_info->normal = info.normal; + p_info->specular = info.specular; + p_info->sampler = info.sampler; // cache values to be copied to instance data if (info.specular_color.a < 0.999) { - p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + p_info->flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; } if (info.use_normal) { - p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; + p_info->flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; } uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0)); uint8_t b = uint8_t(CLAMP(info.specular_color.b * 255.0, 0.0, 255.0)); uint8_t g = uint8_t(CLAMP(info.specular_color.g * 255.0, 0.0, 255.0)); uint8_t r = uint8_t(CLAMP(info.specular_color.r * 255.0, 0.0, 255.0)); - p_current_batch->tex_info.specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r); + p_info->specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r); - p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height)); + p_info->texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height)); } RendererCanvasRenderRD::~RendererCanvasRenderRD() { @@ -3075,7 +3223,7 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() { RD::get_singleton()->free(state.shadow_texture); memdelete_arr(state.instance_data_array); - for (uint32_t i = 0; i < state.canvas_instance_data_buffers.size(); i++) { + for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) { for (uint32_t j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) { RD::get_singleton()->free(state.canvas_instance_data_buffers[i].instance_buffers[j]); } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 07445b5c53..1bdc5076c5 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -31,6 +31,7 @@ #ifndef RENDERER_CANVAS_RENDER_RD_H #define RENDERER_CANVAS_RENDER_RD_H +#include "core/templates/lru.h" #include "servers/rendering/renderer_canvas_render.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" @@ -50,6 +51,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { }; const int SAMPLERS_BINDING_FIRST_INDEX = 10; + // The size of the ring buffer to store GPU buffers. Triple-buffering the max expected frames in flight. + static const uint32_t BATCH_DATA_BUFFER_COUNT = 3; enum ShaderVariant { SHADER_VARIANT_QUAD, @@ -339,7 +342,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct InstanceData { float world[6]; uint32_t flags; - uint32_t specular_shininess; + uint32_t pad1; union { //rect struct { @@ -366,8 +369,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct PushConstant { uint32_t base_instance_index; ShaderSpecialization shader_specialization; - uint32_t pad2; - uint32_t pad3; + uint32_t specular_shininess; + uint32_t pad; }; // TextureState is used to determine when a new batch is required due to a change of texture state. @@ -398,50 +401,91 @@ class RendererCanvasRenderRD : public RendererCanvasRender { (((uint32_t)p_use_linear_colors & LINEAR_COLORS_MASK) << LINEAR_COLORS_SHIFT); } - _FORCE_INLINE_ RS::CanvasItemTextureFilter texture_filter() const { + _ALWAYS_INLINE_ RS::CanvasItemTextureFilter texture_filter() const { return (RS::CanvasItemTextureFilter)((other >> FILTER_SHIFT) & FILTER_MASK); } - _FORCE_INLINE_ RS::CanvasItemTextureRepeat texture_repeat() const { + _ALWAYS_INLINE_ RS::CanvasItemTextureRepeat texture_repeat() const { return (RS::CanvasItemTextureRepeat)((other >> REPEAT_SHIFT) & REPEAT_MASK); } - _FORCE_INLINE_ bool linear_colors() const { + _ALWAYS_INLINE_ bool linear_colors() const { return (other >> LINEAR_COLORS_SHIFT) & LINEAR_COLORS_MASK; } - _FORCE_INLINE_ bool texture_is_data() const { + _ALWAYS_INLINE_ bool texture_is_data() const { return (other >> TEXTURE_IS_DATA_SHIFT) & TEXTURE_IS_DATA_MASK; } - bool operator==(const TextureState &p_val) const { + _ALWAYS_INLINE_ bool operator==(const TextureState &p_val) const { return (texture == p_val.texture) && (other == p_val.other); } - bool operator!=(const TextureState &p_val) const { + _ALWAYS_INLINE_ bool operator!=(const TextureState &p_val) const { return (texture != p_val.texture) || (other != p_val.other); } + + _ALWAYS_INLINE_ bool is_valid() const { return texture.is_valid(); } + _ALWAYS_INLINE_ bool is_null() const { return texture.is_null(); } + + uint32_t hash() const { + uint32_t hash = hash_murmur3_one_64(texture.get_id()); + return hash_murmur3_one_32(other, hash); + } }; struct TextureInfo { TextureState state; - uint32_t specular_shininess = 0; - uint32_t flags = 0; - Vector2 texpixel_size; - RID diffuse; RID normal; RID specular; RID sampler; + Vector2 texpixel_size; + uint32_t specular_shininess = 0; + uint32_t flags = 0; + }; + + /// A key used to uniquely identify a distinct BATCH_UNIFORM_SET + struct RIDSetKey { + TextureState state; + RID instance_data; + + RIDSetKey() { + } + + RIDSetKey(TextureState p_state, RID p_instance_data) : + state(p_state), + instance_data(p_instance_data) { + } + + _ALWAYS_INLINE_ bool operator==(const RIDSetKey &p_val) const { + return state == p_val.state && instance_data == p_val.instance_data; + } + + _ALWAYS_INLINE_ bool operator!=(const RIDSetKey &p_val) const { + return !(*this == p_val); + } + + _ALWAYS_INLINE_ uint32_t hash() const { + uint32_t h = state.hash(); + h = hash_murmur3_one_64(instance_data.get_id(), h); + return hash_fmix32(h); + } }; + static void _before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid); + static void _uniform_set_invalidation_callback(void *p_userdata); + + typedef LRUCache<RIDSetKey, RID, HashableHasher<RIDSetKey>, HashMapComparatorDefault<RIDSetKey>, _before_evict> RIDCache; + RIDCache rid_set_to_uniform_set; + struct Batch { // Position in the UBO measured in bytes uint32_t start = 0; uint32_t instance_count = 0; uint32_t instance_buffer_index = 0; - TextureInfo tex_info; + TextureInfo *tex_info; Color modulate = Color(1.0, 1.0, 1.0, 1.0); @@ -466,6 +510,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender { bool has_blend = false; }; + HashMap<TextureState, TextureInfo, HashableHasher<TextureState>> texture_info_map; + + // per-frame buffers struct DataBuffer { LocalVector<RID> instance_buffers; }; @@ -492,7 +539,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t pad2; }; - LocalVector<DataBuffer> canvas_instance_data_buffers; + DataBuffer canvas_instance_data_buffers[BATCH_DATA_BUFFER_COUNT]; LocalVector<Batch> canvas_instance_batches; uint32_t current_data_buffer_index = 0; uint32_t current_instance_buffer_index = 0; @@ -503,6 +550,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t max_instances_per_buffer = 16384; uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData); + Vector<RD::Uniform> batch_texture_uniforms; RID current_batch_uniform_set; LightUniform *light_uniforms = nullptr; @@ -518,7 +566,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID default_transforms_uniform_set; uint32_t max_lights_per_render; - uint32_t max_lights_per_item; double time; @@ -558,7 +605,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr); void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch); void _render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr); - void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const; + void _prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info); + InstanceData *new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info); [[nodiscard]] Batch *_new_batch(bool &r_batch_broken); void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch); void _allocate_instance_buffer(); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 84ea6a5da2..ba47508700 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -66,6 +66,16 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); + // We need to invert the phone rotation. + const int screen_rotation_degrees = -RD::get_singleton()->screen_get_pre_rotation_degrees(p_screen); + float screen_rotation = Math::deg_to_rad((float)screen_rotation_degrees); + + blit.push_constant.rotation_cos = Math::cos(screen_rotation); + blit.push_constant.rotation_sin = Math::sin(screen_rotation); + // Swap width and height when the orientation is not the native one. + if (screen_rotation_degrees % 180 != 0) { + SWAP(screen_size.width, screen_size.height); + } blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x; blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y; blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width; @@ -228,6 +238,10 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0); + const int screen_rotation_degrees = -RD::get_singleton()->screen_get_pre_rotation_degrees(DisplayServer::MAIN_WINDOW_ID); + float screen_rotation = Math::deg_to_rad((float)screen_rotation_degrees); + blit.push_constant.rotation_cos = Math::cos(screen_rotation); + blit.push_constant.rotation_sin = Math::sin(screen_rotation); blit.push_constant.src_rect[0] = 0.0; blit.push_constant.src_rect[1] = 0.0; blit.push_constant.src_rect[2] = 1.0; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 2547f08715..6821fa737e 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -74,6 +74,10 @@ protected: float src_rect[4]; float dst_rect[4]; + float rotation_sin; + float rotation_cos; + float pad[2]; + float eye_center[2]; float k1; float k2; @@ -103,7 +107,7 @@ protected: static RendererCompositorRD *singleton; public: - RendererUtilities *get_utilities() { return utilities; }; + RendererUtilities *get_utilities() { return utilities; } RendererLightStorage *get_light_storage() { return light_storage; } RendererMaterialStorage *get_material_storage() { return material_storage; } RendererMeshStorage *get_mesh_storage() { return mesh_storage; } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index dc2605b670..4417f6832c 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1130,6 +1130,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render scene_data.cam_transform = p_camera_data->main_transform; scene_data.cam_projection = p_camera_data->main_projection; scene_data.cam_orthogonal = p_camera_data->is_orthogonal; + scene_data.cam_frustum = p_camera_data->is_frustum; scene_data.camera_visible_layers = p_camera_data->visible_layers; scene_data.taa_jitter = p_camera_data->taa_jitter; scene_data.taa_frame_count = p_camera_data->taa_frame_count; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index b82d50378e..631ad21247 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -78,7 +78,7 @@ protected: //////////////////////////////// - virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); }; + virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); } void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers); diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl index d451647bec..fe6416f03c 100644 --- a/servers/rendering/renderer_rd/shaders/blit.glsl +++ b/servers/rendering/renderer_rd/shaders/blit.glsl @@ -8,6 +8,10 @@ layout(push_constant, std140) uniform Pos { vec4 src_rect; vec4 dst_rect; + float rotation_sin; + float rotation_cos; + vec2 pad; + vec2 eye_center; float k1; float k2; @@ -15,17 +19,23 @@ layout(push_constant, std140) uniform Pos { float upscale; float aspect_ratio; uint layer; - uint pad1; + bool convert_to_srgb; } data; layout(location = 0) out vec2 uv; void main() { + mat4 swapchain_transform = mat4(1.0); + swapchain_transform[0][0] = data.rotation_cos; + swapchain_transform[0][1] = -data.rotation_sin; + swapchain_transform[1][0] = data.rotation_sin; + swapchain_transform[1][1] = data.rotation_cos; + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw; vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw; - gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0); + gl_Position = swapchain_transform * vec4(vtx * 2.0 - 1.0, 0.0, 1.0); } #[fragment] @@ -38,6 +48,10 @@ layout(push_constant, std140) uniform Pos { vec4 src_rect; vec4 dst_rect; + float rotation_sin; + float rotation_cos; + vec2 pad; + vec2 eye_center; float k1; float k2; diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index dafcce37ad..f665bc24a4 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -28,7 +28,7 @@ layout(location = 11) in vec4 weight_attrib; layout(location = 4) out flat uint instance_index_interp; -#endif // USE_ATTRIBUTES +#endif // !USE_ATTRIBUTES layout(location = 0) out vec2 uv_interp; layout(location = 1) out vec4 color_interp; @@ -322,11 +322,7 @@ vec4 light_compute( #ifdef USE_NINEPATCH float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) { -#ifdef USE_ATTRIBUTES - const InstanceData draw_data = instances.data[params.base_instance_index]; -#else const InstanceData draw_data = instances.data[instance_index]; -#endif // USE_ATTRIBUTES float tex_size = 1.0 / tex_pixel_size; @@ -567,7 +563,7 @@ void main() { if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv); - specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess); + specular_shininess *= unpackUnorm4x8(params.specular_shininess); specular_shininess_used = true; } else { specular_shininess = vec4(1.0); diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index ead8c459a4..84017a1fe1 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -37,7 +37,7 @@ struct InstanceData { vec2 world_y; vec2 world_ofs; uint flags; - uint specular_shininess; + uint pad2; #ifdef USE_PRIMITIVE vec2 points[3]; vec2 uvs[3]; @@ -57,8 +57,8 @@ struct InstanceData { layout(push_constant, std430) uniform Params { uint base_instance_index; // base index to instance data uint sc_packed_0; - uint pad2; - uint pad3; + uint specular_shininess; + uint pad; } params; @@ -68,7 +68,7 @@ params; // Pull the constants from the draw call's push constants. uint sc_packed_0() { - return draw_call.sc_packed_0; + return params.sc_packed_0; } #else diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl index 3fb93dda35..b45e310b61 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl @@ -8,7 +8,6 @@ layout(push_constant, std430) uniform Params { float z_far; float z_near; vec2 texel_size; - vec4 screen_rect; } params; @@ -17,8 +16,7 @@ layout(location = 0) out vec2 uv_interp; void main() { vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); uv_interp = base_arr[gl_VertexIndex]; - vec2 screen_pos = uv_interp * params.screen_rect.zw + params.screen_rect.xy; - gl_Position = vec4(screen_pos * 2.0 - 1.0, 0.0, 1.0); + gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); } #[fragment] @@ -35,7 +33,6 @@ layout(push_constant, std430) uniform Params { float z_far; float z_near; vec2 texel_size; - vec4 screen_rect; } params; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 72236dcd9f..81d3d87a22 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -211,6 +211,13 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec } #endif +uint multimesh_stride() { + uint stride = sc_multimesh_format_2d() ? 2 : 3; + stride += sc_multimesh_has_color() ? 1 : 0; + stride += sc_multimesh_has_custom_data() ? 1 : 0; + return stride; +} + void vertex_shader(vec3 vertex_input, #ifdef NORMAL_USED in vec3 normal_input, @@ -219,7 +226,7 @@ void vertex_shader(vec3 vertex_input, in vec3 tangent_input, in vec3 binormal_input, #endif - in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) { + in uint instance_index, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) { vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) color_interp = color_attrib; @@ -248,7 +255,7 @@ void vertex_shader(vec3 vertex_input, mat4 matrix; mat4 read_model_matrix = model_matrix; - if (is_multimesh) { + if (sc_multimesh()) { //multimesh, instances are for it #ifdef USE_PARTICLE_TRAILS @@ -296,25 +303,10 @@ void vertex_shader(vec3 vertex_input, #endif #else - uint stride = 0; - { - //TODO implement a small lookup table for the stride - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { - stride += 2; - } else { - stride += 3; - } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { - stride += 1; - } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { - stride += 1; - } - } - + uint stride = multimesh_stride(); uint offset = stride * (gl_InstanceIndex + multimesh_offset); - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (sc_multimesh_format_2d()) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); offset += 2; } else { @@ -322,14 +314,14 @@ void vertex_shader(vec3 vertex_input, offset += 3; } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (sc_multimesh_has_color()) { #ifdef COLOR_USED color_interp *= transforms.data[offset]; #endif offset += 1; } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + if (sc_multimesh_has_custom_data()) { instance_custom = transforms.data[offset]; } @@ -427,7 +419,7 @@ void vertex_shader(vec3 vertex_input, // Then we combine the translations from the model matrix and the view matrix using emulated doubles. // We add the result to the vertex and ignore the final lost precision. vec3 model_origin = model_matrix[3].xyz; - if (is_multimesh) { + if (sc_multimesh()) { vertex = mat3(matrix) * vertex; model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision); } @@ -708,9 +700,7 @@ void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position void main() { uint instance_index = draw_call.instance_index; - - bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH); - if (!is_multimesh) { + if (!sc_multimesh()) { instance_index += gl_InstanceIndex; } @@ -753,7 +743,7 @@ void main() { prev_tangent, prev_binormal, #endif - instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position); + instance_index, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position); #else // Unused output. vec4 screen_position; @@ -792,7 +782,7 @@ void main() { tangent, binormal, #endif - instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position); + instance_index, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position); } #[fragment] diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index 9f68d59be2..8f153f7ed5 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -59,6 +59,10 @@ uint sc_packed_0() { return draw_call.sc_packed_0; } +uint sc_packed_1() { + return draw_call.sc_packed_1; +} + uint uc_cull_mode() { return (draw_call.uc_packed_0 >> 0) & 3U; } @@ -67,11 +71,16 @@ uint uc_cull_mode() { // Pull the constants from the pipeline's specialization constants. layout(constant_id = 0) const uint pso_sc_packed_0 = 0; +layout(constant_id = 1) const uint pso_sc_packed_1 = 0; uint sc_packed_0() { return pso_sc_packed_0; } +uint sc_packed_1() { + return pso_sc_packed_1; +} + #endif bool sc_use_forward_gi() { @@ -107,19 +116,35 @@ bool sc_use_lightmap_bicubic_filter() { } uint sc_soft_shadow_samples() { - return (sc_packed_0() >> 8) & 15U; + return (sc_packed_0() >> 8) & 63U; } uint sc_penumbra_shadow_samples() { - return (sc_packed_0() >> 12) & 15U; + return (sc_packed_0() >> 14) & 63U; } uint sc_directional_soft_shadow_samples() { - return (sc_packed_0() >> 16) & 15U; + return (sc_packed_0() >> 20) & 63U; } uint sc_directional_penumbra_shadow_samples() { - return (sc_packed_0() >> 20) & 15U; + return (sc_packed_0() >> 26) & 63U; +} + +bool sc_multimesh() { + return ((sc_packed_1() >> 0) & 1U) != 0; +} + +bool sc_multimesh_format_2d() { + return ((sc_packed_1() >> 1) & 1U) != 0; +} + +bool sc_multimesh_has_color() { + return ((sc_packed_1() >> 2) & 1U) != 0; +} + +bool sc_multimesh_has_custom_data() { + return ((sc_packed_1() >> 3) & 1U) != 0; } float sc_luminance_multiplier() { @@ -144,10 +169,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; #define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9) #define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10) #define INSTANCE_FLAGS_PARTICLES (1 << 11) -#define INSTANCE_FLAGS_MULTIMESH (1 << 12) -#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) -#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) -#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) #define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16 #define INSTANCE_FLAGS_FADE_SHIFT 24 //3 bits of stride diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 2f0e4e0bea..404f658fa6 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -178,6 +178,13 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec } #endif +uint multimesh_stride() { + uint stride = sc_multimesh_format_2d() ? 2 : 3; + stride += sc_multimesh_has_color() ? 1 : 0; + stride += sc_multimesh_has_custom_data() ? 1 : 0; + return stride; +} + void main() { vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) @@ -208,7 +215,7 @@ void main() { mat4 matrix; mat4 read_model_matrix = model_matrix; - if (sc_is_multimesh()) { + if (sc_multimesh()) { //multimesh, instances are for it #ifdef USE_PARTICLE_TRAILS @@ -256,25 +263,10 @@ void main() { #endif #else - uint stride = 0; - { - //TODO implement a small lookup table for the stride - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { - stride += 2; - } else { - stride += 3; - } - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { - stride += 1; - } - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { - stride += 1; - } - } - + uint stride = multimesh_stride(); uint offset = stride * gl_InstanceIndex; - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (sc_multimesh_format_2d()) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); offset += 2; } else { @@ -282,14 +274,14 @@ void main() { offset += 3; } - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (sc_multimesh_has_color()) { #ifdef COLOR_USED color_interp *= transforms.data[offset]; #endif offset += 1; } - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + if (sc_multimesh_has_custom_data()) { instance_custom = transforms.data[offset]; } @@ -404,7 +396,7 @@ void main() { // Then we combine the translations from the model matrix and the view matrix using emulated doubles. // We add the result to the vertex and ignore the final lost precision. vec3 model_origin = model_matrix[3].xyz; - if (sc_is_multimesh()) { + if (sc_multimesh()) { vertex = mat3(matrix) * vertex; model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision); } @@ -461,50 +453,24 @@ void main() { diffuse_light_interp = vec4(0.0); specular_light_interp = vec4(0.0); - if (!sc_disable_omni_lights()) { - uint light_indices = instances.data[draw_call.instance_index].omni_lights.x; - for (uint i = 0; i < 8; i++) { - uint light_index = light_indices & 0xFF; - if (i == 3) { - light_indices = instances.data[draw_call.instance_index].omni_lights.y; - } else { - light_indices = light_indices >> 8; - } - - if (light_index == 0xFF) { - break; - } - - light_process_omni_vertex(light_index, vertex, view, normal, roughness, - diffuse_light_interp.rgb, specular_light_interp.rgb); - } + uvec2 omni_light_indices = instances.data[draw_call.instance_index].omni_lights; + for (uint i = 0; i < sc_omni_lights(); i++) { + uint light_index = (i > 3) ? ((omni_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_light_indices.x >> (i * 8)) & 0xFF); + light_process_omni_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb); } - if (!sc_disable_spot_lights()) { - uint light_indices = instances.data[draw_call.instance_index].spot_lights.x; - for (uint i = 0; i < 8; i++) { - uint light_index = light_indices & 0xFF; - if (i == 3) { - light_indices = instances.data[draw_call.instance_index].spot_lights.y; - } else { - light_indices = light_indices >> 8; - } - - if (light_index == 0xFF) { - break; - } - - light_process_spot_vertex(light_index, vertex, view, normal, roughness, - diffuse_light_interp.rgb, specular_light_interp.rgb); - } + uvec2 spot_light_indices = instances.data[draw_call.instance_index].spot_lights; + for (uint i = 0; i < sc_spot_lights(); i++) { + uint light_index = (i > 3) ? ((spot_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_light_indices.x >> (i * 8)) & 0xFF); + light_process_spot_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb); } - if (!sc_disable_directional_lights()) { + if (sc_directional_lights() > 0) { // We process the first directional light separately as it may have shadows. vec3 directional_diffuse = vec3(0.0); vec3 directional_specular = vec3(0.0); - for (uint i = 0; i < scene_data.directional_light_count; i++) { + for (uint i = 0; i < sc_directional_lights(); i++) { if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; // Not masked, skip. } @@ -823,7 +789,7 @@ vec4 fog_process(vec3 vertex) { float sun_total = 0.0; vec3 view = normalize(vertex); - for (uint i = 0; i < scene_data_block.data.directional_light_count; i++) { + for (uint i = 0; i < sc_directional_lights(); i++) { vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy; float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0); fog_color += light_color * light_amount * scene_data_block.data.fog_sun_scatter; @@ -1110,97 +1076,83 @@ void main() { vec3 vertex_ddx = dFdx(vertex); vec3 vertex_ddy = dFdy(vertex); - if (!sc_disable_decals()) { //Decals - // must implement - - uint decal_indices = instances.data[draw_call.instance_index].decals.x; - for (uint i = 0; i < 8; i++) { - uint decal_index = decal_indices & 0xFF; - if (i == 3) { - decal_indices = instances.data[draw_call.instance_index].decals.y; - } else { - decal_indices = decal_indices >> 8; - } + uvec2 decal_indices = instances.data[draw_call.instance_index].decals; + for (uint i = 0; i < sc_decals(); i++) { + uint decal_index = (i > 3) ? ((decal_indices.y >> ((i - 4) * 8)) & 0xFF) : ((decal_indices.x >> (i * 8)) & 0xFF); + if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) { + continue; //not masked + } - if (decal_index == 0xFF) { - break; - } + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal + } - if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) { - continue; //not masked - } + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); - vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; - if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { - continue; //out of decal - } + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + } - float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; - if (decals.data[decal_index].normal_fade > 0.0) { - fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo; + if (sc_decal_use_mipmaps()) { + decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + } else { + decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0); } + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); - //we need ddx/ddy for mipmaps, so simulate them - vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; - vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; - - if (decals.data[decal_index].albedo_rect != vec4(0.0)) { - //has albedo - vec4 decal_albedo; + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + vec3 decal_normal; if (sc_decal_use_mipmaps()) { - decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; } else { - decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0); - } - decal_albedo *= decals.data[decal_index].modulate; - decal_albedo.a *= fade; - albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); - - if (decals.data[decal_index].normal_rect != vec4(0.0)) { - vec3 decal_normal; - if (sc_decal_use_mipmaps()) { - decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; - } else { - decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz; - } - decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software - decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); - //convert to view space, use xzy because y is up - decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; - - normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz; } + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; - if (decals.data[decal_index].orm_rect != vec4(0.0)) { - vec3 decal_orm; - if (sc_decal_use_mipmaps()) { - decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; - } else { - decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz; - } - ao = mix(ao, decal_orm.r, decal_albedo.a); - roughness = mix(roughness, decal_orm.g, decal_albedo.a); - metallic = mix(metallic, decal_orm.b, decal_albedo.a); - } + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); } - if (decals.data[decal_index].emission_rect != vec4(0.0)) { - //emission is additive, so its independent from albedo + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + vec3 decal_orm; if (sc_decal_use_mipmaps()) { - emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; } else { - emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade; + decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz; } + ao = mix(ao, decal_orm.r, decal_albedo.a); + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + if (sc_decal_use_mipmaps()) { + emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } else { + emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade; } } - } //Decals + } #endif //!MODE_RENDER_DEPTH /////////////////////// LIGHTING ////////////////////////////// #ifdef NORMAL_USED - if (scene_data.roughness_limiter_enabled) { + if (sc_scene_roughness_limiter_enabled()) { //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; vec3 dndu = dFdx(normal), dndv = dFdy(normal); @@ -1225,7 +1177,7 @@ void main() { #ifndef AMBIENT_LIGHT_DISABLED - if (scene_data.use_reflection_cubemap) { + if (sc_scene_use_reflection_cubemap()) { #ifdef LIGHT_ANISOTROPY_USED // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; @@ -1266,7 +1218,7 @@ void main() { if (scene_data.use_ambient_light) { ambient_light = scene_data.ambient_light_color_energy.rgb; - if (scene_data.use_ambient_cubemap) { + if (sc_scene_use_ambient_cubemap()) { vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; #ifdef USE_RADIANCE_CUBEMAP_ARRAY vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; @@ -1285,7 +1237,7 @@ void main() { #endif // CUSTOM_IRRADIANCE_USED #ifdef LIGHT_CLEARCOAT_USED - if (scene_data.use_reflection_cubemap) { + if (sc_scene_use_reflection_cubemap()) { vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map float NoV = max(dot(n, view), 0.0001); vec3 ref_vec = reflect(-view, n); @@ -1393,12 +1345,10 @@ void main() { // skipping ssao, do we remove ssao totally? - if (!sc_disable_reflection_probes()) { //Reflection probes + if (sc_reflection_probes() > 0) { vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - uint reflection_indices = instances.data[draw_call.instance_index].reflection_probes.x; - #ifdef LIGHT_ANISOTROPY_USED // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; @@ -1411,18 +1361,9 @@ void main() { vec3 ref_vec = normalize(reflect(-view, bent_normal)); ref_vec = mix(ref_vec, bent_normal, roughness * roughness); - for (uint i = 0; i < 8; i++) { - uint reflection_index = reflection_indices & 0xFF; - if (i == 3) { - reflection_indices = instances.data[draw_call.instance_index].reflection_probes.y; - } else { - reflection_indices = reflection_indices >> 8; - } - - if (reflection_index == 0xFF) { - break; - } - + uvec2 reflection_indices = instances.data[draw_call.instance_index].reflection_probes; + for (uint i = 0; i < sc_reflection_probes(); i++) { + uint reflection_index = (i > 3) ? ((reflection_indices.y >> ((i - 4) * 8)) & 0xFF) : ((reflection_indices.x >> (i * 8)) & 0xFF); reflection_process(reflection_index, vertex, ref_vec, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); } @@ -1487,7 +1428,7 @@ void main() { specular_light += specular_light_interp.rgb * f0; #endif - if (!sc_disable_directional_lights()) { //directional light + if (sc_directional_lights() > 0) { #ifndef SHADOWS_DISABLED // Do shadow and lighting in two passes to reduce register pressure uint shadow0 = 0; @@ -1497,7 +1438,7 @@ void main() { // Only process the first light's shadow for vertex lighting. for (uint i = 0; i < 1; i++) { #else - for (uint i = 0; i < scene_data.directional_light_count; i++) { + for (uint i = 0; i < sc_directional_lights(); i++) { #endif if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { @@ -1612,7 +1553,7 @@ void main() { #endif // SHADOWS_DISABLED #ifndef USE_VERTEX_LIGHTING - for (uint i = 0; i < scene_data.directional_light_count; i++) { + for (uint i = 0; i < sc_directional_lights(); i++) { if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked } @@ -1678,95 +1619,72 @@ void main() { } //directional light #ifndef USE_VERTEX_LIGHTING - if (!sc_disable_omni_lights()) { //omni lights - uint light_indices = instances.data[draw_call.instance_index].omni_lights.x; - for (uint i = 0; i < 8; i++) { - uint light_index = light_indices & 0xFF; - if (i == 3) { - light_indices = instances.data[draw_call.instance_index].omni_lights.y; - } else { - light_indices = light_indices >> 8; - } - - if (light_index == 0xFF) { - break; - } + uvec2 omni_indices = instances.data[draw_call.instance_index].omni_lights; + for (uint i = 0; i < sc_omni_lights(); i++) { + uint light_index = (i > 3) ? ((omni_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_indices.x >> (i * 8)) & 0xFF); - float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count); + float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - shadow = blur_shadow(shadow); + shadow = blur_shadow(shadow); - // Fragment lighting - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + // Fragment lighting + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif /* #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_boost, #endif */ #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_roughness, normalize(normal_interp), + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, - binormal, anisotropy, + tangent, + binormal, anisotropy, #endif - diffuse_light, specular_light); - } - } //omni lights - - if (!sc_disable_spot_lights()) { //spot lights - - uint light_indices = instances.data[draw_call.instance_index].spot_lights.x; - for (uint i = 0; i < 8; i++) { - uint light_index = light_indices & 0xFF; - if (i == 3) { - light_indices = instances.data[draw_call.instance_index].spot_lights.y; - } else { - light_indices = light_indices >> 8; - } + diffuse_light, specular_light); + } - if (light_index == 0xFF) { - break; - } + uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights; + for (uint i = 0; i < sc_spot_lights(); i++) { + uint light_index = (i > 3) ? ((spot_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_indices.x >> (i * 8)) & 0xFF); - float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count); + float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - shadow = blur_shadow(shadow); + shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif /* #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_boost, #endif */ #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_roughness, normalize(normal_interp), + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, - binormal, anisotropy, + tangent, + binormal, anisotropy, #endif - diffuse_light, specular_light); - } - } //spot lights + diffuse_light, specular_light); + } #endif // !VERTEX_LIGHTING #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 495e52a29e..2cc86482f6 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -22,8 +22,8 @@ layout(push_constant, std430) uniform DrawCall { uint pad; #ifdef UBERSHADER uint sc_packed_0; - float sc_packed_1; - uint sc_packed_2; + uint sc_packed_1; + float sc_packed_2; uint uc_packed_0; #endif } @@ -42,10 +42,14 @@ uint sc_packed_0() { return draw_call.sc_packed_0; } -float sc_packed_1() { +uint sc_packed_1() { return draw_call.sc_packed_1; } +float sc_packed_2() { + return draw_call.sc_packed_2; +} + uint uc_cull_mode() { return (draw_call.uc_packed_0 >> 0) & 3U; } @@ -54,16 +58,21 @@ uint uc_cull_mode() { // Pull the constants from the pipeline's specialization constants. layout(constant_id = 0) const uint pso_sc_packed_0 = 0; -layout(constant_id = 1) const float pso_sc_packed_1 = 2.0; +layout(constant_id = 1) const uint pso_sc_packed_1 = 0; +layout(constant_id = 2) const float pso_sc_packed_2 = 2.0; uint sc_packed_0() { return pso_sc_packed_0; } -float sc_packed_1() { +uint sc_packed_1() { return pso_sc_packed_1; } +float sc_packed_2() { + return pso_sc_packed_2; +} + #endif bool sc_use_light_projector() { @@ -86,60 +95,84 @@ bool sc_projector_use_mipmaps() { return ((sc_packed_0() >> 4) & 1U) != 0; } -bool sc_disable_omni_lights() { +bool sc_disable_fog() { return ((sc_packed_0() >> 5) & 1U) != 0; } -bool sc_disable_spot_lights() { +bool sc_use_depth_fog() { return ((sc_packed_0() >> 6) & 1U) != 0; } -bool sc_disable_reflection_probes() { +bool sc_use_lightmap_bicubic_filter() { return ((sc_packed_0() >> 7) & 1U) != 0; } -bool sc_disable_directional_lights() { +bool sc_multimesh() { return ((sc_packed_0() >> 8) & 1U) != 0; } -bool sc_disable_decals() { +bool sc_multimesh_format_2d() { return ((sc_packed_0() >> 9) & 1U) != 0; } -bool sc_disable_fog() { +bool sc_multimesh_has_color() { return ((sc_packed_0() >> 10) & 1U) != 0; } -bool sc_use_depth_fog() { +bool sc_multimesh_has_custom_data() { return ((sc_packed_0() >> 11) & 1U) != 0; } -bool sc_is_multimesh() { +bool sc_scene_use_ambient_cubemap() { return ((sc_packed_0() >> 12) & 1U) != 0; } -bool sc_use_lightmap_bicubic_filter() { +bool sc_scene_use_reflection_cubemap() { return ((sc_packed_0() >> 13) & 1U) != 0; } +bool sc_scene_roughness_limiter_enabled() { + return ((sc_packed_0() >> 14) & 1U) != 0; +} + uint sc_soft_shadow_samples() { - return (sc_packed_0() >> 16) & 15U; + return (sc_packed_0() >> 20) & 63U; } uint sc_penumbra_shadow_samples() { - return (sc_packed_0() >> 20) & 15U; + return (sc_packed_0() >> 26) & 63U; } uint sc_directional_soft_shadow_samples() { - return (sc_packed_0() >> 24) & 15U; + return (sc_packed_1() >> 0) & 63U; } uint sc_directional_penumbra_shadow_samples() { - return (sc_packed_0() >> 28) & 15U; + return (sc_packed_1() >> 6) & 63U; +} + +uint sc_omni_lights() { + return (sc_packed_1() >> 12) & 15U; +} + +uint sc_spot_lights() { + return (sc_packed_1() >> 16) & 15U; +} + +uint sc_reflection_probes() { + return (sc_packed_1() >> 20) & 15U; +} + +uint sc_directional_lights() { + return (sc_packed_1() >> 24) & 15U; +} + +uint sc_decals() { + return (sc_packed_1() >> 28) & 15U; } float sc_luminance_multiplier() { - return sc_packed_1(); + return sc_packed_2(); } /* Set 0: Base Pass (never changes) */ @@ -157,10 +190,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; #define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9) #define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10) #define INSTANCE_FLAGS_PARTICLES (1 << 11) -#define INSTANCE_FLAGS_MULTIMESH (1 << 12) -#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) -#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) -#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) #define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16 //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 8f71909154..9de37050f0 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -285,6 +285,23 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } +void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL(light); + + light->shadow_caster_mask = p_caster_mask; + + light->version++; + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); +} + +uint32_t LightStorage::light_get_shadow_caster_mask(RID p_light) const { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL_V(light, 0); + + return light->shadow_caster_mask; +} + void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { Light *light = light_owner.get_or_null(p_light); ERR_FAIL_NULL(light); @@ -1032,7 +1049,7 @@ void LightStorage::reflection_probe_free(RID p_rid) { ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); reflection_probe->dependency.deleted_notify(p_rid); reflection_probe_owner.free(p_rid); -}; +} void LightStorage::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 59303e8a73..1a92c5470d 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -72,6 +72,7 @@ private: RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC; uint32_t max_sdfgi_cascade = 2; uint32_t cull_mask = 0xFFFFFFFF; + uint32_t shadow_caster_mask = 0xFFFFFFFF; bool distance_fade = false; real_t distance_fade_begin = 40.0; real_t distance_fade_shadow = 50.0; @@ -480,6 +481,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override; + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override; virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override; virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override; @@ -587,7 +590,7 @@ public: /* LIGHT INSTANCE API */ - bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); }; + bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); } virtual RID light_instance_create(RID p_light) override; virtual void light_instance_free(RID p_light) override; @@ -808,7 +811,7 @@ public: /* REFLECTION PROBE */ - bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); }; + bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); } virtual RID reflection_probe_allocate() override; virtual void reflection_probe_initialize(RID p_reflection_probe) override; @@ -950,7 +953,7 @@ public: /* LIGHTMAP */ - bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }; + bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); } virtual RID lightmap_allocate() override; virtual void lightmap_initialize(RID p_lightmap) override; @@ -1016,7 +1019,7 @@ public: /* LIGHTMAP INSTANCE */ - bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }; + bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); } virtual RID lightmap_instance_create(RID p_lightmap) override; virtual void lightmap_instance_free(RID p_lightmap) override; @@ -1036,7 +1039,7 @@ public: /* SHADOW ATLAS API */ - bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); }; + bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); } virtual RID shadow_atlas_create() override; virtual void shadow_atlas_free(RID p_atlas) override; diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index 08c1064dcb..89a8b36853 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -254,7 +254,7 @@ private: MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX]; mutable RID_Owner<Material, true> material_owner; - Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); }; + Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); } SelfList<Material>::List material_update_list; Mutex material_update_list_mutex; @@ -403,7 +403,7 @@ public: /* SHADER API */ - bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); }; + bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); } virtual RID shader_allocate() override; virtual void shader_initialize(RID p_shader) override; @@ -423,7 +423,7 @@ public: /* MATERIAL API */ - bool owns_material(RID p_rid) { return material_owner.owns(p_rid); }; + bool owns_material(RID p_rid) { return material_owner.owns(p_rid); } void _material_queue_update(Material *material, bool p_uniform, bool p_texture); void _update_queued_materials(); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 322f3cc6f4..c14c2945bd 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -351,7 +351,7 @@ public: /* MESH API */ - bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); }; + bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); } virtual RID mesh_allocate() override; virtual void mesh_initialize(RID p_mesh) override; @@ -616,7 +616,7 @@ public: /* MESH INSTANCE API */ - bool owns_mesh_instance(RID p_rid) const { return mesh_instance_owner.owns(p_rid); }; + bool owns_mesh_instance(RID p_rid) const { return mesh_instance_owner.owns(p_rid); } virtual RID mesh_instance_create(RID p_base) override; virtual void mesh_instance_free(RID p_rid) override; @@ -628,7 +628,7 @@ public: /* MULTIMESH API */ - bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); }; + bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); } virtual RID _multimesh_allocate() override; virtual void _multimesh_initialize(RID p_multimesh) override; @@ -737,7 +737,7 @@ public: /* SKELETON API */ - bool owns_skeleton(RID p_rid) const { return skeleton_owner.owns(p_rid); }; + bool owns_skeleton(RID p_rid) const { return skeleton_owner.owns(p_rid); } virtual RID skeleton_allocate() override; virtual void skeleton_initialize(RID p_skeleton) override; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 314cbf9aa9..6efb8c176f 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -306,9 +306,14 @@ void ParticlesStorage::_particles_free_data(Particles *particles) { particles->emission_storage_buffer = RID(); } - if (particles->unused_storage_buffer.is_valid()) { - RD::get_singleton()->free(particles->unused_storage_buffer); - particles->unused_storage_buffer = RID(); + if (particles->unused_emission_storage_buffer.is_valid()) { + RD::get_singleton()->free(particles->unused_emission_storage_buffer); + particles->unused_emission_storage_buffer = RID(); + } + + if (particles->unused_trail_storage_buffer.is_valid()) { + RD::get_singleton()->free(particles->unused_trail_storage_buffer); + particles->unused_trail_storage_buffer = RID(); } if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) { @@ -534,9 +539,15 @@ void ParticlesStorage::_particles_allocate_emission_buffer(Particles *particles) } } -void ParticlesStorage::_particles_ensure_unused_buffer(Particles *particles) { - if (particles->unused_storage_buffer.is_null()) { - particles->unused_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); +void ParticlesStorage::_particles_ensure_unused_emission_buffer(Particles *particles) { + if (particles->unused_emission_storage_buffer.is_null()) { + particles->unused_emission_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); + } +} + +void ParticlesStorage::_particles_ensure_unused_trail_buffer(Particles *particles) { + if (particles->unused_trail_storage_buffer.is_null()) { + particles->unused_trail_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); } } @@ -763,8 +774,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta if (p_particles->emission_storage_buffer.is_valid()) { u.append_id(p_particles->emission_storage_buffer); } else { - _particles_ensure_unused_buffer(p_particles); - u.append_id(p_particles->unused_storage_buffer); + _particles_ensure_unused_emission_buffer(p_particles); + u.append_id(p_particles->unused_emission_storage_buffer); } uniforms.push_back(u); } @@ -779,8 +790,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta } u.append_id(sub_emitter->emission_storage_buffer); } else { - _particles_ensure_unused_buffer(p_particles); - u.append_id(p_particles->unused_storage_buffer); + _particles_ensure_unused_emission_buffer(p_particles); + u.append_id(p_particles->unused_emission_storage_buffer); } uniforms.push_back(u); } @@ -1481,8 +1492,8 @@ void ParticlesStorage::update_particles() { if (particles->trail_bind_pose_buffer.is_valid()) { u.append_id(particles->trail_bind_pose_buffer); } else { - _particles_ensure_unused_buffer(particles); - u.append_id(particles->unused_storage_buffer); + _particles_ensure_unused_trail_buffer(particles); + u.append_id(particles->unused_trail_storage_buffer); } uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index 33f44f3045..ec897c4ea9 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -247,7 +247,8 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; - RID unused_storage_buffer; + RID unused_emission_storage_buffer; + RID unused_trail_storage_buffer; HashSet<RID> collisions; @@ -265,7 +266,8 @@ private: void _particles_process(Particles *p_particles, double p_delta); void _particles_allocate_emission_buffer(Particles *particles); - void _particles_ensure_unused_buffer(Particles *particles); + void _particles_ensure_unused_emission_buffer(Particles *particles); + void _particles_ensure_unused_trail_buffer(Particles *particles); void _particles_free_data(Particles *particles); void _particles_update_buffers(Particles *particles); @@ -509,7 +511,7 @@ public: _FORCE_INLINE_ bool particles_has_collision(RID p_particles) { Particles *particles = particles_owner.get_or_null(p_particles); - ERR_FAIL_NULL_V(particles, 0); + ERR_FAIL_NULL_V(particles, false); return particles->has_collision_cache; } diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h index 4a70482d72..59671c3a13 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h @@ -51,6 +51,7 @@ public: float taa_frame_count = 0.0f; uint32_t camera_visible_layers; bool cam_orthogonal = false; + bool cam_frustum = false; bool flip_y = false; // For billboards to cast correct shadows. diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 42fce65b2d..8a9499dfc9 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1666,7 +1666,9 @@ void TextureStorage::texture_rd_initialize(RID p_texture, const RID &p_rd_textur ERR_FAIL_COND(tf.array_layers != 1); texture.type = TextureStorage::TYPE_2D; } break; - case RD::TEXTURE_TYPE_2D_ARRAY: { + case RD::TEXTURE_TYPE_2D_ARRAY: + case RD::TEXTURE_TYPE_CUBE: + case RD::TEXTURE_TYPE_CUBE_ARRAY: { // RenderingDevice doesn't distinguish between Array textures and Cube textures // this condition covers TextureArrays, TextureCube, and TextureCubeArray. ERR_FAIL_COND(tf.array_layers == 1); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 866fdd50ac..3d281cf98a 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -102,9 +102,9 @@ private: /* Canvas Texture API */ struct CanvasTextureCache { - RID diffuse = RID(); - RID normal = RID(); - RID specular = RID(); + RID diffuse; + RID normal; + RID specular; }; class CanvasTexture { @@ -122,7 +122,6 @@ private: Size2i size_cache = Size2i(1, 1); bool use_normal_cache = false; bool use_specular_cache = false; - bool cleared_cache = true; void clear_cache(); ~CanvasTexture(); @@ -195,7 +194,7 @@ private: // Textures can be created from threads, so this RID_Owner is thread safe. mutable RID_Owner<Texture, true> texture_owner; - Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); }; + Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); } struct TextureToRDFormat { RD::DataFormat format; @@ -439,7 +438,7 @@ private: }; mutable RID_Owner<RenderTarget> render_target_owner; - RenderTarget *get_render_target(RID p_rid) const { return render_target_owner.get_or_null(p_rid); }; + RenderTarget *get_render_target(RID p_rid) const { return render_target_owner.get_or_null(p_rid); } void _clear_render_target(RenderTarget *rt); void _update_render_target(RenderTarget *rt); @@ -486,7 +485,7 @@ public: /* Canvas Texture API */ - bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); }; + bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); } virtual RID canvas_texture_allocate() override; virtual void canvas_texture_initialize(RID p_rid) override; @@ -502,7 +501,7 @@ public: /* Texture API */ - bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); }; + bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); } virtual RID texture_allocate() override; virtual void texture_free(RID p_rid) override; @@ -591,7 +590,7 @@ public: void update_decal_atlas(); - bool owns_decal(RID p_rid) const { return decal_owner.owns(p_rid); }; + bool owns_decal(RID p_rid) const { return decal_owner.owns(p_rid); } RID decal_atlas_get_texture() const; RID decal_atlas_get_texture_srgb() const; @@ -731,7 +730,7 @@ public: /* RENDER TARGET API */ - bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); }; + bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); } virtual RID render_target_create() override; virtual void render_target_free(RID p_rid) override; diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.h b/servers/rendering/renderer_rd/storage_rd/utilities.h index 2ba3da7515..96508fd3ff 100644 --- a/servers/rendering/renderer_rd/storage_rd/utilities.h +++ b/servers/rendering/renderer_rd/storage_rd/utilities.h @@ -77,8 +77,8 @@ public: /* VISIBILITY NOTIFIER */ - VisibilityNotifier *get_visibility_notifier(RID p_rid) { return visibility_notifier_owner.get_or_null(p_rid); }; - bool owns_visibility_notifier(RID p_rid) const { return visibility_notifier_owner.owns(p_rid); }; + VisibilityNotifier *get_visibility_notifier(RID p_rid) { return visibility_notifier_owner.get_or_null(p_rid); } + bool owns_visibility_notifier(RID p_rid) const { return visibility_notifier_owner.owns(p_rid); } virtual RID visibility_notifier_allocate() override; virtual void visibility_notifier_initialize(RID p_notifier) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index ca07444465..11ca7de44f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2299,6 +2299,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in cull.shadow_count = p_shadow_index + 1; cull.shadows[p_shadow_index].cascade_count = splits; cull.shadows[p_shadow_index].light_instance = light->instance; + cull.shadows[p_shadow_index].caster_mask = RSG::light_storage->light_get_shadow_caster_mask(p_instance->base); for (int i = 0; i < splits; i++) { RENDER_TIMESTAMP("Cull DirectionalLight3D, Split " + itos(i)); @@ -2529,7 +2530,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2611,7 +2612,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2678,7 +2679,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2737,6 +2738,7 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu Projection projection; bool vaspect = camera->vaspect; bool is_orthogonal = false; + bool is_frustum = false; switch (camera->type) { case Camera::ORTHOGONAL: { @@ -2765,10 +2767,11 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu camera->znear, camera->zfar, camera->vaspect); + is_frustum = true; } break; } - camera_data.set_camera(transform, projection, is_orthogonal, vaspect, jitter, taa_frame_count, camera->visible_layers); + camera_data.set_camera(transform, projection, is_orthogonal, is_frustum, vaspect, jitter, taa_frame_count, camera->visible_layers); } else { // Setup our camera for our XR interface. // We can support multiple views here each with their own camera @@ -2790,9 +2793,9 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu } if (view_count == 1) { - camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect, jitter, p_jitter_phase_count, camera->visible_layers); + camera_data.set_camera(transforms[0], projections[0], false, false, camera->vaspect, jitter, p_jitter_phase_count, camera->visible_layers); } else if (view_count == 2) { - camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect); + camera_data.set_multiview_camera(view_count, transforms, projections, false, false, camera->vaspect); } else { // this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future... } @@ -3036,6 +3039,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul for (const Instance *E : geom->lights) { InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data); + if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { + continue; + } + instance_pair_buffer[idx++] = light->instance; if (idx == MAX_INSTANCE_PAIRS) { break; @@ -3140,7 +3147,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) { uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && LAYER_CHECK) { + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && (LAYER_CHECK & cull_data.cull->shadows[j].caster_mask)) { cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); mesh_visible = true; } @@ -3636,7 +3643,7 @@ void RendererSceneCull::render_empty_scene(const Ref<RenderSceneBuffers> &p_rend RENDER_TIMESTAMP("Render Empty 3D Scene"); RendererSceneRender::CameraData camera_data; - camera_data.set_camera(Transform3D(), Projection(), true, false); + camera_data.set_camera(Transform3D(), Projection(), true, false, false); scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray<RenderGeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), environment, RID(), compositor, p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif @@ -3714,7 +3721,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int RENDER_TIMESTAMP("Render ReflectionProbe, Step " + itos(p_step)); RendererSceneRender::CameraData camera_data; - camera_data.set_camera(xform, cm, false, false); + camera_data.set_camera(xform, cm, false, false, false); Ref<RenderSceneBuffers> render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas); _render_scene(&camera_data, render_buffers, environment, RID(), RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 5aae59eb51..82523fd4ef 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1121,6 +1121,7 @@ public: struct Cull { struct Shadow { RID light_instance; + uint32_t caster_mask; struct Cascade { Frustum frustum; @@ -1255,6 +1256,7 @@ public: PASS3(environment_set_bg_energy, RID, float, float) PASS2(environment_set_canvas_max_layer, RID, int) PASS6(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource) + PASS2(environment_set_camera_feed_id, RID, int) PASS1RC(RS::EnvironmentBG, environment_get_background, RID) PASS1RC(RID, environment_get_sky, RID) diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index df403c5484..14b97918ec 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -72,7 +72,7 @@ public: return false; } - float min_depth = -closest_point_view.z * 0.95f; + float min_depth = (closest_point - p_cam_position).length(); Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX); Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN); @@ -83,6 +83,10 @@ public: Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z); Vector3 view = p_cam_inv_transform.xform(corner); + if (p_cam_projection.is_orthogonal()) { + min_depth = MIN(min_depth, -view.z); + } + Plane vp = Plane(view, 1.0); Plane projected = p_cam_projection.xform4(vp); @@ -230,11 +234,11 @@ public: RendererSceneOcclusionCull() { singleton = this; - }; + } virtual ~RendererSceneOcclusionCull() { singleton = nullptr; - }; + } }; #endif // RENDERER_SCENE_OCCLUSION_CULL_H diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index 797ba7eaf7..07259f73d2 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -33,9 +33,10 @@ ///////////////////////////////////////////////////////////////////////////// // CameraData -void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter, float p_taa_frame_count, const uint32_t p_visible_layers) { +void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect, const Vector2 &p_taa_jitter, float p_taa_frame_count, const uint32_t p_visible_layers) { view_count = 1; is_orthogonal = p_is_orthogonal; + is_frustum = p_is_frustum; vaspect = p_vaspect; main_transform = p_transform; @@ -48,12 +49,13 @@ void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, taa_frame_count = p_taa_frame_count; } -void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect) { +void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect) { ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view"); visible_layers = 0xFFFFFFFF; view_count = p_view_count; is_orthogonal = p_is_orthogonal; + is_frustum = p_is_frustum; vaspect = p_vaspect; Vector<Plane> planes[2]; @@ -349,6 +351,14 @@ RS::EnvironmentReflectionSource RendererSceneRender::environment_get_reflection_ return environment_storage.environment_get_reflection_source(p_env); } +void RendererSceneRender::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { + environment_storage.environment_set_camera_feed_id(p_env, p_camera_feed_id); +} + +int RendererSceneRender::environment_get_camera_feed_id(RID p_env) const { + return environment_storage.environment_get_camera_feed_id(p_env); +} + // Tonemap void RendererSceneRender::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) { diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 4d81a9b6a3..99418e0411 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -118,10 +118,7 @@ public: void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value); void environment_set_canvas_max_layer(RID p_env, int p_max_layer); void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG); -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); -#endif RS::EnvironmentBG environment_get_background(RID p_env) const; RID environment_get_sky(RID p_env) const; @@ -136,6 +133,7 @@ public: float environment_get_ambient_light_energy(RID p_env) const; float environment_get_ambient_sky_contribution(RID p_env) const; RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const; + int environment_get_camera_feed_id(RID p_env) const; // Tonemap void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white); @@ -302,6 +300,7 @@ public: // flags uint32_t view_count; bool is_orthogonal; + bool is_frustum; uint32_t visible_layers; bool vaspect; @@ -314,8 +313,8 @@ public: Vector2 taa_jitter; float taa_frame_count = 0.0f; - void set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), float p_taa_frame_count = 0.0f, uint32_t p_visible_layers = 0xFFFFFFFF); - void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect); + void set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), float p_taa_frame_count = 0.0f, uint32_t p_visible_layers = 0xFFFFFFFF); + void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect); }; virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_compositor, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 942d5631e4..cc67873b24 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1260,8 +1260,6 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons write_ptr = driver->buffer_map(transfer_worker->staging_buffer); ERR_FAIL_NULL_V(write_ptr, ERR_CANT_CREATE); - write_ptr += staging_worker_offset; - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { // Transition the texture to the optimal layout. RDD::TextureBarrier tb; @@ -1303,11 +1301,12 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons if (copy_pass) { const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z; - _copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr, 0, 0, width, width, height, block_w, block_h, pitch, pixel_size, block_size); - write_ptr += to_allocate; + uint64_t staging_buffer_offset = staging_worker_offset + staging_local_offset; + uint8_t *write_ptr_mipmap_layer = write_ptr + staging_buffer_offset; + _copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr_mipmap_layer, 0, 0, width, width, height, block_w, block_h, pitch, pixel_size, block_size); RDD::BufferTextureCopyRegion copy_region; - copy_region.buffer_offset = staging_worker_offset + staging_local_offset; + copy_region.buffer_offset = staging_buffer_offset; copy_region.texture_subresources.aspect = texture->read_aspect_flags; copy_region.texture_subresources.mipmap = mm_i; copy_region.texture_subresources.base_layer = p_layer; @@ -3758,6 +3757,15 @@ int RenderingDevice::screen_get_height(DisplayServer::WindowID p_screen) const { return context->surface_get_height(surface); } +int RenderingDevice::screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen) const { + _THREAD_SAFE_METHOD_ + + HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen); + ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen."); + + return driver->swap_chain_get_pre_rotation_degrees(it->value); +} + RenderingDevice::FramebufferFormatID RenderingDevice::screen_get_framebuffer_format(DisplayServer::WindowID p_screen) const { _THREAD_SAFE_METHOD_ @@ -4441,6 +4449,117 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint dl->state.draw_count++; } +void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) { + ERR_RENDER_THREAD_GUARD(); + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_NULL(dl); + + Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer); + ERR_FAIL_NULL(buffer); + + ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch."); + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, + "No render pipeline was set before attempting to draw."); + if (dl->validation.pipeline_vertex_format != INVALID_ID) { + // Pipeline uses vertices, validate format. + ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID, + "No vertex array was bound, and render pipeline expects vertices."); + // Make sure format is right. + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format, + "The vertex format used to create the pipeline does not match the vertex format bound."); + } + + if (dl->validation.pipeline_push_constant_size > 0) { + // Using push constants, check that they were supplied. + ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } +#endif + +#ifdef DEBUG_ENABLED + for (uint32_t i = 0; i < dl->state.set_count; i++) { + if (dl->state.sets[i].pipeline_expected_format == 0) { + // Nothing expected by this pipeline. + continue; + } + + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { + if (dl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i)); + } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set); + ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d):\n%s\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(us->shader_id, us->shader_set), _shader_uniform_debug(dl->state.pipeline_shader))); + } else { + ERR_FAIL_MSG(vformat("Uniforms supplied for set (%s, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(dl->state.pipeline_shader))); + } + } + } +#endif + + // Prepare descriptor sets if the API doesn't use pipeline barriers. + if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + for (uint32_t i = 0; i < dl->state.set_count; i++) { + if (dl->state.sets[i].pipeline_expected_format == 0) { + // Nothing expected by this pipeline. + continue; + } + + draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); + } + } + + // Bind descriptor sets. + for (uint32_t i = 0; i < dl->state.set_count; i++) { + if (dl->state.sets[i].pipeline_expected_format == 0) { + continue; // Nothing expected by this pipeline. + } + if (!dl->state.sets[i].bound) { + // All good, see if this requires re-binding. + draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); + + UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set); + _uniform_set_update_shared(uniform_set); + + draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); + + dl->state.sets[i].bound = true; + } + } + + if (p_use_indices) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.index_array_count, + "Draw command requested indices, but no index buffer was set."); + + ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, + "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); +#endif + + ERR_FAIL_COND_MSG(p_offset + 20 > buffer->size, "Offset provided (+20) is past the end of buffer."); + + draw_graph.add_draw_list_draw_indexed_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride); + } else { + ERR_FAIL_COND_MSG(p_offset + 16 > buffer->size, "Offset provided (+16) is past the end of buffer."); + + draw_graph.add_draw_list_draw_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride); + } + + dl->state.draw_count++; + + if (buffer->draw_tracker != nullptr) { + draw_graph.add_draw_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ); + } + + _check_transfer_worker_buffer(buffer); +} + void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { ERR_RENDER_THREAD_GUARD(); @@ -6553,6 +6672,12 @@ void RenderingDevice::finalize() { ERR_FAIL_COND(reverse_dependency_map.size()); } +void RenderingDevice::_set_max_fps(int p_max_fps) { + for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) { + driver->swap_chain_set_max_fps(it.value, p_max_fps); + } +} + RenderingDevice *RenderingDevice::create_local_device() { RenderingDevice *rd = memnew(RenderingDevice); rd->initialize(context); @@ -6651,6 +6776,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_set_push_constant", "draw_list", "buffer", "size_bytes"), &RenderingDevice::_draw_list_set_push_constant); ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("draw_list_draw_indirect", "draw_list", "use_indices", "buffer", "offset", "draw_count", "stride"), &RenderingDevice::draw_list_draw_indirect, DEFVAL(0), DEFVAL(1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2())); ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); @@ -7260,6 +7386,10 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DEBUG_PASS); } +void RenderingDevice::make_current() { + render_thread_id = Thread::get_caller_id(); +} + RenderingDevice::~RenderingDevice() { finalize(); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 71ffbfbd88..9939df976f 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1083,6 +1083,7 @@ public: Error screen_prepare_for_drawing(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID); int screen_get_width(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; int screen_get_height(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; + int screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; FramebufferFormatID screen_get_framebuffer_format(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; Error screen_free(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID); @@ -1186,6 +1187,7 @@ public: void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size); void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0); + void draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset = 0, uint32_t p_draw_count = 1, uint32_t p_stride = 0); void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect); void draw_list_disable_scissor(DrawListID p_list); @@ -1427,6 +1429,8 @@ public: Error initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window = DisplayServer::INVALID_WINDOW_ID); void finalize(); + void _set_max_fps(int p_max_fps); + void free(RID p_id); /****************/ @@ -1496,6 +1500,8 @@ public: static RenderingDevice *get_singleton(); + void make_current(); + RenderingDevice(); ~RenderingDevice(); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index d9ca286b15..e41a56b0a3 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -31,7 +31,10 @@ #include "rendering_device_binds.h" Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) { - ERR_FAIL_NULL_V(RenderingDevice::get_singleton(), ERR_UNAVAILABLE); + ERR_FAIL_NULL_V_MSG( + RenderingDevice::get_singleton(), + ERR_UNAVAILABLE, + "Cannot import custom .glsl shaders when running without a RenderingDevice. This can happen if you are using the headless more or the Compatibility backend."); Vector<String> lines = p_text.split("\n"); diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index 9ff7b83215..c1a3f34af8 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -376,6 +376,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) { return true; case API_TRAIT_USE_GENERAL_IN_COPY_QUEUES: return false; + case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS: + return false; default: ERR_FAIL_V(0); } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 637d52c060..d2d14676db 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -120,9 +120,9 @@ struct VersatileResourceTemplate { class RenderingDeviceDriver : public RenderingDeviceCommons { public: struct ID { - size_t id = 0; + uint64_t id = 0; _ALWAYS_INLINE_ ID() = default; - _ALWAYS_INLINE_ ID(size_t p_id) : + _ALWAYS_INLINE_ ID(uint64_t p_id) : id(p_id) {} }; @@ -138,11 +138,9 @@ public: _ALWAYS_INLINE_ bool operator!=(const m_name##ID &p_other) const { return id != p_other.id; } \ _ALWAYS_INLINE_ m_name##ID(const m_name##ID &p_other) : ID(p_other.id) {} \ _ALWAYS_INLINE_ explicit m_name##ID(uint64_t p_int) : ID(p_int) {} \ - _ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((size_t)p_ptr) {} \ + _ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((uint64_t)p_ptr) {} \ _ALWAYS_INLINE_ m_name##ID() = default; \ - }; \ - /* Ensure type-punnable to pointer. Makes some things easier.*/ \ - static_assert(sizeof(m_name##ID) == sizeof(void *)); + }; // Id types declared before anything else to prevent cyclic dependencies between the different concerns. DEFINE_ID(Buffer); @@ -454,9 +452,16 @@ public: // Retrieve the render pass that can be used to draw on the swap chain's framebuffers. virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) = 0; + // Retrieve the rotation in degrees to apply as a pre-transform. Usually 0 on PC. May be 0, 90, 180 & 270 on Android. + virtual int swap_chain_get_pre_rotation_degrees(SwapChainID p_swap_chain) { return 0; } + // Retrieve the format used by the swap chain's framebuffers. virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) = 0; + // Tells the swapchain the max_fps so it can use the proper frame pacing. + // Android uses this with Swappy library. Some implementations or platforms may ignore this hint. + virtual void swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) {} + // Wait until all rendering associated to the swap chain is finished before deleting it. virtual void swap_chain_free(SwapChainID p_swap_chain) = 0; @@ -752,6 +757,7 @@ public: API_TRAIT_SECONDARY_VIEWPORT_SCISSOR, API_TRAIT_CLEARS_WITH_COPY_ENGINE, API_TRAIT_USE_GENERAL_IN_COPY_QUEUES, + API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS, }; enum ShaderChangeInvalidation { diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index 0ecd818805..ec2f336f3c 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -34,7 +34,6 @@ #define FORCE_FULL_ACCESS_BITS 0 #define PRINT_RESOURCE_TRACKER_TOTAL 0 #define PRINT_COMMAND_RECORDING 0 -#define INSERT_BREADCRUMBS 1 RenderingDeviceGraph::RenderingDeviceGraph() { driver_honors_barriers = false; @@ -141,6 +140,25 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage #endif } +bool RenderingDeviceGraph::_check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const { + if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) { + // We don't check possible intersections for usages that aren't consecutive color or depth writes. + return true; + } + + const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index]; + const uint32_t current_command_data_offset = command_data_offsets[p_command_index]; + const RecordedDrawListCommand &previous_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[previous_command_data_offset]); + const RecordedDrawListCommand ¤t_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[current_command_data_offset]); + if (previous_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST || current_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) { + // We don't check possible intersections if both commands aren't draw lists. + return true; + } + + // We check if the region used by both draw lists have an intersection. + return previous_draw_list_command.region.intersects(current_draw_list_command.region); +} + int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) { DEV_ASSERT(p_command_index < int32_t(command_count)); DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size())); @@ -426,11 +444,9 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr #if USE_BUFFER_BARRIERS _add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count); #endif - // FIXME: Memory barriers are currently pushed regardless of whether buffer barriers are being used or not. Refer to the comment on the - // definition of USE_BUFFER_BARRIERS for the reason behind this. This can be fixed to be one case or the other once it's been confirmed - // the buffer and memory barrier behavior discrepancy has been solved. - r_command->memory_barrier.src_access = resource_tracker->usage_access; - r_command->memory_barrier.dst_access = new_usage_access; + // Memory barriers are pushed regardless of buffer barriers being used or not. + r_command->memory_barrier.src_access = r_command->memory_barrier.src_access | resource_tracker->usage_access; + r_command->memory_barrier.dst_access = r_command->memory_barrier.dst_access | new_usage_access; } else { DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID."); } @@ -450,10 +466,12 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr if (different_usage) { // Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write. - write_usage = true; + // In the case of buffers however, this is not exactly necessary if the driver does not consider different buffer usages as different states. + write_usage = write_usage || bool(resource_tracker->texture_driver_id) || driver_buffers_require_transitions; resource_tracker->usage = new_resource_usage; } + bool command_intersection_failed = false; if (search_tracker->write_command_or_list_index >= 0) { if (search_tracker->write_command_list_enabled) { // Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies. @@ -465,7 +483,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr if (!resource_has_parent || search_tracker_rect.intersects(write_list_node.subresources)) { if (write_list_node.command_index == p_command_index) { ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency."); - } else { + } else if (_check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) { // Command is dependent on this command. Add this command to the adjacency list of the write command. _add_adjacent_command(write_list_node.command_index, p_command_index, r_command); @@ -481,6 +499,8 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr write_list_index = write_list_node.next_list_index; continue; } + } else { + command_intersection_failed = true; } } @@ -491,14 +511,16 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr // The index is just the latest command index that wrote to the resource. if (search_tracker->write_command_or_list_index == p_command_index) { ERR_FAIL_MSG("Command can't have itself as a dependency."); - } else { + } else if (_check_command_intersection(resource_tracker, search_tracker->write_command_or_list_index, p_command_index)) { _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command); + } else { + command_intersection_failed = true; } } } if (write_usage) { - if (resource_has_parent) { + if (resource_has_parent || command_intersection_failed) { if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) { // Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list. const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources; @@ -709,6 +731,16 @@ void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0); instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction); } break; + case DrawListInstruction::TYPE_DRAW_INDIRECT: { + const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction); + driver->command_render_draw_indirect(p_command_buffer, draw_indirect_instruction->buffer, draw_indirect_instruction->offset, draw_indirect_instruction->draw_count, draw_indirect_instruction->stride); + instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction); + } break; + case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: { + const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction); + driver->command_render_draw_indexed_indirect(p_command_buffer, draw_indexed_indirect_instruction->buffer, draw_indexed_indirect_instruction->offset, draw_indexed_indirect_instruction->draw_count, draw_indexed_indirect_instruction->stride); + instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction); + } break; case DrawListInstruction::TYPE_EXECUTE_COMMANDS: { const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction); driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer); @@ -833,7 +865,7 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command); const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count); -#if INSERT_BREADCRUMBS +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb); #endif driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values); @@ -1190,6 +1222,16 @@ void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, u print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index); instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction); } break; + case DrawListInstruction::TYPE_DRAW_INDIRECT: { + const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction); + print_line("\tDRAW INDIRECT BUFFER ID", itos(draw_indirect_instruction->buffer.id), "OFFSET", draw_indirect_instruction->offset, "DRAW COUNT", draw_indirect_instruction->draw_count, "STRIDE", draw_indirect_instruction->stride); + instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction); + } break; + case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: { + const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction); + print_line("\tDRAW INDEXED INDIRECT BUFFER ID", itos(draw_indexed_indirect_instruction->buffer.id), "OFFSET", draw_indexed_indirect_instruction->offset, "DRAW COUNT", draw_indexed_indirect_instruction->draw_count, "STRIDE", draw_indexed_indirect_instruction->stride); + instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction); + } break; case DrawListInstruction::TYPE_EXECUTE_COMMANDS: { print_line("\tEXECUTE COMMANDS"); instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction); @@ -1299,6 +1341,7 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Dev driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS); driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE); + driver_buffers_require_transitions = driver->api_trait_get(RDD::API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS); } void RenderingDeviceGraph::finalize() { @@ -1416,7 +1459,9 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) { compute_instruction_list.clear(); +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1)); +#endif compute_instruction_list.index++; } @@ -1512,7 +1557,9 @@ void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, draw_instruction_list.render_pass = p_render_pass; draw_instruction_list.framebuffer = p_framebuffer; draw_instruction_list.region = p_region; +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) draw_instruction_list.breadcrumb = p_breadcrumb; +#endif draw_instruction_list.clear_values.resize(p_clear_values.size()); for (uint32_t i = 0; i < p_clear_values.size(); i++) { draw_instruction_list.clear_values[i] = p_clear_values[i]; @@ -1608,6 +1655,26 @@ void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, ui instruction->first_index = p_first_index; } +void RenderingDeviceGraph::add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) { + DrawListDrawIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndirectInstruction))); + instruction->type = DrawListInstruction::TYPE_DRAW_INDIRECT; + instruction->buffer = p_buffer; + instruction->offset = p_offset; + instruction->draw_count = p_draw_count; + instruction->stride = p_stride; + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); +} + +void RenderingDeviceGraph::add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) { + DrawListDrawIndexedIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndexedIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedIndirectInstruction))); + instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT; + instruction->buffer = p_buffer; + instruction->offset = p_offset; + instruction->draw_count = p_draw_count; + instruction->stride = p_stride; + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); +} + void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) { DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction))); instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS; @@ -1723,7 +1790,9 @@ void RenderingDeviceGraph::add_draw_list_end() { command->framebuffer = draw_instruction_list.framebuffer; command->command_buffer_type = command_buffer_type; command->region = draw_instruction_list.region; +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) command->breadcrumb = draw_instruction_list.breadcrumb; +#endif command->clear_values_count = draw_instruction_list.clear_values.size(); RDD::RenderPassClearValue *clear_values = command->clear_values(); diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h index 0534d4ee1e..9ddd70bc80 100644 --- a/servers/rendering/rendering_device_graph.h +++ b/servers/rendering/rendering_device_graph.h @@ -69,6 +69,8 @@ public: TYPE_CLEAR_ATTACHMENTS, TYPE_DRAW, TYPE_DRAW_INDEXED, + TYPE_DRAW_INDIRECT, + TYPE_DRAW_INDEXED_INDIRECT, TYPE_EXECUTE_COMMANDS, TYPE_NEXT_SUBPASS, TYPE_SET_BLEND_CONSTANTS, @@ -221,14 +223,18 @@ private: }; struct ComputeInstructionList : InstructionList { +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) uint32_t breadcrumb; +#endif }; struct DrawInstructionList : InstructionList { RDD::RenderPassID render_pass; RDD::FramebufferID framebuffer; Rect2i region; +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) uint32_t breadcrumb; +#endif LocalVector<RDD::RenderPassClearValue> clear_values; }; @@ -317,7 +323,9 @@ private: RDD::FramebufferID framebuffer; RDD::CommandBufferType command_buffer_type; Rect2i region; +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) uint32_t breadcrumb = 0; +#endif uint32_t clear_values_count = 0; _FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() { @@ -466,6 +474,20 @@ private: uint32_t first_index = 0; }; + struct DrawListDrawIndirectInstruction : DrawListInstruction { + RDD::BufferID buffer; + uint32_t offset = 0; + uint32_t draw_count = 0; + uint32_t stride = 0; + }; + + struct DrawListDrawIndexedIndirectInstruction : DrawListInstruction { + RDD::BufferID buffer; + uint32_t offset = 0; + uint32_t draw_count = 0; + uint32_t stride = 0; + }; + struct DrawListEndRenderPassInstruction : DrawListInstruction { // No contents. }; @@ -615,6 +637,7 @@ private: BarrierGroup barrier_group; bool driver_honors_barriers : 1; bool driver_clears_with_copy_engine : 1; + bool driver_buffers_require_transitions : 1; WorkaroundsState workarounds_state; TightLocalVector<Frame> frames; uint32_t frame = 0; @@ -626,6 +649,7 @@ private: static bool _is_write_usage(ResourceUsage p_usage); static RDD::TextureLayout _usage_to_image_layout(ResourceUsage p_usage); static RDD::BarrierAccessBits _usage_to_access_bits(ResourceUsage p_usage); + bool _check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const; int32_t _add_to_command_list(int32_t p_command_index, int32_t p_list_index); void _add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command); int32_t _add_to_slice_read_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index); @@ -678,6 +702,8 @@ public: void add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect); void add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count); void add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index); + void add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride); + void add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride); void add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer); void add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type); void add_draw_list_set_blend_constants(const Color &p_color); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 4c277ac215..34f11924ce 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -168,6 +168,7 @@ public: virtual void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) = 0; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0; + virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; virtual RS::EnvironmentBG environment_get_background(RID p_Env) const = 0; virtual RID environment_get_sky(RID p_env) const = 0; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 20f1f9ad6f..2ec693cbbf 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -370,6 +370,8 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const { void RenderingServerDefault::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) { server_thread = Thread::get_caller_id(); server_task_id = p_pump_task_id; + // This is needed because the main RD is created on the main thread. + RenderingDevice::get_singleton()->make_current(); } void RenderingServerDefault::_thread_exit() { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 225a67fb52..5c3ee513c7 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -443,6 +443,7 @@ public: FUNC2(light_set_cull_mask, RID, uint32_t) FUNC5(light_set_distance_fade, RID, bool, float, float, float) FUNC2(light_set_reverse_cull_face_mode, RID, bool) + FUNC2(light_set_shadow_caster_mask, RID, uint32_t) FUNC2(light_set_bake_mode, RID, LightBakeMode) FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t) @@ -785,10 +786,8 @@ public: FUNC2(environment_set_canvas_max_layer, RID, int) FUNC6(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource) -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 FUNC2(environment_set_camera_feed_id, RID, int) -#endif + FUNC6(environment_set_ssr, RID, bool, int, float, float, float) FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 119ac677eb..f52963f98f 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -489,7 +489,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene struct_code += _typestr(m->datatype); } struct_code += " "; - struct_code += m->name; + struct_code += _mkid(m->name); if (m->array_size > 0) { struct_code += "["; struct_code += itos(m->array_size); @@ -1448,7 +1448,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } break; case SL::Node::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; + String name; + if (mnode->basetype == SL::TYPE_STRUCT) { + name = _mkid(mnode->name); + } else { + name = mnode->name; + } + code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + name; if (mnode->index_expression != nullptr) { code += "["; code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index b6770c773c..7c4128b0e3 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -356,7 +356,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_CF_BREAK, "break", CF_BLOCK, {}, {} }, { TK_CF_CONTINUE, "continue", CF_BLOCK, {}, {} }, { TK_CF_RETURN, "return", CF_BLOCK, {}, {} }, - { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "fragment" } }, + { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "vertex" } }, // function specifier keywords @@ -3565,28 +3565,33 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI int argcount = args.size(); - if (p_function_info.stage_functions.has(name)) { - //stage based function - const StageFunctionInfo &sf = p_function_info.stage_functions[name]; - if (argcount != sf.arguments.size()) { - _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size())); - return false; - } - //validate arguments - for (int i = 0; i < argcount; i++) { - if (args[i] != sf.arguments[i].type) { - _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type))); - return false; - } - } + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue<StringName, FunctionInfo> &E : *stages) { + if (E.value.stage_functions.has(name)) { + // Stage-based function. + const StageFunctionInfo &sf = E.value.stage_functions[name]; + if (argcount != sf.arguments.size()) { + _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size())); + return false; + } + // Validate arguments. + for (int i = 0; i < argcount; i++) { + if (args[i] != sf.arguments[i].type) { + _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type))); + return false; + } + } - if (r_ret_type) { - *r_ret_type = sf.return_type; - } - if (r_ret_type_str) { - *r_ret_type_str = ""; + if (r_ret_type) { + *r_ret_type = sf.return_type; + } + if (r_ret_type_str) { + *r_ret_type_str = ""; + } + return true; + } } - return true; } bool failed_builtin = false; @@ -5937,22 +5942,35 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons calls_info[current_function].calls.push_back(&calls_info[name]); } - int idx = 0; bool is_builtin = false; - while (frag_only_func_defs[idx].name) { - if (frag_only_func_defs[idx].name == name) { - // If a built-in function not found for the current shader type, then it shouldn't be parsed further. - if (!is_supported_frag_only_funcs) { - _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier)); - return nullptr; + if (is_supported_frag_only_funcs && stages) { + for (const KeyValue<StringName, FunctionInfo> &E : *stages) { + if (E.value.stage_functions.has(name)) { + // Register usage of the restricted stage function. + calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); + is_builtin = true; + break; } - // Register usage of the restricted function. - calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); - is_builtin = true; - break; } - idx++; + } + + if (!is_builtin) { + int idx = 0; + while (frag_only_func_defs[idx].name) { + if (frag_only_func_defs[idx].name == name) { + // If a built-in function not found for the current shader type, then it shouldn't be parsed further. + if (!is_supported_frag_only_funcs) { + _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier)); + return nullptr; + } + // Register usage of the restricted function. + calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); + is_builtin = true; + break; + } + idx++; + } } // Recursively checks for the restricted function call. @@ -8581,6 +8599,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun block = block->parent_block; } } else if (tk.type == TK_CF_DISCARD) { + if (!is_discard_supported) { + _set_error(vformat(RTR("Use of '%s' is not supported for the '%s' shader type."), "discard", shader_type_identifier)); + return ERR_PARSE_ERROR; + } + //check return type BlockNode *b = p_block; while (b && !b->parent_function) { @@ -8592,7 +8615,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (!b->parent_function->can_discard) { - _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard")); + _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), "discard", b->parent_function->name)); return ERR_PARSE_ERROR; } @@ -8601,6 +8624,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun pos = _get_tkpos(); tk = _get_token(); + + calls_info[b->parent_function->name].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>("discard", CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, pos))); + if (tk.type != TK_SEMICOLON) { _set_expected_after_error(";", "discard"); return ERR_PARSE_ERROR; @@ -8838,7 +8864,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; stages = &p_functions; - is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky"; + + is_discard_supported = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial"; + is_supported_frag_only_funcs = is_discard_supported || shader_type_identifier == "sky"; const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo(); @@ -10332,6 +10360,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f if (p_functions.has(name)) { func_node->can_discard = p_functions[name].can_discard; + } else { + func_node->can_discard = is_discard_supported; // Allow use it for custom functions (in supported shader types). } if (!function_overload_count.has(name)) { @@ -10922,10 +10952,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ break; // Ignore hint keywords (parsed below). } if (keyword_list[i].flags & keyword_completion_context) { - if (keyword_list[i].excluded_shader_types.has(shader_type_identifier)) { - continue; - } - if (!keyword_list[i].functions.is_empty() && !keyword_list[i].functions.has(current_function)) { + if (keyword_list[i].excluded_shader_types.has(shader_type_identifier) || keyword_list[i].excluded_functions.has(current_function)) { continue; } ScriptLanguage::CodeCompletionOption option(keyword_list[i].text, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -11160,9 +11187,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ int idx = 0; bool low_end = RenderingServer::get_singleton()->is_low_end(); - if (stages && stages->has(skip_function)) { - for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) { - matches.insert(String(E.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue<StringName, FunctionInfo> &E : *stages) { + for (const KeyValue<StringName, StageFunctionInfo> &F : E.value.stage_functions) { + if (F.value.skip_function == skip_function && stages->has(skip_function)) { + continue; + } + matches.insert(String(F.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + } } } @@ -11292,9 +11325,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ return OK; } - if (stages && stages->has(block_function)) { - for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) { - if (completion_function == E.key) { + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue<StringName, FunctionInfo> &S : *stages) { + for (const KeyValue<StringName, StageFunctionInfo> &E : S.value.stage_functions) { + // No need to check for the skip function here. + if (completion_function != E.key) { + continue; + } + calltip += get_datatype_name(E.value.return_type); calltip += " "; calltip += E.key; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index fb0a526230..4dade4d79f 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -859,6 +859,7 @@ public: Vector<Argument> arguments; DataType return_type = TYPE_VOID; + String skip_function; }; struct ModeInfo { @@ -934,7 +935,7 @@ private: const char *text; uint32_t flags; const Vector<String> excluded_shader_types; - const Vector<String> functions; + const Vector<String> excluded_functions; }; static const KeyWord keyword_list[]; @@ -1150,6 +1151,7 @@ private: const HashMap<StringName, FunctionInfo> *stages = nullptr; bool is_supported_frag_only_funcs = false; + bool is_discard_supported = false; bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); static const BuiltinFuncDef builtin_func_defs[]; @@ -1211,7 +1213,7 @@ public: struct ShaderCompileInfo { HashMap<StringName, FunctionInfo> functions; Vector<ModeInfo> render_modes; - VaryingFunctionNames varying_function_names = VaryingFunctionNames(); + VaryingFunctionNames varying_function_names; HashSet<String> shader_types; GlobalShaderUniformGetTypeFunc global_shader_uniform_type_func = nullptr; bool is_include = false; diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 0e41a178b5..88ea74cdfc 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -816,6 +816,11 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) { } if (state->defines.has(label)) { + if (state->defines[label]->is_builtin) { + set_error(vformat(RTR("Cannot use '%s' on built-in define."), "undef"), line); + return; + } + memdelete(state->defines[label]); state->defines.erase(label); } @@ -1324,6 +1329,35 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen pp_state.current_filename = p_filename; pp_state.save_regions = r_regions != nullptr; } + + // Built-in defines. + { + static HashMap<StringName, String> defines; + + if (defines.is_empty()) { + const String rendering_method = OS::get_singleton()->get_current_rendering_method(); + + if (rendering_method == "forward_plus") { + defines["CURRENT_RENDERER"] = _MKSTR(2); + } else if (rendering_method == "mobile") { + defines["CURRENT_RENDERER"] = _MKSTR(1); + } else { // gl_compatibility + defines["CURRENT_RENDERER"] = _MKSTR(0); + } + + defines["RENDERER_COMPATIBILITY"] = _MKSTR(0); + defines["RENDERER_MOBILE"] = _MKSTR(1); + defines["RENDERER_FORWARD_PLUS"] = _MKSTR(2); + } + + for (const KeyValue<StringName, String> &E : defines) { + Define *define = memnew(Define); + define->is_builtin = true; + define->body = E.value; + pp_state.defines[E.key] = define; + } + } + Error err = preprocess(&pp_state, p_code, r_result); if (err != OK) { if (r_error_text) { diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h index 0a90aec958..b3d9594bcb 100644 --- a/servers/rendering/shader_preprocessor.h +++ b/servers/rendering/shader_preprocessor.h @@ -132,6 +132,7 @@ private: struct Define { Vector<String> arguments; String body; + bool is_builtin = false; }; struct Branch { diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index f498c0bf93..821009f07c 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -63,6 +63,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; @@ -96,8 +98,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MAIN_CAM_INV_VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); @@ -159,9 +159,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EYE_OFFSET"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -203,8 +200,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true; @@ -284,6 +279,7 @@ ShaderTypes::ShaderTypes() { { ShaderLanguage::StageFunctionInfo func; + func.skip_function = "vertex"; func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("sdf_pos", ShaderLanguage::TYPE_VEC2)); func.return_type = ShaderLanguage::TYPE_FLOAT; //whether it could emit shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf"] = func; @@ -297,6 +293,7 @@ ShaderTypes::ShaderTypes() { { ShaderLanguage::StageFunctionInfo func; + func.skip_function = "vertex"; func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("uv", ShaderLanguage::TYPE_VEC2)); func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["screen_uv_to_sdf"] = func; diff --git a/servers/rendering/storage/camera_attributes_storage.h b/servers/rendering/storage/camera_attributes_storage.h index 6fbcd3da7d..afb8ad23cf 100644 --- a/servers/rendering/storage/camera_attributes_storage.h +++ b/servers/rendering/storage/camera_attributes_storage.h @@ -72,8 +72,8 @@ public: RendererCameraAttributes(); ~RendererCameraAttributes(); - CameraAttributes *get_camera_attributes(RID p_rid) { return camera_attributes_owner.get_or_null(p_rid); }; - bool owns_camera_attributes(RID p_rid) { return camera_attributes_owner.owns(p_rid); }; + CameraAttributes *get_camera_attributes(RID p_rid) { return camera_attributes_owner.get_or_null(p_rid); } + bool owns_camera_attributes(RID p_rid) { return camera_attributes_owner.owns(p_rid); } RID camera_attributes_allocate(); void camera_attributes_initialize(RID p_rid); diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp index 1bbb5da6bb..e7556f9000 100644 --- a/servers/rendering/storage/environment_storage.cpp +++ b/servers/rendering/storage/environment_storage.cpp @@ -189,6 +189,18 @@ RS::EnvironmentReflectionSource RendererEnvironmentStorage::environment_get_refl return env->reflection_source; } +void RendererEnvironmentStorage::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { + Environment *env = environment_owner.get_or_null(p_env); + ERR_FAIL_NULL(env); + env->camera_feed_id = p_camera_feed_id; +} + +int RendererEnvironmentStorage::environment_get_camera_feed_id(RID p_env) const { + Environment *env = environment_owner.get_or_null(p_env); + ERR_FAIL_NULL_V(env, -1); + return env->camera_feed_id; +} + // Tonemap void RendererEnvironmentStorage::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) { diff --git a/servers/rendering/storage/environment_storage.h b/servers/rendering/storage/environment_storage.h index 9f78808ff7..6fdc047ba2 100644 --- a/servers/rendering/storage/environment_storage.h +++ b/servers/rendering/storage/environment_storage.h @@ -57,6 +57,7 @@ private: float ambient_light_energy = 1.0; float ambient_sky_contribution = 1.0; RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG; + int camera_feed_id = 0; // Tonemap RS::EnvironmentToneMapper tone_mapper; @@ -181,10 +182,8 @@ public: void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value); void environment_set_canvas_max_layer(RID p_env, int p_max_layer); void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG); -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); -#endif + int environment_get_camera_feed_id(RID p_env) const; RS::EnvironmentBG environment_get_background(RID p_env) const; RID environment_get_sky(RID p_env) const; diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 6a0adfa596..1e149e3a97 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -59,6 +59,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) = 0; + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const = 0; virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp index 96e6492854..6d18ae2f77 100644 --- a/servers/rendering/storage/render_scene_buffers.cpp +++ b/servers/rendering/storage/render_scene_buffers.cpp @@ -81,7 +81,7 @@ void RenderSceneBuffersExtension::_bind_methods() { void RenderSceneBuffersExtension::configure(const RenderSceneBuffersConfiguration *p_config) { GDVIRTUAL_CALL(_configure, p_config); -}; +} void RenderSceneBuffersExtension::set_fsr_sharpness(float p_fsr_sharpness) { GDVIRTUAL_CALL(_set_fsr_sharpness, p_fsr_sharpness); |