mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Add debanding to SMAA and apply debanding before spatial upscalers.
This commit is contained in:
parent
17fb6e3bd0
commit
5a3e69d16e
5 changed files with 125 additions and 11 deletions
|
@ -181,6 +181,11 @@ void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_colo
|
|||
|
||||
smaa.blend_push_constant.inv_size[0] = inv_size.x;
|
||||
smaa.blend_push_constant.inv_size[1] = inv_size.y;
|
||||
if (debanding_mode == DEBANDING_MODE_8_BIT) {
|
||||
smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_8_BIT_DEBANDING;
|
||||
} else if (debanding_mode == DEBANDING_MODE_10_BIT) {
|
||||
smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_10_BIT_DEBANDING;
|
||||
}
|
||||
|
||||
RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
struct SMAAEdgePushConstant {
|
||||
float inv_size[2];
|
||||
float threshold;
|
||||
float reserved;
|
||||
float pad;
|
||||
};
|
||||
|
||||
struct SMAAWeightPushConstant {
|
||||
|
@ -71,7 +71,13 @@ private:
|
|||
|
||||
struct SMAABlendPushConstant {
|
||||
float inv_size[2];
|
||||
float reserved[2];
|
||||
uint32_t flags;
|
||||
float pad;
|
||||
};
|
||||
|
||||
enum SMAABlendFlags {
|
||||
SMAA_BLEND_FLAG_USE_8_BIT_DEBANDING = (1 << 0),
|
||||
SMAA_BLEND_FLAG_USE_10_BIT_DEBANDING = (1 << 1),
|
||||
};
|
||||
|
||||
struct SMAAEffect {
|
||||
|
@ -103,6 +109,13 @@ public:
|
|||
|
||||
void allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers);
|
||||
void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer);
|
||||
|
||||
enum DebandingMode {
|
||||
DEBANDING_MODE_DISABLED,
|
||||
DEBANDING_MODE_8_BIT,
|
||||
DEBANDING_MODE_10_BIT,
|
||||
};
|
||||
DebandingMode debanding_mode = DEBANDING_MODE_DISABLED;
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
||||
|
|
|
@ -685,36 +685,48 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
|
|||
|
||||
RID dest_fb;
|
||||
RD::DataFormat dest_fb_format;
|
||||
RD::DataFormat format_for_debanding;
|
||||
if (spatial_upscaler != nullptr || use_smaa) {
|
||||
// If we use a spatial upscaler to upscale or SMAA to antialias we need to write our result into an intermediate buffer.
|
||||
// Note that this is cached so we only create the texture the first time.
|
||||
dest_fb_format = _render_buffers_get_color_format();
|
||||
RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), dest_fb_format, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
|
||||
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
|
||||
if (use_smaa) {
|
||||
format_for_debanding = dest_fb_format;
|
||||
} else {
|
||||
// Debanding is currently not supported when using spatial upscaling, so apply it before scaling.
|
||||
// This produces suboptimal results because the image will be modified by spatial upscaling after
|
||||
// debanding has been applied. Ideally, debanding should be applied as the final step before quantization
|
||||
// to integer values, but in the case of MetalFX, it may not be worth the performance cost of creating a new
|
||||
// intermediate buffer. In the case of FSR 1.0, the work of adding debanding support hasn't been done yet.
|
||||
// Assume that the DataFormat that will be used by spatial_upscaler is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, tonemap.convert_to_srgb);
|
||||
}
|
||||
} else {
|
||||
// If we do a bilinear upscale we just render into our render target and our shader will upscale automatically.
|
||||
// Target size in this case is lying as we never get our real target size communicated.
|
||||
// Bit nasty but...
|
||||
|
||||
if (dest_is_msaa_2d) {
|
||||
// Assume that the DataFormat of render_target_get_rd_texture_msaa is the same as render_target_get_color_format.
|
||||
dest_fb_format = texture_storage->render_target_get_color_format(using_hdr, tonemap.convert_to_srgb);
|
||||
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target));
|
||||
// Assume that the DataFormat of render_target_get_rd_texture_msaa is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, tonemap.convert_to_srgb);
|
||||
texture_storage->render_target_set_msaa_needs_resolve(render_target, true); // Make sure this gets resolved.
|
||||
} else {
|
||||
// Assume that the DataFormat of render_target_get_rd_framebuffer is the same as render_target_get_color_format.
|
||||
dest_fb_format = texture_storage->render_target_get_color_format(using_hdr, tonemap.convert_to_srgb);
|
||||
dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
|
||||
// Assume that the DataFormat of render_target_get_rd_framebuffer is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, tonemap.convert_to_srgb);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb->get_use_debanding()) {
|
||||
if (dest_fb_format >= RD::DATA_FORMAT_R8_UNORM && dest_fb_format <= RD::DATA_FORMAT_A8B8G8R8_SRGB_PACK32) {
|
||||
if (_is_8bit_data_format(format_for_debanding)) {
|
||||
tonemap.debanding_mode = RendererRD::ToneMapper::TonemapSettings::DebandingMode::DEBANDING_MODE_8_BIT;
|
||||
} else if (dest_fb_format >= RD::DATA_FORMAT_A2R10G10B10_UNORM_PACK32 && dest_fb_format <= RD::DATA_FORMAT_A2B10G10R10_SINT_PACK32) {
|
||||
} else if (_is_10bit_data_format(format_for_debanding)) {
|
||||
tonemap.debanding_mode = RendererRD::ToneMapper::TonemapSettings::DebandingMode::DEBANDING_MODE_10_BIT;
|
||||
} else {
|
||||
// In this case, debanding will be handled later when quantizing to an integer data format. (During blit, for example.)
|
||||
// In this case, debanding will be handled later when quantizing to an integer data format. (During blit or SMAA, for example.)
|
||||
tonemap.debanding_mode = RendererRD::ToneMapper::TonemapSettings::DebandingMode::DEBANDING_MODE_DISABLED;
|
||||
}
|
||||
} else {
|
||||
|
@ -730,6 +742,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
|
|||
RENDER_TIMESTAMP("SMAA");
|
||||
RD::get_singleton()->draw_command_begin_label("SMAA");
|
||||
|
||||
bool using_hdr = texture_storage->render_target_is_using_hdr(render_target);
|
||||
RID dest_fb;
|
||||
if (spatial_upscaler) {
|
||||
rb->create_texture(SNAME("SMAA"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
|
||||
|
@ -739,30 +752,78 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
|
|||
RID source_texture = rb->get_texture_slice(SNAME("Tonemapper"), SNAME("destination"), v, 0);
|
||||
|
||||
RID dest_texture;
|
||||
RD::DataFormat format_for_debanding;
|
||||
if (spatial_upscaler) {
|
||||
dest_texture = rb->get_texture_slice(SNAME("SMAA"), SNAME("destination"), v, 0);
|
||||
// Debanding is currently not supported when using spatial upscaling, so apply it before scaling.
|
||||
// This produces suboptimal results because the image will be modified by spatial upscaling after
|
||||
// debanding has been applied. Ideally, debanding should be applied as the final step before quantization
|
||||
// to integer values, but in the case of MetalFX, it may not be worth the performance cost of creating a new
|
||||
// intermediate buffer. In the case of FSR 1.0, the work of adding debanding support hasn't been done yet.
|
||||
// Assume that the DataFormat that will be used by spatial_upscaler is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, !using_hdr);
|
||||
} else {
|
||||
dest_texture = texture_storage->render_target_get_rd_texture_slice(render_target, v);
|
||||
// Assume that the DataFormat is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, !using_hdr);
|
||||
}
|
||||
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
|
||||
|
||||
if (rb->get_use_debanding()) {
|
||||
if (_is_8bit_data_format(format_for_debanding)) {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_8_BIT;
|
||||
} else if (_is_10bit_data_format(format_for_debanding)) {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_10_BIT;
|
||||
} else {
|
||||
// In this case, debanding will be handled later when quantizing to an integer data format. (During blit, for example.)
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_DISABLED;
|
||||
}
|
||||
} else {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_DISABLED;
|
||||
}
|
||||
|
||||
smaa->process(rb, source_texture, dest_fb);
|
||||
}
|
||||
} else {
|
||||
RID source_texture = rb->get_texture(SNAME("Tonemapper"), SNAME("destination"));
|
||||
RD::DataFormat format_for_debanding;
|
||||
|
||||
if (spatial_upscaler) {
|
||||
RID dest_texture = rb->create_texture(SNAME("SMAA"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
|
||||
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
|
||||
// Debanding is currently not supported when using spatial upscaling, so apply it before scaling.
|
||||
// This produces suboptimal results because the image will be modified by spatial upscaling after
|
||||
// debanding has been applied. Ideally, debanding should be applied as the final step before quantization
|
||||
// to integer values, but in the case of MetalFX, it may not be worth the performance cost of creating a new
|
||||
// intermediate buffer. In the case of FSR 1.0, the work of adding debanding support hasn't been done yet.
|
||||
// Assume that the DataFormat that will be used by spatial_upscaler is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, !using_hdr);
|
||||
} else {
|
||||
if (dest_is_msaa_2d) {
|
||||
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target));
|
||||
// Assume that the DataFormat of render_target_get_rd_texture_msaa is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, !using_hdr);
|
||||
texture_storage->render_target_set_msaa_needs_resolve(render_target, true); // Make sure this gets resolved.
|
||||
} else {
|
||||
dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
|
||||
// Assume that the DataFormat of render_target_get_rd_framebuffer is the same as render_target_get_color_format.
|
||||
format_for_debanding = texture_storage->render_target_get_color_format(using_hdr, !using_hdr);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb->get_use_debanding()) {
|
||||
if (_is_8bit_data_format(format_for_debanding)) {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_8_BIT;
|
||||
} else if (_is_10bit_data_format(format_for_debanding)) {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_10_BIT;
|
||||
} else {
|
||||
// In this case, debanding will be handled later when quantizing to an integer data format. (During blit, for example.)
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_DISABLED;
|
||||
}
|
||||
} else {
|
||||
smaa->debanding_mode = RendererRD::SMAA::DebandingMode::DEBANDING_MODE_DISABLED;
|
||||
}
|
||||
|
||||
smaa->process(rb, source_texture, dest_fb);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,14 @@ protected:
|
|||
void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);
|
||||
void _disable_clear_request(const RenderDataRD *p_render_data);
|
||||
|
||||
_FORCE_INLINE_ bool _is_8bit_data_format(RD::DataFormat p_data_format) {
|
||||
return p_data_format >= RD::DATA_FORMAT_R8_UNORM && p_data_format <= RD::DATA_FORMAT_A8B8G8R8_SRGB_PACK32;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool _is_10bit_data_format(RD::DataFormat p_data_format) {
|
||||
return p_data_format >= RD::DATA_FORMAT_A2R10G10B10_UNORM_PACK32 && p_data_format <= RD::DATA_FORMAT_A2B10G10R10_SINT_PACK32;
|
||||
}
|
||||
|
||||
// needed for a single argument calls (material and uv2)
|
||||
PagedArrayPool<RenderGeometryInstance *> cull_argument_pool;
|
||||
PagedArray<RenderGeometryInstance *> cull_argument; //need this to exist
|
||||
|
|
|
@ -34,7 +34,7 @@ layout(location = 1) out vec4 offset;
|
|||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec2 inv_size;
|
||||
vec2 reserved;
|
||||
vec2 pad;
|
||||
}
|
||||
params;
|
||||
|
||||
|
@ -62,9 +62,13 @@ layout(set = 1, binding = 0) uniform sampler2D blend_tex;
|
|||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
#define FLAG_USE_8_BIT_DEBANDING (1 << 0)
|
||||
#define FLAG_USE_10_BIT_DEBANDING (1 << 1)
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec2 inv_size;
|
||||
vec2 reserved;
|
||||
uint flags;
|
||||
float pad;
|
||||
}
|
||||
params;
|
||||
|
||||
|
@ -95,6 +99,22 @@ void SMAAMovc(bvec4 cond, inout vec4 variable, vec4 value) {
|
|||
SMAAMovc(cond.zw, variable.zw, value.zw);
|
||||
}
|
||||
|
||||
// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
|
||||
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
|
||||
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
|
||||
// This dithering must be applied after encoding changes (linear/nonlinear) have been applied
|
||||
// as the final step before quantization from floating point to integer values.
|
||||
vec3 screen_space_dither(vec2 frag_coord, float bit_alignment_diviser) {
|
||||
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
|
||||
// Removed the time component to avoid passing time into this shader.
|
||||
vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord));
|
||||
dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0));
|
||||
|
||||
// Subtract 0.5 to avoid slightly brightening the whole viewport.
|
||||
// Use a dither strength of 100% rather than the 37.5% suggested by the original source.
|
||||
return (dither.rgb - 0.5) / bit_alignment_diviser;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 a;
|
||||
a.x = texture(blend_tex, offset.xy).a;
|
||||
|
@ -120,4 +140,11 @@ void main() {
|
|||
out_color.rgb = linear_to_srgb(out_color.rgb);
|
||||
out_color.a = texture(color_tex, tex_coord).a;
|
||||
}
|
||||
if (bool(params.flags & FLAG_USE_8_BIT_DEBANDING)) {
|
||||
// Divide by 255 to align to 8-bit quantization.
|
||||
out_color.rgb += screen_space_dither(gl_FragCoord.xy, 255.0);
|
||||
} else if (bool(params.flags & FLAG_USE_10_BIT_DEBANDING)) {
|
||||
// Divide by 1023 to align to 10-bit quantization.
|
||||
out_color.rgb += screen_space_dither(gl_FragCoord.xy, 1023.0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue