diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml index 10ac4b0fccf..8867ca58e83 100644 --- a/doc/classes/Sprite2D.xml +++ b/doc/classes/Sprite2D.xml @@ -76,7 +76,7 @@ If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect]. - If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code]. + If [code]true[/code], the area outside of the [member region_rect] is clipped to avoid bleeding of the surrounding texture pixels. [member region_enabled] must be [code]true[/code]. The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 7f4988583b6..bc67e0fafcb 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -2348,6 +2348,19 @@ RDD::CommandPoolID RenderingDeviceDriverD3D12::command_pool_create(CommandQueueF void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) { CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id); + + // Destroy all command buffers associated with this command pool, mirroring Vulkan's behavior. + SelfList *cmd_buf_elem = command_pool->command_buffers.first(); + while (cmd_buf_elem != nullptr) { + CommandBufferInfo *cmd_buf_info = cmd_buf_elem->self(); + cmd_buf_elem = cmd_buf_elem->next(); + + cmd_buf_info->cmd_list.Reset(); + cmd_buf_info->cmd_allocator.Reset(); + + VersatileResource::free(resources_allocator, cmd_buf_info); + } + memdelete(command_pool); } @@ -2356,7 +2369,7 @@ void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) { RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPoolID p_cmd_pool) { DEV_ASSERT(p_cmd_pool); - const CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id); + CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id); D3D12_COMMAND_LIST_TYPE list_type; if (command_pool->buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) { list_type = D3D12_COMMAND_LIST_TYPE_BUNDLE; @@ -2392,6 +2405,9 @@ RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPo cmd_buf_info->cmd_allocator = cmd_allocator; cmd_buf_info->cmd_list = cmd_list; + // Add this command buffer to the command pool's list of command buffers. + command_pool->command_buffers.add(&cmd_buf_info->command_buffer_info_elem); + return CommandBufferID(cmd_buf_info); } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index e6833e0793b..e43cb322b51 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -451,6 +451,9 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { struct CommandPoolInfo { CommandQueueFamilyID queue_family; CommandBufferType buffer_type = COMMAND_BUFFER_TYPE_PRIMARY; + // Since there are no command pools in D3D12, we need to track the command buffers created by this pool + // so that we can free them when the pool is freed. + SelfList::List command_buffers; }; public: @@ -478,6 +481,9 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { // Leveraging knowledge of actual usage and D3D12 specifics (namely, command lists from the same allocator // can't be freely begun and ended), an allocator per list works better. struct CommandBufferInfo { + // Store a self list reference to be used by the command pool. + SelfList command_buffer_info_elem{ this }; + ComPtr cmd_allocator; ComPtr cmd_list; diff --git a/drivers/gles3/effects/cubemap_filter.cpp b/drivers/gles3/effects/cubemap_filter.cpp index 84528056dde..8415ce92d7d 100644 --- a/drivers/gles3/effects/cubemap_filter.cpp +++ b/drivers/gles3/effects/cubemap_filter.cpp @@ -43,7 +43,10 @@ CubemapFilter *CubemapFilter::singleton = nullptr; CubemapFilter::CubemapFilter() { singleton = this; - ggx_samples = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); + // Use a factor 4 larger for the compatibility renderer to make up for the fact + // That we don't use an array texture. We will reduce samples on low roughness + // to compensate. + ggx_samples = 4 * uint32_t(GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples")); { String defines; @@ -59,10 +62,10 @@ CubemapFilter::CubemapFilter() { const float qv[6] = { -1.0f, -1.0f, - 3.0f, - -1.0f, -1.0f, 3.0f, + 3.0f, + -1.0f, }; glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW); @@ -148,10 +151,11 @@ void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubem } if (p_layer > 0) { - const uint32_t sample_counts[4] = { 1, ggx_samples / 4, ggx_samples / 2, ggx_samples }; - uint32_t sample_count = sample_counts[MIN(3, p_layer)]; + const uint32_t sample_counts[5] = { 1, ggx_samples / 16, ggx_samples / 8, ggx_samples / 4, ggx_samples }; + uint32_t sample_count = sample_counts[MIN(4, p_layer)]; - float roughness = float(p_layer) / (p_mipmap_count); + float roughness = float(p_layer) / (p_mipmap_count - 1); + roughness *= roughness; // Convert to non-perceptual roughness. float roughness4 = roughness * roughness; roughness4 *= roughness4; @@ -167,7 +171,7 @@ void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubem Vector3 dir = importance_sample_GGX(xi, roughness4); Vector3 light_vec = (2.0 * dir.z * dir - Vector3(0.0, 0.0, 1.0)); - if (light_vec.z < 0.0) { + if (light_vec.z <= 0.0) { continue; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 10d580f5b7c..b45926cafee 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2397,6 +2397,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ bool draw_sky = false; bool draw_sky_fog_only = false; bool keep_color = false; + bool draw_canvas = false; float sky_energy_multiplier = 1.0; if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) { @@ -2436,12 +2437,13 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ draw_sky = !render_data.transparent_bg; } break; case RS::ENV_BG_CANVAS: { - keep_color = true; + draw_canvas = true; } break; case RS::ENV_BG_KEEP: { keep_color = true; } break; case RS::ENV_BG_CAMERA_FEED: { + keep_color = true; } break; default: { } @@ -2553,10 +2555,14 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ glClear(GL_DEPTH_BUFFER_BIT); } - if (!keep_color) { + // Need to clear framebuffer unless: + // a) We explicitly request not to (i.e. ENV_BG_KEEP). + // b) We are rendering to a non-intermediate framebuffer with ENV_BG_CANVAS (shared between 2D and 3D). + if (!keep_color && (!draw_canvas || fbo != rt->fbo)) { clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f; glClearBufferfv(GL_COLOR, 0, clear_color.components); - } else if (fbo != rt->fbo) { + } + if ((keep_color || draw_canvas) && fbo != rt->fbo) { // Need to copy our current contents to our intermediate/MSAA buffer GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton(); @@ -2567,6 +2573,9 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ glBindTexture(rt->view_count > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, rt->color); copy_effects->copy_screen(render_data.luminance_multiplier); + + scene_state.enable_gl_depth_test(true); + scene_state.enable_gl_depth_draw(true); } RENDER_TIMESTAMP("Render Opaque Pass"); @@ -3287,10 +3296,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, spec_constants); - - prev_shader = shader; - prev_variant = instance_variant; - prev_spec_constants = spec_constants; } // Pass in lighting uniforms. @@ -3328,7 +3333,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } // Pass light count and array of light indices for base pass. - if ((prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) && pass == 0) { + if ((prev_inst != inst || prev_shader != shader || prev_variant != instance_variant || prev_spec_constants != spec_constants) && pass == 0) { // Rebind the light indices. material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_gl_cache.size(), shader->version, instance_variant, spec_constants); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_gl_cache.size(), shader->version, instance_variant, spec_constants); @@ -3380,11 +3385,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } else if (inst->lightmap_sh) { glUniform4fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURES, shader->version, instance_variant, spec_constants), 9, reinterpret_cast(inst->lightmap_sh->sh)); } - prev_inst = inst; } } + prev_shader = shader; + prev_variant = instance_variant; + prev_spec_constants = spec_constants; + // Pass in reflection probe data if constexpr (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) { if (pass == 0 && inst->reflection_probe_rid_cache.size() > 0) { diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 728d0d47f38..1ac289d5a24 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -578,7 +578,8 @@ void main() { #endif if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) { - uv = clamp(uv, read_draw_data_src_rect.xy, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw)); + vec2 half_texpixel = read_draw_data_color_texture_pixel_size * 0.5; + uv = clamp(uv, read_draw_data_src_rect.xy + half_texpixel, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) - half_texpixel); } #endif diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 2591937a1da..bdc28e292e2 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -453,14 +453,14 @@ void main() { vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5; - float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r; + float y = texture(height_field_texture, uvw_pos.xz).r; if (y + EPSILON > uvw_pos.y) { //inside heightfield vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz; - vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz; - vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz; + vec3 pos2 = (vec3(uvw_pos.x + DELTA, texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz; + vec3 pos3 = (vec3(uvw_pos.x, texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz; normal = normalize(cross(pos1 - pos2, pos1 - pos3)); float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y; diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp index f6002a18d6e..2ed6156d26a 100644 --- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp @@ -167,13 +167,6 @@ void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { aabb.position = -size / 2; aabb.size = size; - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - for (int i = 0; i < 8; i++) { Vector3 ep = aabb.get_endpoint(i); internal_lines.push_back(probe->get_origin_offset()); diff --git a/platform/web/doc_classes/EditorExportPlatformWeb.xml b/platform/web/doc_classes/EditorExportPlatformWeb.xml index 6907bb1a256..dc7fc2c069a 100644 --- a/platform/web/doc_classes/EditorExportPlatformWeb.xml +++ b/platform/web/doc_classes/EditorExportPlatformWeb.xml @@ -87,10 +87,10 @@ If [code]false[/code], the exported game will not support threads. As a result, it is more prone to performance and audio issues, but will only require to be run on an HTTPS website. - If [code]true[/code], allows textures to be optimized for desktop through the S3TC algorithm. + If [code]true[/code], allows textures to be optimized for desktop through the S3TC/BPTC algorithm. - If [code]true[/code] allows textures to be optimized for mobile through the ETC2 algorithm. + If [code]true[/code] allows textures to be optimized for mobile through the ETC2/ASTC algorithm. diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index e52b1fdedb9..8aed2a18ef0 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -336,9 +336,11 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref &p_prese void EditorExportPlatformWeb::get_preset_features(const Ref &p_preset, List *r_features) const { if (p_preset->get("vram_texture_compression/for_desktop")) { r_features->push_back("s3tc"); + r_features->push_back("bptc"); } if (p_preset->get("vram_texture_compression/for_mobile")) { r_features->push_back("etc2"); + r_features->push_back("astc"); } if (p_preset->get("variant/thread_support").operator bool()) { r_features->push_back("threads"); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index c8a15c814d4..c9116c04d6d 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -6292,7 +6292,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID); - ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Failed to create main window."); + } joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index b9c843b1dc8..aa1f8c7cd67 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -187,8 +187,8 @@ ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const { AABB ReflectionProbe::get_aabb() const { AABB aabb; - aabb.position = -origin_offset; - aabb.size = origin_offset + size / 2; + aabb.position = -size / 2; + aabb.size = size; return aabb; } diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index 8084cace216..8d05c72c4d2 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -197,6 +197,9 @@ Vector MultiMesh::_get_custom_data_array() const { #endif // DISABLE_DEPRECATED void MultiMesh::set_buffer(const Vector &p_buffer) { + if (instance_count == 0) { + return; + } RS::get_singleton()->multimesh_set_buffer(multimesh, p_buffer); } diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp index 65783f4d1c0..0882a3d349c 100644 --- a/scene/resources/texture_rd.cpp +++ b/scene/resources/texture_rd.cpp @@ -199,7 +199,7 @@ void TextureLayeredRD::_set_texture_rd_rid(RID p_texture_rd_rid) { RS::TextureLayeredType rs_layer_type; RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid); - ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY); + ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY && tf.texture_type != RD::TEXTURE_TYPE_CUBE && tf.texture_type != RD::TEXTURE_TYPE_CUBE_ARRAY); ERR_FAIL_COND(tf.depth > 1); switch (layer_type) { case LAYERED_TYPE_2D_ARRAY: { diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 6cbd2479a32..4cdb38fd29c 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -624,6 +624,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]); @@ -654,41 +655,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)); } @@ -697,15 +725,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/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 7bd30d4876a..44c5dd725b1 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -2276,7 +2276,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co for (uint32_t v = 0; v < rb->get_view_count(); v++) { real_t fov = p_render_data->scene_data->cam_projection.get_fov(); real_t aspect = p_render_data->scene_data->cam_projection.get_aspect(); - real_t fovy = p_render_data->scene_data->cam_projection.get_fovy(fov, aspect); + real_t fovy = p_render_data->scene_data->cam_projection.get_fovy(fov, 1.0 / aspect); Vector2 jitter = p_render_data->scene_data->taa_jitter * Vector2(rb->get_internal_size()) * 0.5f; RendererRD::FSR2Effect::Parameters params; params.context = rb_data->get_fsr2_context(); 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 23d8a598019..27a41c36def 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1976,6 +1976,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const surf = surf->next; } } + + if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) { + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures); + } } void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 3b86386fc95..7bd7d4448a4 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -479,7 +479,8 @@ void main() { #endif if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) { - uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw)); + vec2 half_texpixel = draw_data.color_texture_pixel_size * 0.5; + uv = clamp(uv, draw_data.src_rect.xy + half_texpixel, draw_data.src_rect.xy + abs(draw_data.src_rect.zw) - half_texpixel); } #endif diff --git a/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl index fb35d3cde69..553637dc4fe 100644 --- a/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl @@ -152,10 +152,10 @@ void main() { float depth_scale; if (params.orthogonal) { - depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0; + depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0; depth_scale = params.unit_size; //remember depth is negative by default in OpenGL } else { - depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near)); depth_scale = params.unit_size / depth; //remember depth is negative by default in OpenGL } diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index d0cfe6a3b87..5a2ea19b2b6 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -513,6 +513,7 @@ void main() { shadow_sample.z = 1.0 + abs(shadow_sample.z); vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias); pos.z *= omni_lights.data[light_index].inv_radius; + pos.z = 1.0 - pos.z; pos.xy = pos.xy * 0.5 + 0.5; pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; 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 409a71dc782..205e5d20f7b 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 @@ -439,12 +439,12 @@ void main() { vertex_interp = vertex; #ifdef NORMAL_USED - normal_interp = normal; + normal_interp = normalize(normal); #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - tangent_interp = tangent; - binormal_interp = binormal; + tangent_interp = normalize(tangent); + binormal_interp = normalize(binormal); #endif #ifdef MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index 43befaf6c0d..7bc5257e828 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -130,7 +130,7 @@ class RenderSceneBuffersRD : public RenderSceneBuffers { h = hash_murmur3_one_32(p_val.layers, h); h = hash_murmur3_one_32(p_val.mipmap, h); h = hash_murmur3_one_32(p_val.mipmaps, h); - h = hash_murmur3_one_32(p_val.texture_view.format_override); + h = hash_murmur3_one_32(p_val.texture_view.format_override, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_r, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_g, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_b, h); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 2ce6c6c0a85..49558b13e3c 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1505,7 +1505,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_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 83e149a97e4..1afbd3a1b0c 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1845,6 +1845,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base); + } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; @@ -2878,6 +2881,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul for (const Instance *E : geom->lights) { InstanceLightData *light = static_cast(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; @@ -3097,7 +3104,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c continue; } - if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { + if (directional_lights.size() >= RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { break; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 4e2ca99ab51..1032403fb23 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -695,9 +695,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture if (format.texture_type == TEXTURE_TYPE_1D_ARRAY || format.texture_type == TEXTURE_TYPE_2D_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) { ERR_FAIL_COND_V_MSG(format.array_layers < 1, RID(), - "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); + "Number of layers must be equal or greater than 1 for arrays and cubemaps."); ERR_FAIL_COND_V_MSG((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) && (format.array_layers % 6) != 0, RID(), "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); + ERR_FAIL_COND_V_MSG(format.array_layers > driver->limit_get(LIMIT_MAX_TEXTURE_ARRAY_LAYERS), RID(), "Number of layers exceeds device maximum."); } else { format.array_layers = 1; } @@ -709,6 +710,28 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture format.height = format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY ? format.height : 1; format.depth = format.texture_type == TEXTURE_TYPE_3D ? format.depth : 1; + uint64_t size_max = 0; + switch (format.texture_type) { + case TEXTURE_TYPE_1D: + case TEXTURE_TYPE_1D_ARRAY: + size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_1D); + break; + case TEXTURE_TYPE_2D: + case TEXTURE_TYPE_2D_ARRAY: + size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_2D); + break; + case TEXTURE_TYPE_CUBE: + case TEXTURE_TYPE_CUBE_ARRAY: + size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_CUBE); + break; + case TEXTURE_TYPE_3D: + size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_3D); + break; + case TEXTURE_TYPE_MAX: + break; + } + ERR_FAIL_COND_V_MSG(format.width > size_max || format.height > size_max || format.depth > size_max, RID(), "Texture dimensions exceed device maximum."); + uint32_t required_mipmaps = get_image_required_mipmaps(format.width, format.height, format.depth); ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(), diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index 6ed98b2d63e..bd40bfdb1bd 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -261,7 +261,7 @@ Error RenderingDeviceDriver::_reflect_spirv(VectorView p_s } } - if (existing > 0) { + if (existing >= 0) { r_reflection.specialization_constants.write[existing].stages.set_flag(stage_flag); } else { r_reflection.specialization_constants.push_back(sconst);