From 57eb762bae0a24a4fb33e825e57f1e100bd9d354 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Thu, 3 Aug 2023 14:10:01 +0200 Subject: Add option to enable HDR rendering in 2D This is needed to allow 2D to fully make use of 3D effects (e.g. glow), and can be used to substantially improve quality of 2D rendering at the cost of performance Additionally, the 2D rendering pipeline is done in linear space (we skip linear_to_srgb conversion in 3D tonemapping) so the entire Viewport can be kept linear. This is necessary for proper HDR screen support in the future. --- .../rendering/renderer_rd/effects/tone_mapper.cpp | 26 +++--- .../rendering/renderer_rd/effects/tone_mapper.h | 25 +++--- servers/rendering/renderer_rd/environment/fog.cpp | 2 +- servers/rendering/renderer_rd/environment/sky.cpp | 2 +- .../forward_clustered/render_forward_clustered.cpp | 3 +- .../scene_shader_forward_clustered.cpp | 2 +- .../forward_mobile/render_forward_mobile.cpp | 3 +- .../forward_mobile/scene_shader_forward_mobile.cpp | 2 +- .../renderer_rd/renderer_canvas_render_rd.cpp | 73 ++++++++++++----- .../renderer_rd/renderer_canvas_render_rd.h | 3 + .../renderer_rd/renderer_compositor_rd.cpp | 4 +- .../rendering/renderer_rd/renderer_compositor_rd.h | 2 +- .../renderer_rd/renderer_scene_render_rd.cpp | 4 + servers/rendering/renderer_rd/shaders/blit.glsl | 13 ++- servers/rendering/renderer_rd/shaders/canvas.glsl | 15 +++- .../renderer_rd/shaders/canvas_uniforms_inc.glsl | 2 +- .../renderer_rd/shaders/effects/copy.glsl | 2 +- .../renderer_rd/shaders/effects/tonemap.glsl | 48 ++++++----- .../renderer_rd/storage_rd/material_storage.cpp | 8 +- .../renderer_rd/storage_rd/material_storage.h | 4 +- .../renderer_rd/storage_rd/particles_storage.cpp | 2 +- .../renderer_rd/storage_rd/texture_storage.cpp | 93 +++++++++++++++++----- .../renderer_rd/storage_rd/texture_storage.h | 7 +- 23 files changed, 241 insertions(+), 104 deletions(-) (limited to 'servers/rendering/renderer_rd') diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 821960bb3b..9c8e8dd231 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -89,12 +89,12 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; tonemap.push_constant.bcs[0] = p_settings.brightness; tonemap.push_constant.bcs[1] = p_settings.contrast; tonemap.push_constant.bcs[2] = p_settings.saturation; - tonemap.push_constant.use_glow = p_settings.use_glow; + tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; tonemap.push_constant.glow_intensity = p_settings.glow_intensity; tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something @@ -114,19 +114,21 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; tonemap.push_constant.exposure = p_settings.exposure; tonemap.push_constant.white = p_settings.white; tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; - tonemap.push_constant.use_fxaa = p_settings.use_fxaa; - tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0; + tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; + if (p_settings.view_count > 1) { // Use MULTIVIEW versions mode += 6; @@ -185,13 +187,13 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; tonemap.push_constant.bcs[0] = p_settings.brightness; tonemap.push_constant.bcs[1] = p_settings.contrast; tonemap.push_constant.bcs[2] = p_settings.saturation; ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses."); - tonemap.push_constant.use_glow = p_settings.use_glow; + tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; if (p_settings.view_count > 1) { @@ -200,16 +202,18 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; tonemap.push_constant.exposure = p_settings.exposure; tonemap.push_constant.white = p_settings.white; tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; - tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; + tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h index afd2f8e401..a1a99f931f 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.h +++ b/servers/rendering/renderer_rd/effects/tone_mapper.h @@ -59,14 +59,23 @@ private: TONEMAP_MODE_MAX }; + enum { + TONEMAP_FLAG_USE_BCS = (1 << 0), + TONEMAP_FLAG_USE_GLOW = (1 << 1), + TONEMAP_FLAG_USE_AUTO_EXPOSURE = (1 << 2), + TONEMAP_FLAG_USE_COLOR_CORRECTION = (1 << 3), + TONEMAP_FLAG_USE_FXAA = (1 << 4), + TONEMAP_FLAG_USE_DEBANDING = (1 << 5), + TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 6), + }; + struct TonemapPushConstant { float bcs[3]; // 12 - 12 - uint32_t use_bcs; // 4 - 16 + uint32_t flags; // 4 - 16 - uint32_t use_glow; // 4 - 20 - uint32_t use_auto_exposure; // 4 - 24 - uint32_t use_color_correction; // 4 - 28 - uint32_t tonemapper; // 4 - 32 + float pixel_size[2]; // 8 - 24 + uint32_t tonemapper; // 4 - 28 + uint32_t pad; // 4 - 32 uint32_t glow_texture_size[2]; // 8 - 40 float glow_intensity; // 4 - 44 @@ -79,10 +88,6 @@ private: float white; // 4 - 88 float auto_exposure_scale; // 4 - 92 float luminance_multiplier; // 4 - 96 - - float pixel_size[2]; // 8 - 104 - uint32_t use_fxaa; // 4 - 108 - uint32_t use_debanding; // 4 - 112 }; /* tonemap actually writes to a framebuffer, which is @@ -141,6 +146,8 @@ public: bool use_debanding = false; Vector2i texture_size; uint32_t view_count = 1; + + bool convert_to_srgb = false; }; void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 98d826b1f9..8402cc7444 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -143,7 +143,7 @@ Vector3 Fog::fog_volume_get_size(RID p_fog_volume) const { bool Fog::FogMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { uniform_set_updated = true; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true, true); } Fog::FogMaterialData::~FogMaterialData() { diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index ebf3c5f619..431bf9cb84 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -185,7 +185,7 @@ bool SkyRD::SkyMaterialData::update_parameters(const HashMapuniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true, true); } SkyRD::SkyMaterialData::~SkyMaterialData() { 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 7bca1dc3be..9b05bf0c64 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1769,7 +1769,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co case RS::ENV_BG_CANVAS: { if (!is_reflection_probe) { RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); - copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear); } keep_color = true; } break; 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 298a6c0752..12f8f6a366 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 @@ -436,7 +436,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); } SceneShaderForwardClustered::MaterialData::~MaterialData() { 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 2053c3a9a6..1ea1997f3e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -803,7 +803,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb_data.is_valid()) { RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS); RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); - copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear); } keep_color = true; } break; 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 e4498ac533..32d2289f75 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 @@ -388,7 +388,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); } SceneShaderForwardMobile::MaterialData::~MaterialData() { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index eb33f296d0..773ea9098a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -363,7 +363,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI bool use_normal; bool use_specular; - bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); + bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, bool(push_constant.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR), uniform_set, size, specular_shininess, use_normal, use_specular); //something odd happened if (!success) { _bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size); @@ -421,6 +421,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend _update_transform_2d_to_mat2x3(base_transform, push_constant.world); Color base_color = p_item->final_modulate; + bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_render_target); for (int i = 0; i < 4; i++) { push_constant.modulation[i] = 0; @@ -441,6 +442,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.lights[3] = 0; uint32_t base_flags = 0; + base_flags |= use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0; uint16_t light_count = 0; PipelineLightMode light_mode; @@ -566,10 +568,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.flags |= FLAGS_USE_LCD; } - push_constant.modulation[0] = rect->modulate.r * base_color.r; - push_constant.modulation[1] = rect->modulate.g * base_color.g; - push_constant.modulation[2] = rect->modulate.b * base_color.b; - push_constant.modulation[3] = rect->modulate.a * base_color.a; + Color modulated = rect->modulate * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -618,10 +625,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend } } - push_constant.modulation[0] = np->color.r * base_color.r; - push_constant.modulation[1] = np->color.g * base_color.g; - push_constant.modulation[2] = np->color.b * base_color.b; - push_constant.modulation[3] = np->color.a * base_color.a; + Color modulated = np->color * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -676,10 +688,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend _bind_canvas_texture(p_draw_list, polygon->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size); - push_constant.modulation[0] = base_color.r; - push_constant.modulation[1] = base_color.g; - push_constant.modulation[2] = base_color.b; - push_constant.modulation[3] = base_color.a; + Color color = base_color; + if (use_linear_colors) { + color = color.srgb_to_linear(); + } + + push_constant.modulation[0] = color.r; + push_constant.modulation[1] = color.g; + push_constant.modulation[2] = color.b; + push_constant.modulation[3] = color.a; for (int j = 0; j < 4; j++) { push_constant.src_rect[j] = 0; @@ -718,6 +735,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y; Color col = primitive->colors[j] * base_color; + if (use_linear_colors) { + col = col.srgb_to_linear(); + } push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -732,6 +752,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y; Color col = primitive->colors[j + 1] * base_color; + if (use_linear_colors) { + col = col.srgb_to_linear(); + } push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -849,10 +872,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh); static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP }; - push_constant.modulation[0] = base_color.r * modulate.r; - push_constant.modulation[1] = base_color.g * modulate.g; - push_constant.modulation[2] = base_color.b * modulate.b; - push_constant.modulation[3] = base_color.a * modulate.a; + Color modulated = modulate * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; for (int j = 0; j < 4; j++) { push_constant.src_rect[j] = 0; @@ -1113,8 +1141,9 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) { pipeline_variants = &material_data->shader_data->pipeline_variants; // Update uniform set. - if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set. - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET); + RID uniform_set = texture_storage->render_target_is_using_hdr(p_to_render_target) ? material_data->uniform_set : material_data->uniform_set_srgb; + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { // Material may not have a uniform set. + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set, MATERIAL_UNIFORM_SET); material_data->set_as_used(); } } else { @@ -2235,12 +2264,14 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_ bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { RendererCanvasRenderRD *canvas_singleton = static_cast(RendererCanvasRender::singleton); - - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false); + bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false, RD::BARRIER_MASK_ALL_BARRIERS); + bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false, RD::BARRIER_MASK_ALL_BARRIERS); + return uniform_set_changed || uniform_set_srgb_changed; } RendererCanvasRenderRD::CanvasMaterialData::~CanvasMaterialData() { free_parameters_uniform_set(uniform_set); + free_parameters_uniform_set(uniform_set_srgb); } RendererRD::MaterialStorage::MaterialData *RendererCanvasRenderRD::_create_material_func(CanvasShaderData *p_shader) { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 1116bed6e4..af8736a445 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -75,6 +75,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { FLAGS_CLIP_RECT_UV = (1 << 9), FLAGS_TRANSPOSE_RECT = (1 << 10), + FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11), + FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), FLAGS_USING_PARTICLES = (1 << 13), @@ -195,6 +197,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct CanvasMaterialData : public RendererRD::MaterialStorage::MaterialData { CanvasShaderData *shader_data = nullptr; RID uniform_set; + RID uniform_set_srgb; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 870da3c321..4ccd2aa322 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -81,6 +81,7 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2; blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale; blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio; + blit.push_constant.convert_to_srgb = texture_storage->render_target_is_using_hdr(p_render_targets[i].render_target); RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); @@ -171,7 +172,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color RID texture = texture_storage->texture_allocate(); texture_storage->texture_2d_initialize(texture, p_image); - RID rd_texture = texture_storage->texture_get_rd_texture(texture); + RID rd_texture = texture_storage->texture_get_rd_texture(texture, false); RD::SamplerState sampler_state; sampler_state.min_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST; @@ -237,6 +238,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color blit.push_constant.k2 = 0; blit.push_constant.upscale = 1.0; blit.push_constant.aspect_ratio = 1.0; + blit.push_constant.convert_to_srgb = false; RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 14fb4e6340..705fb9e8e5 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -80,7 +80,7 @@ protected: float upscale; float aspect_ratio; uint32_t layer; - uint32_t pad1; + uint32_t convert_to_srgb; }; struct Blit { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 646bdc5436..07947f29e5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -552,6 +552,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = rb->get_view_count(); + tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target); + RID dest_fb; if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) { // If we use FSR to upscale we need to write our result into an intermediate buffer. @@ -647,6 +649,8 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = rb->get_view_count(); + tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(rb->get_render_target()); + tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap); RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl index 14f190a49f..d451647bec 100644 --- a/servers/rendering/renderer_rd/shaders/blit.glsl +++ b/servers/rendering/renderer_rd/shaders/blit.glsl @@ -45,7 +45,7 @@ layout(push_constant, std140) uniform Pos { float upscale; float aspect_ratio; uint layer; - uint pad1; + bool convert_to_srgb; } data; @@ -59,6 +59,13 @@ layout(binding = 0) uniform sampler2DArray src_rt; layout(binding = 0) uniform sampler2D src_rt; #endif +vec3 linear_to_srgb(vec3 color) { + // If going to srgb, clamp from 0 to 1. + color = clamp(color, vec3(0.0), vec3(1.0)); + const vec3 a = vec3(0.055f); + return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); +} + void main() { #ifdef APPLY_LENS_DISTORTION vec2 coords = uv * 2.0 - 1.0; @@ -94,4 +101,8 @@ void main() { #else color = texture(src_rt, uv); #endif + + if (data.convert_to_srgb) { + color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion. + } } diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 6270450c15..31c5aadc88 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -36,6 +36,12 @@ layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ #GLOBALS +#ifdef USE_ATTRIBUTES +vec3 srgb_to_linear(vec3 color) { + return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045))); +} +#endif + void main() { vec4 instance_custom = vec4(0.0); #ifdef USE_PRIMITIVE @@ -65,7 +71,11 @@ void main() { #elif defined(USE_ATTRIBUTES) vec2 vertex = vertex_attrib; - vec4 color = color_attrib * draw_data.modulation; + vec4 color = color_attrib; + if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) { + color.rgb = srgb_to_linear(color.rgb); + } + color *= draw_data.modulation; vec2 uv = uv_attrib; uvec4 bones = bone_attrib; @@ -563,9 +573,6 @@ void main() { } vec4 base_color = color; - if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) { - color = vec4(0.0); //invisible by default due to using light mask - } #ifdef MODE_LIGHT_ONLY float light_only_alpha = 0.0; diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 2dd5abb75f..7ac7cf9c07 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -12,7 +12,7 @@ #define FLAGS_CLIP_RECT_UV (1 << 9) #define FLAGS_TRANSPOSE_RECT (1 << 10) -#define FLAGS_USING_LIGHT_MASK (1 << 11) +#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11) #define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) #define FLAGS_USING_PARTICLES (1 << 13) diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl index 3a82861057..2b3d27b000 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl @@ -57,7 +57,7 @@ layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffe #elif defined(DST_IMAGE_8BIT) layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #else -layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +layout(rgba16f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #endif #ifdef MODE_GAUSSIAN_BLUR diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl index 52aee8b648..29abff2911 100644 --- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -57,14 +57,21 @@ layout(set = 3, binding = 0) uniform sampler2D source_color_correction; layout(set = 3, binding = 0) uniform sampler3D source_color_correction; #endif +#define FLAG_USE_BCS (1 << 0) +#define FLAG_USE_GLOW (1 << 1) +#define FLAG_USE_AUTO_EXPOSURE (1 << 2) +#define FLAG_USE_COLOR_CORRECTION (1 << 3) +#define FLAG_USE_FXAA (1 << 4) +#define FLAG_USE_DEBANDING (1 << 5) +#define FLAG_CONVERT_TO_SRGB (1 << 6) + layout(push_constant, std430) uniform Params { vec3 bcs; - bool use_bcs; + uint flags; - bool use_glow; - bool use_auto_exposure; - bool use_color_correction; + vec2 pixel_size; uint tonemapper; + uint pad; uvec2 glow_texture_size; float glow_intensity; @@ -77,10 +84,6 @@ layout(push_constant, std430) uniform Params { float white; float auto_exposure_scale; float luminance_multiplier; - - vec2 pixel_size; - bool use_fxaa; - bool use_debanding; } params; @@ -318,10 +321,12 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi if (params.glow_mode == GLOW_MODE_ADD) { return color + glow; } else if (params.glow_mode == GLOW_MODE_SCREEN) { - //need color clamping + // Needs color clamping. + glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f)); return max((color + glow) - (color * glow), vec3(0.0)); } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) { - //need color clamping + // Needs color clamping. + glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f)); glow = glow * vec3(0.5f) + vec3(0.5f); color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); @@ -439,7 +444,7 @@ void main() { float exposure = params.exposure; #ifndef SUBPASS - if (params.use_auto_exposure) { + if (bool(params.flags & FLAG_USE_AUTO_EXPOSURE)) { exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_scale); } #endif @@ -448,12 +453,12 @@ void main() { // Early Tonemap & SRGB Conversion #ifndef SUBPASS - if (params.use_fxaa) { + if (bool(params.flags & FLAG_USE_FXAA)) { // FXAA must be performed before glow to preserve the "bleed" effect of glow. color.rgb = do_fxaa(color.rgb, exposure, uv_interp); } - if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { + if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; if (params.glow_map_strength > 0.001) { glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); @@ -464,11 +469,12 @@ void main() { color.rgb = apply_tonemapping(color.rgb, params.white); - color.rgb = linear_to_srgb(color.rgb); // regular linear -> SRGB conversion - + if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) { + color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion. + } #ifndef SUBPASS // Glow - if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { + if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; if (params.glow_map_strength > 0.001) { glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); @@ -476,7 +482,9 @@ void main() { // high dynamic range -> SRGB glow = apply_tonemapping(glow, params.white); - glow = linear_to_srgb(glow); + if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) { + glow = linear_to_srgb(glow); + } color.rgb = apply_glow(color.rgb, glow); } @@ -484,15 +492,15 @@ void main() { // Additional effects - if (params.use_bcs) { + if (bool(params.flags & FLAG_USE_BCS)) { color.rgb = apply_bcs(color.rgb, params.bcs); } - if (params.use_color_correction) { + if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) { color.rgb = apply_color_correction(color.rgb); } - if (params.use_debanding) { + if (bool(params.flags & FLAG_USE_DEBANDING)) { // Debanding should be done at the end of tonemapping, but before writing to the LDR buffer. // Otherwise, we're adding noise to an already-quantized image. color.rgb += screen_space_dither(gl_FragCoord.xy); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index d055f01009..a96893570e 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -751,7 +751,7 @@ MaterialStorage::MaterialData::~MaterialData() { } } -void MaterialStorage::MaterialData::update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { +void MaterialStorage::MaterialData::update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material) { TextureStorage *texture_storage = TextureStorage::get_singleton(); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -917,7 +917,7 @@ void MaterialStorage::MaterialData::update_textures(const HashMaprd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; #ifdef TOOLS_ENABLED - if (tex->detect_3d_callback && p_use_linear_color) { + if (tex->detect_3d_callback && p_3d_material) { tex->detect_3d_callback(tex->detect_3d_callback_ud); } if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { @@ -986,7 +986,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se } } -bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier) { +bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier) { if ((uint32_t)ubo_data.size() != p_ubo_size) { p_uniform_dirty = true; if (uniform_buffer.is_valid()) { @@ -1033,7 +1033,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap< } if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color); + update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color, p_3d_material); } if (p_ubo_size == 0 && (p_texture_uniforms.size() == 0)) { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index b6da3df783..ae97f43a3c 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -78,7 +78,7 @@ public: struct MaterialData { Vector render_target_cache; void update_uniform_buffer(const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color); - void update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color); + void update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material); void set_as_used(); virtual void set_render_priority(int p_priority) = 0; @@ -87,7 +87,7 @@ public: virtual ~MaterialData(); //to be used internally by update_parameters, in the most common configuration of material parameters - bool update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + bool update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); void free_parameters_uniform_set(RID p_uniform_set); private: diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 8f647be5c9..0a91672544 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1629,7 +1629,7 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() { } bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true, false); } ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index d84f6e6850..f009318d24 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -46,9 +46,11 @@ void TextureStorage::CanvasTexture::clear_sets() { } for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { - if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j])) { - RD::get_singleton()->free(uniform_sets[i][j]); - uniform_sets[i][j] = RID(); + for (int k = 0; k < 2; k++) { + if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) { + RD::get_singleton()->free(uniform_sets[i][j][k]); + uniform_sets[i][j][k] = RID(); + } } } } @@ -641,7 +643,7 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS: ct->clear_sets(); } -bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { +bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { MaterialStorage *material_storage = MaterialStorage::get_singleton(); CanvasTexture *ct = nullptr; @@ -674,7 +676,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat; ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false); - RID uniform_set = ct->uniform_sets[filter][repeat]; + RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)]; if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) { //create and update Vector uniforms; @@ -688,7 +690,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); ct->size_cache = Size2i(1, 1); } else { - u.append_id(t->rd_texture); + u.append_id(t->rd_texture_srgb.is_valid() && (p_use_srgb) ? t->rd_texture_srgb : t->rd_texture); ct->size_cache = Size2i(t->width_2d, t->height_2d); if (t->render_target) { t->render_target->was_used = true; @@ -741,7 +743,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte } uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set); - ct->uniform_sets[filter][repeat] = uniform_set; + ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set; ct->cleared_cache = false; } @@ -1268,7 +1270,35 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { #endif Vector data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); ERR_FAIL_COND_V(data.size() == 0, Ref()); - Ref image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + Ref image; + + // Expand RGB10_A2 into RGBAH. This is needed for capturing viewport data + // when using the mobile renderer with HDR mode on. + if (tex->rd_format == RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32) { + Vector new_data; + new_data.resize(data.size() * 2); + uint16_t *ndp = (uint16_t *)new_data.ptr(); + + uint32_t *ptr = (uint32_t *)data.ptr(); + uint32_t num_pixels = data.size() / 4; + + for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { + uint32_t px = ptr[ofs]; + uint32_t r = (px & 0x3FF); + uint32_t g = ((px >> 10) & 0x3FF); + uint32_t b = ((px >> 20) & 0x3FF); + uint32_t a = ((px >> 30) & 0x3); + + ndp[ofs * 4 + 0] = Math::make_half_float(float(r) / 1023.0); + ndp[ofs * 4 + 1] = Math::make_half_float(float(g) / 1023.0); + ndp[ofs * 4 + 2] = Math::make_half_float(float(b) / 1023.0); + ndp[ofs * 4 + 3] = Math::make_half_float(float(a) / 3.0); + } + image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, new_data); + } else { + image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + } + ERR_FAIL_COND_V(image->is_empty(), Ref()); if (tex->format != tex->validated_format) { image->convert(tex->format); @@ -3020,10 +3050,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { if (rt->size.width == 0 || rt->size.height == 0) { return; } - //until we implement support for HDR monitors (and render target is attached to screen), this is enough. - rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; - rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + if (rt->use_hdr) { + rt->color_format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format(); + rt->color_format_srgb = rt->color_format; + rt->image_format = rt->is_transparent ? Image::FORMAT_RGBAH : Image::FORMAT_RGBH; + } else { + rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + } RD::TextureFormat rd_color_attachment_format; RD::TextureView rd_view; @@ -3106,6 +3141,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { tex->rd_format = rt->color_format; tex->rd_format_srgb = rt->color_format_srgb; tex->format = rt->image_format; + tex->validated_format = rt->use_hdr ? Image::FORMAT_RGBAH : Image::FORMAT_RGBA8; Vector proxies = tex->proxies; //make a copy, since update may change it for (int i = 0; i < proxies.size(); i++) { @@ -3328,6 +3364,25 @@ RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) con return rt->msaa; } +void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_use_hdr == rt->use_hdr) { + return; + } + + rt->use_hdr = p_use_hdr; + _update_render_target(rt); +} + +bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->use_hdr; +} + RID TextureStorage::render_target_get_rd_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -3404,7 +3459,7 @@ bool TextureStorage::render_target_is_clear_requested(RID p_render_target) { Color TextureStorage::render_target_get_clear_request_color(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, Color()); - return rt->clear_color; + return rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color; } void TextureStorage::render_target_disable_clear_request(RID p_render_target) { @@ -3420,7 +3475,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { return; } Vector clear_colors; - clear_colors.push_back(rt->clear_color); + clear_colors.push_back(rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color); RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); RD::get_singleton()->draw_list_end(); rt->clear_requested = false; @@ -3735,7 +3790,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons // TODO figure out stereo support here if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, !rt->use_hdr, true); } else { copy_effects->copy_to_fb_rect(rt->color, rt->backbuffer_fb, region, false, false, false, false, RID(), false, true); } @@ -3759,7 +3814,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons RID mipmap = rt->backbuffer_mipmaps[i]; if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true); + copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr); } else { copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size); } @@ -3789,9 +3844,9 @@ void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const } } - //single texture copy for backbuffer + // Single texture copy for backbuffer. if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, true); + copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, !rt->use_hdr); } else { copy_effects->set_color_raster(rt->backbuffer_mipmap0, p_color, region); } @@ -3833,7 +3888,7 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, RID mipmap = rt->backbuffer_mipmaps[i]; if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true); + copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr); } else { copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size); } diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 6df6faa40a..2137c5f383 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -96,7 +96,7 @@ private: RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2]; Size2i size_cache = Size2i(1, 1); bool use_normal_cache = false; @@ -341,6 +341,7 @@ private: Image::Format image_format = Image::FORMAT_L8; bool is_transparent = false; + bool use_hdr = false; bool sdf_enabled = false; @@ -474,7 +475,7 @@ public: virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; - bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); + bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); /* Texture API */ @@ -717,6 +718,8 @@ public: virtual void render_target_set_as_unused(RID p_render_target) override; virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override; virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override; + virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) override; + virtual bool render_target_is_using_hdr(RID p_render_target) const override; void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); -- cgit v1.2.3