Optimize glow and tonemap gather step in the mobile renderer

Mobile devices are typically bandwidth bound which means we need to do as few texture samples as possible.

They typically use TBDR GPUs which means that all rendering takes place on special optimized tiles. As a side effect, reading back memory from tile to VRAM is really slow, especially on Mali devices.

This commit uses a technique where you do a small blur while downsampling, and then another small blur while upsampling to get really high quality glow. While this doesn't reduce the renderpass count very much, it does reduce the texture read bandwidth by almost 10 times. Overall glow was more texture-read bound than memory write, bound, so this was a huge win.

A side effect of this new technique is that we can gather the glow as we upsample instead of gathering the glow in the final tonemap pass. Doing so allows us to significantly reduce the cost of the tonemap pass as well.
This commit is contained in:
clayjohn
2025-09-01 14:43:37 -07:00
parent 084d5d407e
commit 2e59cb41f4
22 changed files with 1524 additions and 519 deletions

View File

@@ -53,8 +53,9 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
Vector<String> blur_modes;
blur_modes.push_back("\n#define MODE_MIPMAP\n"); // BLUR_MIPMAP
blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE
blur_modes.push_back("\n#define MODE_GLOW_GATHER\n"); // BLUR_MODE_GAUSSIAN_GLOW_GATHER
blur_modes.push_back("\n#define MODE_GLOW_DOWNSAMPLE\n"); // BLUR_MODE_GAUSSIAN_GLOW_DOWNSAMPLE
blur_modes.push_back("\n#define MODE_GLOW_UPSAMPLE\n"); // BLUR_MODE_GAUSSIAN_GLOW_UPSAMPLE
blur_modes.push_back("\n#define MODE_COPY\n"); // BLUR_MODE_COPY
blur_modes.push_back("\n#define MODE_SET_COLOR\n"); // BLUR_MODE_SET_COLOR
@@ -66,6 +67,15 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
blur_raster.pipelines[i].setup(blur_raster.shader.version_get_shader(blur_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}
RD::SamplerState sampler_state;
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER;
sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER;
sampler_state.border_color = RD::SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
blur_raster.glow_sampler = RD::get_singleton()->sampler_create(sampler_state);
} else {
// not used in clustered
for (int i = 0; i < BLUR_MODE_MAX; i++) {
@@ -319,6 +329,7 @@ CopyEffects::~CopyEffects() {
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
RD::get_singleton()->free_rid(blur_raster.glow_sampler);
cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
filter.raster_shader.version_free(filter.shader_version);
roughness.raster_shader.version_free(roughness.shader_version);
@@ -733,8 +744,8 @@ void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_textu
BlurRasterMode blur_mode = BLUR_MODE_GAUSSIAN_BLUR;
blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.y);
blur_raster.push_constant.dest_pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.dest_pixel_size[1] = 1.0 / float(p_size.y);
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -805,7 +816,7 @@ void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, con
RD::get_singleton()->compute_list_end();
}
void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_scale) {
void CopyEffects::gaussian_glow_downsample_raster(RID p_source_rd_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
@@ -813,16 +824,14 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
RID half_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_half_texture);
RID dest_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_dest_texture);
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
BlurRasterMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW;
uint32_t base_flags = 0;
BlurRasterMode blur_mode = p_first_pass ? BLUR_MODE_GAUSSIAN_GLOW_GATHER : BLUR_MODE_GAUSSIAN_GLOW_DOWNSAMPLE;
blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.y);
blur_raster.push_constant.source_pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.source_pixel_size[1] = 1.0 / float(p_size.y);
blur_raster.push_constant.glow_strength = p_strength;
blur_raster.push_constant.glow_bloom = p_bloom;
@@ -832,45 +841,62 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
blur_raster.push_constant.glow_white = 0; //actually unused
blur_raster.push_constant.glow_luminance_cap = p_luminance_cap;
blur_raster.push_constant.glow_auto_exposure_scale = p_auto_exposure_scale; //unused also
blur_raster.push_constant.luminance_multiplier = p_luminance_multiplier;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
RD::Uniform u_half_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_half_texture }));
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ blur_raster.glow_sampler, p_source_rd_texture }));
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode);
ERR_FAIL_COND(shader.is_null());
//HORIZONTAL
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(half_framebuffer)));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
if (p_auto_exposure.is_valid() && p_first_pass) {
RD::Uniform u_auto_exposure(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_auto_exposure }));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_auto_exposure), 1);
}
blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
blur_mode = BLUR_MODE_GAUSSIAN_GLOW;
void CopyEffects::gaussian_glow_upsample_raster(RID p_source_rd_texture, RID p_dest_texture, RID p_blend_texture, float p_luminance_multiplier, const Size2i &p_source_size, const Size2i &p_dest_size, float p_level, float p_base_strength, bool p_use_debanding) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode);
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
RID dest_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_dest_texture);
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
BlurRasterMode blur_mode = BLUR_MODE_GAUSSIAN_GLOW_UPSAMPLE;
blur_raster.push_constant.source_pixel_size[0] = 1.0 / float(p_source_size.x);
blur_raster.push_constant.source_pixel_size[1] = 1.0 / float(p_source_size.y);
blur_raster.push_constant.dest_pixel_size[0] = 1.0 / float(p_dest_size.x);
blur_raster.push_constant.dest_pixel_size[1] = 1.0 / float(p_dest_size.y);
blur_raster.push_constant.luminance_multiplier = p_luminance_multiplier;
blur_raster.push_constant.level = p_level * 0.5;
blur_raster.push_constant.glow_strength = p_base_strength;
uint32_t spec_constant = p_use_debanding ? 1 : 0;
spec_constant |= p_level > 0.01 ? 2 : 0;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
RD::Uniform u_blend_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_blend_texture }));
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode);
ERR_FAIL_COND(shader.is_null());
//VERTICAL
draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture), 0);
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer), false, 0, spec_constant));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_blend_rd_texture), 1);
blur_raster.push_constant.flags = base_flags;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
@@ -925,8 +951,8 @@ void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture
BlurRasterMode mode = BLUR_MIPMAP;
blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.y);
blur_raster.push_constant.dest_pixel_size[0] = 1.0 / float(p_size.x);
blur_raster.push_constant.dest_pixel_size[1] = 1.0 / float(p_size.y);
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);

View File

@@ -59,8 +59,9 @@ private:
BLUR_MIPMAP,
BLUR_MODE_GAUSSIAN_BLUR,
BLUR_MODE_GAUSSIAN_GLOW,
BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
BLUR_MODE_GAUSSIAN_GLOW_GATHER,
BLUR_MODE_GAUSSIAN_GLOW_DOWNSAMPLE,
BLUR_MODE_GAUSSIAN_GLOW_UPSAMPLE,
BLUR_MODE_COPY,
BLUR_MODE_SET_COLOR,
@@ -69,15 +70,16 @@ private:
};
enum {
BLUR_FLAG_HORIZONTAL = (1 << 0),
BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1),
BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2),
};
struct BlurRasterPushConstant {
float pixel_size[2];
float dest_pixel_size[2];
float source_pixel_size[2];
float pad[2];
uint32_t flags;
uint32_t pad;
float level;
//glow
float glow_strength;
@@ -88,12 +90,7 @@ private:
float glow_exposure;
float glow_white;
float glow_luminance_cap;
float glow_auto_exposure_scale;
float luminance_multiplier;
float res1;
float res2;
float res3;
};
struct BlurRaster {
@@ -101,6 +98,7 @@ private:
BlurRasterShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[BLUR_MODE_MAX];
RID glow_sampler;
} blur_raster;
// Copy shader
@@ -337,7 +335,8 @@ public:
void gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, const Size2i &p_size, bool p_8bit_dst = false);
void gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_region, const Size2i &p_size);
void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
void gaussian_glow_raster(RID p_source_rd_texture, RID p_half_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
void gaussian_glow_downsample_raster(RID p_source_rd_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0);
void gaussian_glow_upsample_raster(RID p_source_rd_texture, RID p_dest_texture, RID p_blend_texture, float p_luminance_multiplier, const Size2i &p_source_size, const Size2i &p_dest_size, float p_level, float p_base_strength, bool p_use_debanding);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);

View File

@@ -157,7 +157,7 @@ void SMAA::allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers) {
p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_STENCIL, smaa.stencil_format, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
}
void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer) {
void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer, bool p_use_debanding) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -181,11 +181,7 @@ 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;
}
smaa.blend_push_constant.use_debanding = p_use_debanding;
RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);

View File

@@ -71,7 +71,7 @@ private:
struct SMAABlendPushConstant {
float inv_size[2];
uint32_t flags;
uint32_t use_debanding;
float pad;
};
@@ -108,14 +108,7 @@ public:
~SMAA();
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;
void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer, bool p_use_debanding);
};
} // namespace RendererRD

View File

@@ -35,24 +35,54 @@
using namespace RendererRD;
ToneMapper::ToneMapper() {
{
ToneMapper::ToneMapper(bool p_use_mobile_version) {
using_mobile_version = p_use_mobile_version;
if (using_mobile_version) {
// Initialize tonemapper
Vector<String> tonemap_modes;
tonemap_modes.push_back("\n");
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n");
// multiview versions of our shaders
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap_mobile.shader.initialize(tonemap_modes);
if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
tonemap_mobile.shader.set_variant_enabled(TONEMAP_MOBILE_MODE_NORMAL_MULTIVIEW, false);
tonemap_mobile.shader.set_variant_enabled(TONEMAP_MOBILE_MODE_1D_LUT_MULTIVIEW, false);
tonemap_mobile.shader.set_variant_enabled(TONEMAP_MOBILE_MODE_SUBPASS_MULTIVIEW, false);
tonemap_mobile.shader.set_variant_enabled(TONEMAP_MOBILE_MODE_SUBPASS_1D_LUT_MULTIVIEW, false);
}
tonemap_mobile.shader_version = tonemap_mobile.shader.version_create();
for (int i = 0; i < TONEMAP_MODE_MAX; i++) {
if (tonemap_mobile.shader.is_variant_enabled(i)) {
tonemap_mobile.pipelines[i].setup(tonemap_mobile.shader.version_get_shader(tonemap_mobile.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
} else {
tonemap_mobile.pipelines[i].clear();
}
}
} else {
// Initialize tonemapper
Vector<String> tonemap_modes;
tonemap_modes.push_back("\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n");
// multiview versions of our shaders
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
@@ -61,8 +91,6 @@ ToneMapper::ToneMapper() {
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false);
}
tonemap.shader_version = tonemap.shader.version_create();
@@ -78,10 +106,15 @@ ToneMapper::ToneMapper() {
}
ToneMapper::~ToneMapper() {
tonemap.shader.version_free(tonemap.shader_version);
if (using_mobile_version) {
tonemap_mobile.shader.version_free(tonemap_mobile.shader_version);
} else {
tonemap.shader.version_free(tonemap.shader_version);
}
}
void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
ERR_FAIL_COND_MSG(using_mobile_version, "Can't use the non mobile version of the tonemapper with the Mobile renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -125,8 +158,6 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0;
if (p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_8_BIT) {
tonemap.push_constant.flags |= TONEMAP_FLAG_USE_8_BIT_DEBANDING;
} else if (p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_10_BIT) {
tonemap.push_constant.flags |= TONEMAP_FLAG_USE_10_BIT_DEBANDING;
}
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;
@@ -135,7 +166,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
if (p_settings.view_count > 1) {
// Use USE_MULTIVIEW versions
mode += 6;
mode += 4;
}
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -182,57 +213,61 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
RD::get_singleton()->draw_list_end();
}
void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
void ToneMapper::tonemapper_mobile(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
ERR_FAIL_COND_MSG(!using_mobile_version, "Can't use the mobile version of the tonemapper with the clustered renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
memset(&tonemap_mobile.push_constant, 0, sizeof(TonemapPushConstantMobile));
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_mobile.push_constant.bcs[0] = p_settings.brightness;
tonemap_mobile.push_constant.bcs[1] = p_settings.contrast;
tonemap_mobile.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.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0;
tonemap_mobile.push_constant.src_pixel_size[0] = 1.0 / p_settings.texture_size.x;
tonemap_mobile.push_constant.src_pixel_size[1] = 1.0 / p_settings.texture_size.y;
tonemap_mobile.push_constant.dest_pixel_size[0] = 1.0 / p_settings.dest_texture_size.x;
tonemap_mobile.push_constant.dest_pixel_size[1] = 1.0 / p_settings.dest_texture_size.y;
tonemap_mobile.push_constant.glow_intensity = p_settings.glow_intensity;
tonemap_mobile.push_constant.glow_map_strength = p_settings.glow_map_strength;
tonemap_mobile.push_constant.exposure = p_settings.exposure;
tonemap_mobile.push_constant.white = p_settings.white;
tonemap_mobile.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
uint32_t spec_constant = 0;
spec_constant |= p_settings.use_bcs ? TONEMAP_MOBILE_FLAG_USE_BCS : 0;
spec_constant |= p_settings.use_glow ? TONEMAP_MOBILE_FLAG_USE_GLOW : 0;
spec_constant |= p_settings.glow_map_strength > 0.01 ? TONEMAP_MOBILE_FLAG_USE_GLOW_MAP : 0;
spec_constant |= p_settings.use_color_correction ? TONEMAP_MOBILE_FLAG_USE_COLOR_CORRECTION : 0;
spec_constant |= p_settings.use_fxaa ? TONEMAP_MOBILE_FLAG_USE_FXAA : 0;
spec_constant |= p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_8_BIT ? TONEMAP_MOBILE_FLAG_USE_8_BIT_DEBANDING : 0;
spec_constant |= p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_10_BIT ? TONEMAP_MOBILE_FLAG_USE_10_BIT_DEBANDING : 0;
spec_constant |= p_settings.convert_to_srgb ? TONEMAP_MOBILE_FLAG_CONVERT_TO_SRGB : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_LINEAR ? TONEMAP_MOBILE_FLAG_TONEMAPPER_LINEAR : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_REINHARD ? TONEMAP_MOBILE_FLAG_TONEMAPPER_REINHARD : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_FILMIC ? TONEMAP_MOBILE_FLAG_TONEMAPPER_FILMIC : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_ACES ? TONEMAP_MOBILE_FLAG_TONEMAPPER_ACES : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_AGX ? TONEMAP_MOBILE_FLAG_TONEMAPPER_AGX : 0;
spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_ADDITIVE ? TONEMAP_MOBILE_FLAG_GLOW_MODE_ADD : 0;
spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_SCREEN ? TONEMAP_MOBILE_FLAG_GLOW_MODE_SCREEN : 0;
spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT ? TONEMAP_MOBILE_FLAG_GLOW_MODE_SOFTLIGHT : 0;
spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_REPLACE ? TONEMAP_MOBILE_FLAG_GLOW_MODE_REPLACE : 0;
spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? TONEMAP_MOBILE_FLAG_GLOW_MODE_MIX : 0;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MOBILE_MODE_1D_LUT : TONEMAP_MOBILE_MODE_NORMAL;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
if (p_settings.view_count > 1) {
// Use USE_MULTIVIEW versions
mode += 6;
mode += 4;
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
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.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
if (p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_8_BIT) {
tonemap.push_constant.flags |= TONEMAP_FLAG_USE_8_BIT_DEBANDING;
} else if (p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_10_BIT) {
tonemap.push_constant.flags |= TONEMAP_FLAG_USE_10_BIT_DEBANDING;
}
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);
RD::Uniform u_source_color;
u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
u_source_color.binding = 0;
u_source_color.append_id(p_source_color);
RD::Uniform u_exposure_texture;
u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_exposure_texture.binding = 0;
u_exposure_texture.append_id(default_sampler);
u_exposure_texture.append_id(p_settings.exposure_texture);
RD::Uniform u_source_color(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_color }));
RD::Uniform u_glow_texture;
u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
@@ -252,15 +287,102 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
u_color_correction_texture.append_id(default_sampler);
u_color_correction_texture.append_id(p_settings.color_correction_texture);
RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode);
RID shader = tonemap_mobile.shader.version_get_shader(tonemap_mobile.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap_mobile.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass(), spec_constant));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_glow_texture, u_glow_map), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_color_correction_texture), 2);
RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap_mobile.push_constant, sizeof(TonemapPushConstantMobile));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
void ToneMapper::tonemapper_subpass(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses.");
memset(&tonemap_mobile.push_constant, 0, sizeof(TonemapPushConstantMobile));
tonemap_mobile.push_constant.bcs[0] = p_settings.brightness;
tonemap_mobile.push_constant.bcs[1] = p_settings.contrast;
tonemap_mobile.push_constant.bcs[2] = p_settings.saturation;
tonemap_mobile.push_constant.src_pixel_size[0] = 1.0 / p_settings.texture_size.x;
tonemap_mobile.push_constant.src_pixel_size[1] = 1.0 / p_settings.texture_size.y;
tonemap_mobile.push_constant.glow_intensity = p_settings.glow_intensity;
tonemap_mobile.push_constant.glow_map_strength = p_settings.glow_map_strength;
tonemap_mobile.push_constant.exposure = p_settings.exposure;
tonemap_mobile.push_constant.white = p_settings.white;
tonemap_mobile.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
uint32_t spec_constant = 0;
spec_constant |= p_settings.use_bcs ? TONEMAP_MOBILE_FLAG_USE_BCS : 0;
//spec_constant |= p_settings.use_glow ? TONEMAP_MOBILE_FLAG_USE_GLOW : 0;
//spec_constant |= p_settings.glow_map_strength > 0.01 ? TONEMAP_MOBILE_FLAG_USE_GLOW_MAP : 0;
//spec_constant |= p_settings.use_color_correction ? TONEMAP_MOBILE_FLAG_USE_COLOR_CORRECTION : 0;
//spec_constant |= p_settings.use_fxaa ? TONEMAP_MOBILE_FLAG_USE_FXAA : 0;
spec_constant |= p_settings.debanding_mode == TonemapSettings::DEBANDING_MODE_8_BIT ? TONEMAP_MOBILE_FLAG_USE_8_BIT_DEBANDING : 0;
spec_constant |= p_settings.convert_to_srgb ? TONEMAP_MOBILE_FLAG_CONVERT_TO_SRGB : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_LINEAR ? TONEMAP_MOBILE_FLAG_TONEMAPPER_LINEAR : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_REINHARD ? TONEMAP_MOBILE_FLAG_TONEMAPPER_REINHARD : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_FILMIC ? TONEMAP_MOBILE_FLAG_TONEMAPPER_FILMIC : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_ACES ? TONEMAP_MOBILE_FLAG_TONEMAPPER_ACES : 0;
spec_constant |= p_settings.tonemap_mode == RS::ENV_TONE_MAPPER_AGX ? TONEMAP_MOBILE_FLAG_TONEMAPPER_AGX : 0;
//spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_ADDITIVE ? TONEMAP_MOBILE_FLAG_GLOW_MODE_ADD : 0;
//spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_SCREEN ? TONEMAP_MOBILE_FLAG_GLOW_MODE_SCREEN : 0;
//spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT ? TONEMAP_MOBILE_FLAG_GLOW_MODE_SOFTLIGHT : 0;
//spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_REPLACE ? TONEMAP_MOBILE_FLAG_GLOW_MODE_REPLACE : 0;
//spec_constant |= p_settings.glow_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? TONEMAP_MOBILE_FLAG_GLOW_MODE_MIX : 0;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MOBILE_MODE_SUBPASS_1D_LUT : TONEMAP_MOBILE_MODE_SUBPASS;
if (p_settings.view_count > 1) {
// Use USE_MULTIVIEW versions
mode += 4;
}
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);
RD::Uniform u_source_color;
u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
u_source_color.binding = 0;
u_source_color.append_id(p_source_color);
RD::Uniform u_glow_texture;
u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_texture.binding = 0;
u_glow_texture.append_id(default_mipmap_sampler);
u_glow_texture.append_id(p_settings.glow_texture);
RD::Uniform u_glow_map;
u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_map.binding = 1;
u_glow_map.append_id(default_mipmap_sampler);
u_glow_map.append_id(p_settings.glow_map);
RD::Uniform u_color_correction_texture;
u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_color_correction_texture.binding = 0;
u_color_correction_texture.append_id(default_sampler);
u_color_correction_texture.append_id(p_settings.color_correction_texture);
RID shader = tonemap_mobile.shader.version_get_shader(tonemap_mobile.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap_mobile.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass(), spec_constant));
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 1, u_glow_texture, u_glow_map), 1); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 2, u_color_correction_texture), 2);
RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap_mobile.push_constant, sizeof(TonemapPushConstantMobile));
RD::get_singleton()->draw_list_draw(p_subpass_draw_list, false, 1u, 3u);
}

View File

@@ -32,6 +32,7 @@
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/tonemap.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/tonemap_mobile.glsl.gen.h"
#include "servers/rendering/rendering_server.h"
@@ -39,35 +40,68 @@ namespace RendererRD {
class ToneMapper {
private:
bool using_mobile_version = false;
enum TonemapMode {
TONEMAP_MODE_NORMAL,
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
TONEMAP_MODE_1D_LUT,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
TONEMAP_MODE_SUBPASS,
TONEMAP_MODE_SUBPASS_1D_LUT,
TONEMAP_MODE_NORMAL_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW,
TONEMAP_MODE_1D_LUT_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW,
TONEMAP_MODE_SUBPASS_MULTIVIEW,
TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW,
TONEMAP_MODE_MAX
};
enum {
enum TonemapModeMobile {
TONEMAP_MOBILE_MODE_NORMAL,
TONEMAP_MOBILE_MODE_1D_LUT,
TONEMAP_MOBILE_MODE_SUBPASS,
TONEMAP_MOBILE_MODE_SUBPASS_1D_LUT,
TONEMAP_MOBILE_MODE_NORMAL_MULTIVIEW,
TONEMAP_MOBILE_MODE_1D_LUT_MULTIVIEW,
TONEMAP_MOBILE_MODE_SUBPASS_MULTIVIEW,
TONEMAP_MOBILE_MODE_SUBPASS_1D_LUT_MULTIVIEW,
TONEMAP_MOBILE_MODE_MAX
};
enum Flags {
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_8_BIT_DEBANDING = (1 << 5),
TONEMAP_FLAG_USE_10_BIT_DEBANDING = (1 << 6),
TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 7),
};
enum FlagsMobile {
TONEMAP_MOBILE_FLAG_USE_BCS = (1 << 0),
TONEMAP_MOBILE_FLAG_USE_GLOW = (1 << 1),
TONEMAP_MOBILE_FLAG_USE_GLOW_MAP = (1 << 2),
TONEMAP_MOBILE_FLAG_USE_COLOR_CORRECTION = (1 << 3),
TONEMAP_MOBILE_FLAG_USE_FXAA = (1 << 4),
TONEMAP_MOBILE_FLAG_USE_8_BIT_DEBANDING = (1 << 5),
TONEMAP_MOBILE_FLAG_USE_10_BIT_DEBANDING = (1 << 6),
TONEMAP_MOBILE_FLAG_CONVERT_TO_SRGB = (1 << 7),
TONEMAP_MOBILE_FLAG_TONEMAPPER_LINEAR = (1 << 8),
TONEMAP_MOBILE_FLAG_TONEMAPPER_REINHARD = (1 << 9),
TONEMAP_MOBILE_FLAG_TONEMAPPER_FILMIC = (1 << 10),
TONEMAP_MOBILE_FLAG_TONEMAPPER_ACES = (1 << 11),
TONEMAP_MOBILE_FLAG_TONEMAPPER_AGX = (1 << 12),
TONEMAP_MOBILE_FLAG_GLOW_MODE_ADD = (1 << 13),
TONEMAP_MOBILE_FLAG_GLOW_MODE_SCREEN = (1 << 14),
TONEMAP_MOBILE_FLAG_GLOW_MODE_SOFTLIGHT = (1 << 15),
TONEMAP_MOBILE_FLAG_GLOW_MODE_REPLACE = (1 << 16),
TONEMAP_MOBILE_FLAG_GLOW_MODE_MIX = (1 << 17),
};
struct TonemapPushConstant {
float bcs[3]; // 12 - 12
uint32_t flags; // 4 - 16
@@ -89,6 +123,19 @@ private:
float luminance_multiplier; // 4 - 96
};
struct TonemapPushConstantMobile {
float bcs[3]; // 12 - 12
float luminance_multiplier; // 4 - 16
float src_pixel_size[2]; // 8 - 24
float dest_pixel_size[2]; // 8 - 32
float glow_intensity; // 4 - 36
float glow_map_strength; // 4 - 40
float exposure; // 4 - 44
float white; // 4 - 48
};
/* tonemap actually writes to a framebuffer, which is
* better to do using the raster pipeline rather than
* compute, as that framebuffer might be in different formats
@@ -100,21 +147,20 @@ private:
PipelineCacheRD pipelines[TONEMAP_MODE_MAX];
} tonemap;
struct TonemapMobile {
TonemapPushConstantMobile push_constant;
TonemapMobileShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[TONEMAP_MOBILE_MODE_MAX];
} tonemap_mobile;
public:
ToneMapper();
ToneMapper(bool p_use_mobile_version);
~ToneMapper();
struct TonemapSettings {
bool use_glow = false;
enum GlowMode {
GLOW_MODE_ADD,
GLOW_MODE_SCREEN,
GLOW_MODE_SOFTLIGHT,
GLOW_MODE_REPLACE,
GLOW_MODE_MIX
};
GlowMode glow_mode = GLOW_MODE_SCREEN;
RS::EnvironmentGlowBlendMode glow_mode = RS::ENV_GLOW_BLEND_MODE_SCREEN;
float glow_intensity = 0.3;
float glow_map_strength = 0.0f;
float glow_levels[7] = { 1.0, 0.8, 0.4, 0.1, 0.0, 0.0, 0.0 };
@@ -149,13 +195,15 @@ public:
};
DebandingMode debanding_mode = DEBANDING_MODE_DISABLED;
Vector2i texture_size;
Vector2i dest_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);
void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
void tonemapper_mobile(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
void tonemapper_subpass(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
};
} // namespace RendererRD