initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
77
servers/rendering/renderer_rd/effects/SCsub
Normal file
77
servers/rendering/renderer_rd/effects/SCsub
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
import methods
|
||||
|
||||
Import("env")
|
||||
|
||||
env_effects = env.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
thirdparty_dir = "#thirdparty/amd-fsr2/"
|
||||
thirdparty_sources = ["ffx_assert.cpp", "ffx_fsr2.cpp"]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_effects.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
|
||||
def areatex_builder(target, source, env):
|
||||
buffer = methods.get_buffer(str(source[0]))
|
||||
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(f"""\
|
||||
#define AREATEX_WIDTH 160
|
||||
#define AREATEX_HEIGHT 560
|
||||
#define AREATEX_PITCH (AREATEX_WIDTH * 2)
|
||||
#define AREATEX_SIZE (AREATEX_HEIGHT * AREATEX_PITCH)
|
||||
|
||||
inline constexpr const unsigned char area_tex_png[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
""")
|
||||
|
||||
|
||||
env.CommandNoCache("smaa_area_tex.gen.h", "#thirdparty/smaa/AreaTex.png", env.Run(areatex_builder))
|
||||
|
||||
|
||||
def searchtex_builder(target, source, env):
|
||||
buffer = methods.get_buffer(str(source[0]))
|
||||
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(f"""\
|
||||
#define SEARCHTEX_WIDTH 64
|
||||
#define SEARCHTEX_HEIGHT 16
|
||||
#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
|
||||
#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
|
||||
|
||||
inline constexpr const unsigned char search_tex_png[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
""")
|
||||
|
||||
|
||||
env.CommandNoCache("smaa_search_tex.gen.h", "#thirdparty/smaa/SearchTex.png", env.Run(searchtex_builder))
|
||||
|
||||
# This flag doesn't actually control anything GCC specific in FSR2. It determines
|
||||
# if symbols should be exported, which is not required for Godot.
|
||||
env_effects.Append(CPPDEFINES=["FFX_GCC"])
|
||||
|
||||
env_thirdparty = env_effects.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
|
||||
env.servers_sources += thirdparty_obj
|
||||
|
||||
# Godot source files
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_effects.add_source_files(module_obj, "*.cpp")
|
||||
if env["metal"]:
|
||||
env_effects.add_source_files(module_obj, "metal_fx.mm")
|
||||
env.servers_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
497
servers/rendering/renderer_rd/effects/bokeh_dof.cpp
Normal file
497
servers/rendering/renderer_rd/effects/bokeh_dof.cpp
Normal file
@@ -0,0 +1,497 @@
|
||||
/**************************************************************************/
|
||||
/* bokeh_dof.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "bokeh_dof.h"
|
||||
#include "copy_effects.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
#include "servers/rendering/storage/camera_attributes_storage.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
BokehDOF::BokehDOF(bool p_prefer_raster_effects) {
|
||||
prefer_raster_effects = p_prefer_raster_effects;
|
||||
|
||||
// Initialize bokeh
|
||||
Vector<String> bokeh_modes;
|
||||
bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
|
||||
bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n#define OUTPUT_WEIGHT\n");
|
||||
bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
|
||||
bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n#define OUTPUT_WEIGHT\n");
|
||||
bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
|
||||
bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n#define OUTPUT_WEIGHT\n");
|
||||
bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
|
||||
if (prefer_raster_effects) {
|
||||
bokeh.raster_shader.initialize(bokeh_modes);
|
||||
|
||||
bokeh.shader_version = bokeh.raster_shader.version_create();
|
||||
|
||||
const int att_count[BOKEH_MAX] = { 1, 2, 1, 2, 1, 2, 1 };
|
||||
for (int i = 0; i < BOKEH_MAX; i++) {
|
||||
RD::PipelineColorBlendState blend_state = (i == BOKEH_COMPOSITE) ? RD::PipelineColorBlendState::create_blend(att_count[i]) : RD::PipelineColorBlendState::create_disabled(att_count[i]);
|
||||
bokeh.raster_pipelines[i].setup(bokeh.raster_shader.version_get_shader(bokeh.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
|
||||
}
|
||||
} else {
|
||||
bokeh.compute_shader.initialize(bokeh_modes);
|
||||
bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_BOX_NOWEIGHT, false);
|
||||
bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, false);
|
||||
bokeh.shader_version = bokeh.compute_shader.version_create();
|
||||
|
||||
for (int i = 0; i < BOKEH_MAX; i++) {
|
||||
if (bokeh.compute_shader.is_variant_enabled(i)) {
|
||||
bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < BOKEH_MAX; i++) {
|
||||
bokeh.raster_pipelines[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BokehDOF::~BokehDOF() {
|
||||
if (prefer_raster_effects) {
|
||||
bokeh.raster_shader.version_free(bokeh.shader_version);
|
||||
} else {
|
||||
bokeh.compute_shader.version_free(bokeh.shader_version);
|
||||
}
|
||||
}
|
||||
|
||||
void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
|
||||
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of bokeh depth of field with the mobile 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);
|
||||
|
||||
bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
|
||||
float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
|
||||
float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
|
||||
bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
|
||||
float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
|
||||
float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
|
||||
float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
|
||||
|
||||
bool use_jitter = RSG::camera_attributes->camera_attributes_get_dof_blur_use_jitter();
|
||||
RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
|
||||
RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
|
||||
|
||||
// setup our push constant
|
||||
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
|
||||
bokeh.push_constant.blur_far_active = dof_far;
|
||||
bokeh.push_constant.blur_far_begin = dof_far_begin;
|
||||
bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size; // Only used with non-physically-based.
|
||||
bokeh.push_constant.use_physical_far = dof_far_size < 0.0;
|
||||
bokeh.push_constant.blur_size_far = bokeh_size; // Only used with physically-based.
|
||||
|
||||
bokeh.push_constant.blur_near_active = dof_near;
|
||||
bokeh.push_constant.blur_near_begin = dof_near_begin;
|
||||
bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size; // Only used with non-physically-based.
|
||||
bokeh.push_constant.use_physical_near = dof_near_size < 0.0;
|
||||
bokeh.push_constant.blur_size_near = bokeh_size; // Only used with physically-based.
|
||||
|
||||
bokeh.push_constant.use_jitter = use_jitter;
|
||||
bokeh.push_constant.jitter_seed = Math::randf() * 1000.0;
|
||||
|
||||
bokeh.push_constant.z_near = p_cam_znear;
|
||||
bokeh.push_constant.z_far = p_cam_zfar;
|
||||
bokeh.push_constant.orthogonal = p_cam_orthogonal;
|
||||
bokeh.push_constant.blur_size = (dof_near_size < 0.0 && dof_far_size < 0.0) ? 32 : bokeh_size; // Cap with physically-based to keep performance reasonable.
|
||||
|
||||
bokeh.push_constant.second_pass = false;
|
||||
bokeh.push_constant.half_size = false;
|
||||
|
||||
bokeh.push_constant.blur_scale = 0.5;
|
||||
|
||||
// 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_base_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.base_texture }));
|
||||
RD::Uniform u_depth_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.depth_texture }));
|
||||
RD::Uniform u_secondary_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.secondary_texture }));
|
||||
RD::Uniform u_half_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[0] }));
|
||||
RD::Uniform u_half_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[1] }));
|
||||
|
||||
RD::Uniform u_base_image(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.base_texture);
|
||||
RD::Uniform u_secondary_image(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.secondary_texture);
|
||||
RD::Uniform u_half_image0(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.half_texture[0]);
|
||||
RD::Uniform u_half_image1(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.half_texture[1]);
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
/* FIRST PASS */
|
||||
// The alpha channel of the source color texture is filled with the expected circle size
|
||||
// If used for DOF far, the size is positive, if used for near, its negative.
|
||||
|
||||
RID shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BLUR_SIZE);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]);
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_texture), 1);
|
||||
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
|
||||
//second pass
|
||||
BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
|
||||
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[mode]);
|
||||
|
||||
static const int quality_samples[4] = { 6, 12, 12, 24 };
|
||||
|
||||
bokeh.push_constant.steps = quality_samples[blur_quality];
|
||||
|
||||
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
|
||||
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image0), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 1);
|
||||
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
|
||||
bokeh.push_constant.half_size = true;
|
||||
bokeh.push_constant.blur_size *= 0.5;
|
||||
|
||||
} else {
|
||||
//medium and high quality use full size
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_secondary_image), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
//third pass
|
||||
bokeh.push_constant.second_pass = true;
|
||||
|
||||
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image1), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);
|
||||
} else {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_secondary_texture), 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
|
||||
//forth pass, upscale for low quality
|
||||
|
||||
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture1), 1);
|
||||
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
|
||||
bokeh.push_constant.half_size = false;
|
||||
bokeh.push_constant.second_pass = false;
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
|
||||
}
|
||||
} else {
|
||||
//circle
|
||||
|
||||
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BOKEH_CIRCULAR);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
//second pass
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
|
||||
|
||||
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
|
||||
|
||||
bokeh.push_constant.steps = 0;
|
||||
bokeh.push_constant.blur_scale = quality_scale[blur_quality];
|
||||
|
||||
//circle always runs in half size, otherwise too expensive
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image0), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 1);
|
||||
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
|
||||
bokeh.push_constant.half_size = true;
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
//circle is just one pass, then upscale
|
||||
|
||||
// upscale
|
||||
|
||||
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);
|
||||
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
|
||||
bokeh.push_constant.half_size = false;
|
||||
bokeh.push_constant.second_pass = false;
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
|
||||
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't blur-based depth of field 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);
|
||||
|
||||
bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
|
||||
float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
|
||||
float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
|
||||
bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
|
||||
float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
|
||||
float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
|
||||
float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
|
||||
|
||||
RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
|
||||
RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
|
||||
|
||||
// setup our base push constant
|
||||
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
|
||||
|
||||
bokeh.push_constant.orthogonal = p_cam_orthogonal;
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.width;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.height;
|
||||
bokeh.push_constant.z_far = p_cam_zfar;
|
||||
bokeh.push_constant.z_near = p_cam_znear;
|
||||
|
||||
bokeh.push_constant.second_pass = false;
|
||||
bokeh.push_constant.half_size = false;
|
||||
bokeh.push_constant.blur_size = bokeh_size;
|
||||
|
||||
// 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_base_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.base_texture }));
|
||||
RD::Uniform u_depth_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.depth_texture }));
|
||||
RD::Uniform u_secondary_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.secondary_texture }));
|
||||
RD::Uniform u_half_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[0] }));
|
||||
RD::Uniform u_half_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[1] }));
|
||||
RD::Uniform u_weight_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[0] }));
|
||||
RD::Uniform u_weight_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[1] }));
|
||||
RD::Uniform u_weight_texture2(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[2] }));
|
||||
RD::Uniform u_weight_texture3(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[3] }));
|
||||
|
||||
if (dof_far || dof_near) {
|
||||
if (dof_far) {
|
||||
bokeh.push_constant.blur_far_active = true;
|
||||
bokeh.push_constant.blur_far_begin = dof_far_begin;
|
||||
bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size;
|
||||
}
|
||||
|
||||
if (dof_near) {
|
||||
bokeh.push_constant.blur_near_active = true;
|
||||
bokeh.push_constant.blur_near_begin = dof_near_begin;
|
||||
bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size;
|
||||
}
|
||||
|
||||
{
|
||||
// generate our depth data
|
||||
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BLUR_SIZE);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RID framebuffer = p_buffers.base_weight_fb;
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_depth_texture), 0);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
|
||||
// double pass approach
|
||||
BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
|
||||
|
||||
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
|
||||
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
|
||||
bokeh.push_constant.half_size = true;
|
||||
bokeh.push_constant.blur_size *= 0.5;
|
||||
}
|
||||
|
||||
static const int quality_samples[4] = { 6, 12, 12, 24 };
|
||||
bokeh.push_constant.blur_scale = 0.5;
|
||||
bokeh.push_constant.steps = quality_samples[blur_quality];
|
||||
|
||||
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
|
||||
|
||||
// Pass 1
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
|
||||
// Pass 2
|
||||
if (!bokeh.push_constant.half_size) {
|
||||
// do not output weight, we're writing back into our base buffer
|
||||
mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
|
||||
|
||||
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
}
|
||||
bokeh.push_constant.second_pass = true;
|
||||
|
||||
framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb;
|
||||
RD::Uniform texture = bokeh.push_constant.half_size ? u_half_texture0 : u_secondary_texture;
|
||||
RD::Uniform weight = bokeh.push_constant.half_size ? u_weight_texture2 : u_weight_texture1;
|
||||
|
||||
draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, texture), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, weight), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
|
||||
if (bokeh.push_constant.half_size) {
|
||||
// Compose pass
|
||||
mode = BOKEH_COMPOSITE;
|
||||
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
framebuffer = p_buffers.base_fb;
|
||||
|
||||
draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture1), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture3), 1);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
} else {
|
||||
// circular is a single pass approach
|
||||
BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR;
|
||||
|
||||
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
{
|
||||
// circle always runs in half size, otherwise too expensive (though the code below does support making this optional)
|
||||
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
|
||||
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
|
||||
bokeh.push_constant.half_size = true;
|
||||
// bokeh.push_constant.blur_size *= 0.5;
|
||||
}
|
||||
|
||||
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
|
||||
bokeh.push_constant.blur_scale = quality_scale[blur_quality];
|
||||
bokeh.push_constant.steps = 0.0;
|
||||
|
||||
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
|
||||
if (bokeh.push_constant.half_size) {
|
||||
// Compose
|
||||
mode = BOKEH_COMPOSITE;
|
||||
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
framebuffer = p_buffers.base_fb;
|
||||
|
||||
draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture0), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture2), 1);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
} else {
|
||||
CopyEffects::get_singleton()->copy_raster(p_buffers.secondary_texture, p_buffers.base_fb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
servers/rendering/renderer_rd/effects/bokeh_dof.h
Normal file
119
servers/rendering/renderer_rd/effects/bokeh_dof.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/**************************************************************************/
|
||||
/* bokeh_dof.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class BokehDOF {
|
||||
private:
|
||||
bool prefer_raster_effects;
|
||||
|
||||
struct BokehPushConstant {
|
||||
uint32_t size[2];
|
||||
float z_far;
|
||||
float z_near;
|
||||
|
||||
uint32_t orthogonal;
|
||||
float blur_size;
|
||||
float blur_scale;
|
||||
uint32_t steps;
|
||||
|
||||
uint32_t blur_near_active;
|
||||
float blur_near_begin;
|
||||
float blur_near_end;
|
||||
uint32_t blur_far_active;
|
||||
|
||||
float blur_far_begin;
|
||||
float blur_far_end;
|
||||
uint32_t second_pass;
|
||||
uint32_t half_size;
|
||||
|
||||
uint32_t use_jitter;
|
||||
float jitter_seed;
|
||||
uint32_t use_physical_near;
|
||||
uint32_t use_physical_far;
|
||||
|
||||
float blur_size_near;
|
||||
float blur_size_far;
|
||||
uint32_t pad[2];
|
||||
};
|
||||
|
||||
enum BokehMode {
|
||||
BOKEH_GEN_BLUR_SIZE,
|
||||
BOKEH_GEN_BOKEH_BOX,
|
||||
BOKEH_GEN_BOKEH_BOX_NOWEIGHT,
|
||||
BOKEH_GEN_BOKEH_HEXAGONAL,
|
||||
BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT,
|
||||
BOKEH_GEN_BOKEH_CIRCULAR,
|
||||
BOKEH_COMPOSITE,
|
||||
BOKEH_MAX
|
||||
};
|
||||
|
||||
struct Bokeh {
|
||||
BokehPushConstant push_constant;
|
||||
BokehDofShaderRD compute_shader;
|
||||
BokehDofRasterShaderRD raster_shader;
|
||||
RID shader_version;
|
||||
RID compute_pipelines[BOKEH_MAX];
|
||||
PipelineCacheRD raster_pipelines[BOKEH_MAX];
|
||||
} bokeh;
|
||||
|
||||
public:
|
||||
struct BokehBuffers {
|
||||
// bokeh buffers
|
||||
|
||||
// textures
|
||||
Size2i base_texture_size;
|
||||
RID base_texture;
|
||||
RID depth_texture;
|
||||
RID secondary_texture;
|
||||
RID half_texture[2];
|
||||
|
||||
// raster only
|
||||
RID base_fb;
|
||||
RID secondary_fb; // with weights
|
||||
RID half_fb[2]; // with weights
|
||||
RID base_weight_fb;
|
||||
RID weight_texture[4];
|
||||
};
|
||||
|
||||
BokehDOF(bool p_prefer_raster_effects);
|
||||
~BokehDOF();
|
||||
|
||||
void bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
|
||||
void bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
1311
servers/rendering/renderer_rd/effects/copy_effects.cpp
Normal file
1311
servers/rendering/renderer_rd/effects/copy_effects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
359
servers/rendering/renderer_rd/effects/copy_effects.h
Normal file
359
servers/rendering/renderer_rd/effects/copy_effects.h
Normal file
@@ -0,0 +1,359 @@
|
||||
/**************************************************************************/
|
||||
/* copy_effects.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class CopyEffects {
|
||||
private:
|
||||
bool prefer_raster_effects;
|
||||
|
||||
// Blur raster shader
|
||||
|
||||
enum BlurRasterMode {
|
||||
BLUR_MIPMAP,
|
||||
|
||||
BLUR_MODE_GAUSSIAN_BLUR,
|
||||
BLUR_MODE_GAUSSIAN_GLOW,
|
||||
BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
|
||||
BLUR_MODE_COPY,
|
||||
|
||||
BLUR_MODE_SET_COLOR,
|
||||
|
||||
BLUR_MODE_MAX
|
||||
};
|
||||
|
||||
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];
|
||||
uint32_t flags;
|
||||
uint32_t pad;
|
||||
|
||||
//glow
|
||||
float glow_strength;
|
||||
float glow_bloom;
|
||||
float glow_hdr_threshold;
|
||||
float glow_hdr_scale;
|
||||
|
||||
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 {
|
||||
BlurRasterPushConstant push_constant;
|
||||
BlurRasterShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[BLUR_MODE_MAX];
|
||||
} blur_raster;
|
||||
|
||||
// Copy shader
|
||||
|
||||
enum CopyMode {
|
||||
COPY_MODE_GAUSSIAN_COPY,
|
||||
COPY_MODE_GAUSSIAN_COPY_8BIT,
|
||||
COPY_MODE_GAUSSIAN_GLOW,
|
||||
COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
|
||||
COPY_MODE_SIMPLY_COPY,
|
||||
COPY_MODE_SIMPLY_COPY_8BIT,
|
||||
COPY_MODE_SIMPLY_COPY_DEPTH,
|
||||
COPY_MODE_SET_COLOR,
|
||||
COPY_MODE_SET_COLOR_8BIT,
|
||||
COPY_MODE_MIPMAP,
|
||||
COPY_MODE_LINEARIZE_DEPTH,
|
||||
COPY_MODE_CUBE_TO_PANORAMA,
|
||||
COPY_MODE_CUBE_ARRAY_TO_PANORAMA,
|
||||
COPY_MODE_MAX,
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
COPY_FLAG_HORIZONTAL = (1 << 0),
|
||||
COPY_FLAG_USE_COPY_SECTION = (1 << 1),
|
||||
COPY_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2),
|
||||
COPY_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3),
|
||||
COPY_FLAG_GLOW_FIRST_PASS = (1 << 4),
|
||||
COPY_FLAG_FLIP_Y = (1 << 5),
|
||||
COPY_FLAG_FORCE_LUMINANCE = (1 << 6),
|
||||
COPY_FLAG_ALL_SOURCE = (1 << 7),
|
||||
COPY_FLAG_ALPHA_TO_ONE = (1 << 8),
|
||||
};
|
||||
|
||||
struct CopyPushConstant {
|
||||
int32_t section[4];
|
||||
int32_t target[2];
|
||||
uint32_t flags;
|
||||
uint32_t pad;
|
||||
// Glow.
|
||||
float glow_strength;
|
||||
float glow_bloom;
|
||||
float glow_hdr_threshold;
|
||||
float glow_hdr_scale;
|
||||
|
||||
float glow_exposure;
|
||||
float glow_white;
|
||||
float glow_luminance_cap;
|
||||
float glow_auto_exposure_scale;
|
||||
// DOF.
|
||||
float camera_z_far;
|
||||
float camera_z_near;
|
||||
uint32_t pad2[2];
|
||||
//SET color
|
||||
float set_color[4];
|
||||
};
|
||||
|
||||
struct Copy {
|
||||
CopyPushConstant push_constant;
|
||||
CopyShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[COPY_MODE_MAX];
|
||||
|
||||
} copy;
|
||||
|
||||
// Copy to FB shader
|
||||
|
||||
enum CopyToFBMode {
|
||||
COPY_TO_FB_COPY,
|
||||
COPY_TO_FB_COPY_PANORAMA_TO_DP,
|
||||
COPY_TO_FB_COPY2,
|
||||
COPY_TO_FB_SET_COLOR,
|
||||
|
||||
// These variants are disabled unless XR shaders are enabled.
|
||||
// They should be listed last.
|
||||
COPY_TO_FB_MULTIVIEW,
|
||||
COPY_TO_FB_MULTIVIEW_WITH_DEPTH,
|
||||
|
||||
COPY_TO_FB_MAX,
|
||||
};
|
||||
|
||||
enum CopyToFBFlags {
|
||||
COPY_TO_FB_FLAG_FLIP_Y = (1 << 0),
|
||||
COPY_TO_FB_FLAG_USE_SECTION = (1 << 1),
|
||||
COPY_TO_FB_FLAG_FORCE_LUMINANCE = (1 << 2),
|
||||
COPY_TO_FB_FLAG_ALPHA_TO_ZERO = (1 << 3),
|
||||
COPY_TO_FB_FLAG_SRGB = (1 << 4),
|
||||
COPY_TO_FB_FLAG_ALPHA_TO_ONE = (1 << 5),
|
||||
COPY_TO_FB_FLAG_LINEAR = (1 << 6),
|
||||
COPY_TO_FB_FLAG_NORMAL = (1 << 7),
|
||||
COPY_TO_FB_FLAG_USE_SRC_SECTION = (1 << 8),
|
||||
};
|
||||
|
||||
struct CopyToFbPushConstant {
|
||||
float section[4];
|
||||
float pixel_size[2];
|
||||
float luminance_multiplier;
|
||||
uint32_t flags;
|
||||
|
||||
float set_color[4];
|
||||
};
|
||||
|
||||
struct CopyToFb {
|
||||
CopyToFbPushConstant push_constant;
|
||||
CopyToFbShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[COPY_TO_FB_MAX];
|
||||
|
||||
} copy_to_fb;
|
||||
|
||||
// Copy to DP
|
||||
|
||||
struct CopyToDPPushConstant {
|
||||
float z_far;
|
||||
float z_near;
|
||||
float texel_size[2];
|
||||
};
|
||||
|
||||
struct CopyToDP {
|
||||
CubeToDpShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipeline;
|
||||
} cube_to_dp;
|
||||
|
||||
// Cubemap effects
|
||||
|
||||
struct CubemapDownsamplerPushConstant {
|
||||
uint32_t face_size;
|
||||
uint32_t face_id;
|
||||
float pad[2];
|
||||
};
|
||||
|
||||
struct CubemapDownsampler {
|
||||
CubemapDownsamplerPushConstant push_constant;
|
||||
CubemapDownsamplerShaderRD compute_shader;
|
||||
CubemapDownsamplerRasterShaderRD raster_shader;
|
||||
RID shader_version;
|
||||
RID compute_pipeline;
|
||||
PipelineCacheRD raster_pipeline;
|
||||
} cubemap_downsampler;
|
||||
|
||||
enum CubemapFilterMode {
|
||||
FILTER_MODE_HIGH_QUALITY,
|
||||
FILTER_MODE_LOW_QUALITY,
|
||||
FILTER_MODE_HIGH_QUALITY_ARRAY,
|
||||
FILTER_MODE_LOW_QUALITY_ARRAY,
|
||||
FILTER_MODE_MAX,
|
||||
};
|
||||
|
||||
struct CubemapFilterRasterPushConstant {
|
||||
uint32_t mip_level;
|
||||
uint32_t face_id;
|
||||
float pad[2];
|
||||
};
|
||||
|
||||
struct CubemapFilter {
|
||||
CubemapFilterShaderRD compute_shader;
|
||||
CubemapFilterRasterShaderRD raster_shader;
|
||||
RID shader_version;
|
||||
RID compute_pipelines[FILTER_MODE_MAX];
|
||||
PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
|
||||
|
||||
RID uniform_set;
|
||||
RID image_uniform_set;
|
||||
RID coefficient_buffer;
|
||||
bool use_high_quality;
|
||||
|
||||
} filter;
|
||||
|
||||
struct CubemapRoughnessPushConstant {
|
||||
uint32_t face_id;
|
||||
uint32_t sample_count;
|
||||
float roughness;
|
||||
uint32_t use_direct_write;
|
||||
float face_size;
|
||||
float pad[3];
|
||||
};
|
||||
|
||||
struct CubemapRoughness {
|
||||
CubemapRoughnessPushConstant push_constant;
|
||||
CubemapRoughnessShaderRD compute_shader;
|
||||
CubemapRoughnessRasterShaderRD raster_shader;
|
||||
RID shader_version;
|
||||
RID compute_pipeline;
|
||||
PipelineCacheRD raster_pipeline;
|
||||
} roughness;
|
||||
|
||||
// Merge specular
|
||||
|
||||
enum SpecularMergeMode {
|
||||
SPECULAR_MERGE_ADD,
|
||||
SPECULAR_MERGE_SSR,
|
||||
SPECULAR_MERGE_ADDITIVE_ADD,
|
||||
SPECULAR_MERGE_ADDITIVE_SSR,
|
||||
|
||||
SPECULAR_MERGE_ADD_MULTIVIEW,
|
||||
SPECULAR_MERGE_SSR_MULTIVIEW,
|
||||
SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW,
|
||||
SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW,
|
||||
|
||||
SPECULAR_MERGE_MAX
|
||||
};
|
||||
|
||||
/* Specular merge must be done using raster, rather than compute
|
||||
* because it must continue the existing color buffer
|
||||
*/
|
||||
|
||||
struct SpecularMerge {
|
||||
SpecularMergeShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[SPECULAR_MERGE_MAX];
|
||||
|
||||
} specular_merge;
|
||||
|
||||
static CopyEffects *singleton;
|
||||
|
||||
public:
|
||||
static CopyEffects *get_singleton();
|
||||
|
||||
CopyEffects(bool p_prefer_raster_effects);
|
||||
~CopyEffects();
|
||||
|
||||
bool get_prefer_raster_effects() { return prefer_raster_effects; }
|
||||
|
||||
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
|
||||
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
|
||||
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
|
||||
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
|
||||
void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false, const Rect2 &p_src_rect = Rect2());
|
||||
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
|
||||
void copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false);
|
||||
void copy_raster(RID p_source_texture, RID p_dest_framebuffer);
|
||||
|
||||
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 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);
|
||||
|
||||
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
|
||||
void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region);
|
||||
|
||||
void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
|
||||
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
|
||||
void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
|
||||
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
|
||||
void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
|
||||
|
||||
void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
|
||||
void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
|
||||
|
||||
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection, uint32_t p_view_count);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
378
servers/rendering/renderer_rd/effects/debug_effects.cpp
Normal file
378
servers/rendering/renderer_rd/effects/debug_effects.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
/**************************************************************************/
|
||||
/* debug_effects.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "debug_effects.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
DebugEffects::DebugEffects() {
|
||||
{
|
||||
// Shadow Frustum debug shader
|
||||
Vector<String> modes;
|
||||
modes.push_back("");
|
||||
|
||||
shadow_frustum.shader.initialize(modes);
|
||||
shadow_frustum.shader_version = shadow_frustum.shader.version_create();
|
||||
|
||||
RD::PipelineRasterizationState raster_state = RD::PipelineRasterizationState();
|
||||
shadow_frustum.pipelines[SFP_TRANSPARENT].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
|
||||
|
||||
raster_state.wireframe = true;
|
||||
shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
// Motion Vectors debug shader.
|
||||
Vector<String> modes;
|
||||
modes.push_back("");
|
||||
|
||||
motion_vectors.shader.initialize(modes);
|
||||
motion_vectors.shader_version = motion_vectors.shader.version_create();
|
||||
|
||||
motion_vectors.pipeline.setup(motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugEffects::_create_frustum_arrays() {
|
||||
if (frustum.vertex_buffer.is_null()) {
|
||||
// Create vertex buffer, but don't put data in it yet
|
||||
frustum.vertex_buffer = RD::get_singleton()->vertex_buffer_create(8 * sizeof(float) * 3, Vector<uint8_t>());
|
||||
|
||||
Vector<RD::VertexAttribute> attributes;
|
||||
Vector<RID> buffers;
|
||||
RD::VertexAttribute vd;
|
||||
|
||||
vd.location = 0;
|
||||
vd.stride = sizeof(float) * 3;
|
||||
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
|
||||
|
||||
attributes.push_back(vd);
|
||||
buffers.push_back(frustum.vertex_buffer);
|
||||
|
||||
frustum.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
|
||||
frustum.vertex_array = RD::get_singleton()->vertex_array_create(8, frustum.vertex_format, buffers);
|
||||
}
|
||||
|
||||
if (frustum.index_buffer.is_null()) {
|
||||
uint16_t indices[6 * 2 * 3] = {
|
||||
// Far
|
||||
0, 1, 2, // FLT, FLB, FRT
|
||||
1, 3, 2, // FLB, FRB, FRT
|
||||
// Near
|
||||
4, 6, 5, // NLT, NRT, NLB
|
||||
6, 7, 5, // NRT, NRB, NLB
|
||||
// Left
|
||||
0, 4, 1, // FLT, NLT, FLB
|
||||
4, 5, 1, // NLT, NLB, FLB
|
||||
// Right
|
||||
6, 2, 7, // NRT, FRT, NRB
|
||||
2, 3, 7, // FRT, FRB, NRB
|
||||
// Top
|
||||
0, 2, 4, // FLT, FRT, NLT
|
||||
2, 6, 4, // FRT, NRT, NLT
|
||||
// Bottom
|
||||
5, 7, 1, // NLB, NRB, FLB,
|
||||
7, 3, 1, // NRB, FRB, FLB
|
||||
};
|
||||
|
||||
// Create our index_array
|
||||
PackedByteArray data;
|
||||
data.resize(6 * 2 * 3 * 2);
|
||||
{
|
||||
uint8_t *w = data.ptrw();
|
||||
uint16_t *p16 = (uint16_t *)w;
|
||||
for (int i = 0; i < 6 * 2 * 3; i++) {
|
||||
*p16 = indices[i];
|
||||
p16++;
|
||||
}
|
||||
}
|
||||
|
||||
frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
|
||||
frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3);
|
||||
}
|
||||
|
||||
if (frustum.lines_buffer.is_null()) {
|
||||
uint16_t indices[12 * 2] = {
|
||||
0, 1, // FLT - FLB
|
||||
1, 3, // FLB - FRB
|
||||
3, 2, // FRB - FRT
|
||||
2, 0, // FRT - FLT
|
||||
|
||||
4, 6, // NLT - NRT
|
||||
6, 7, // NRT - NRB
|
||||
7, 5, // NRB - NLB
|
||||
5, 4, // NLB - NLT
|
||||
|
||||
0, 4, // FLT - NLT
|
||||
1, 5, // FLB - NLB
|
||||
2, 6, // FRT - NRT
|
||||
3, 7, // FRB - NRB
|
||||
};
|
||||
|
||||
// Create our lines_array
|
||||
PackedByteArray data;
|
||||
data.resize(12 * 2 * 2);
|
||||
{
|
||||
uint8_t *w = data.ptrw();
|
||||
uint16_t *p16 = (uint16_t *)w;
|
||||
for (int i = 0; i < 12 * 2; i++) {
|
||||
*p16 = indices[i];
|
||||
p16++;
|
||||
}
|
||||
}
|
||||
|
||||
frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
|
||||
frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2);
|
||||
}
|
||||
}
|
||||
|
||||
DebugEffects::~DebugEffects() {
|
||||
shadow_frustum.shader.version_free(shadow_frustum.shader_version);
|
||||
|
||||
// Destroy vertex buffer and array.
|
||||
if (frustum.vertex_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(frustum.vertex_buffer); // Array gets freed as dependency.
|
||||
}
|
||||
|
||||
// Destroy index buffer and array,
|
||||
if (frustum.index_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(frustum.index_buffer); // Array gets freed as dependency.
|
||||
}
|
||||
|
||||
// Destroy lines buffer and array.
|
||||
if (frustum.lines_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
|
||||
}
|
||||
|
||||
motion_vectors.shader.version_free(motion_vectors.shader_version);
|
||||
}
|
||||
|
||||
void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
|
||||
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
|
||||
|
||||
RID base = light_storage->light_instance_get_base_light(p_light);
|
||||
ERR_FAIL_COND(light_storage->light_get_type(base) != RS::LIGHT_DIRECTIONAL);
|
||||
|
||||
// Make sure our buffers and arrays exist.
|
||||
_create_frustum_arrays();
|
||||
|
||||
// Setup a points buffer for our view frustum.
|
||||
PackedByteArray points;
|
||||
points.resize(8 * sizeof(float) * 3);
|
||||
|
||||
// Get info about our splits.
|
||||
RS::LightDirectionalShadowMode shadow_mode = light_storage->light_directional_get_shadow_mode(base);
|
||||
bool overlap = light_storage->light_directional_get_blend_splits(base);
|
||||
int splits = 1;
|
||||
if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
|
||||
splits = 4;
|
||||
} else if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
|
||||
splits = 2;
|
||||
}
|
||||
|
||||
// Setup our camera info (this is mostly a duplicate of the logic found in RendererSceneCull::_light_instance_setup_directional_shadow).
|
||||
bool is_orthogonal = p_cam_projection.is_orthogonal();
|
||||
real_t aspect = p_cam_projection.get_aspect();
|
||||
real_t fov = 0.0;
|
||||
Vector2 vp_he;
|
||||
if (is_orthogonal) {
|
||||
vp_he = p_cam_projection.get_viewport_half_extents();
|
||||
} else {
|
||||
fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
|
||||
}
|
||||
real_t min_distance = p_cam_projection.get_z_near();
|
||||
real_t max_distance = p_cam_projection.get_z_far();
|
||||
real_t shadow_max = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
|
||||
if (shadow_max > 0 && !is_orthogonal) {
|
||||
max_distance = MIN(shadow_max, max_distance);
|
||||
}
|
||||
|
||||
// Make sure we've not got bad info coming in.
|
||||
max_distance = MAX(max_distance, min_distance + 0.001);
|
||||
min_distance = MIN(min_distance, max_distance);
|
||||
real_t range = max_distance - min_distance;
|
||||
|
||||
real_t distances[5];
|
||||
distances[0] = min_distance;
|
||||
for (int i = 0; i < splits; i++) {
|
||||
distances[i + 1] = min_distance + RSG::light_storage->light_get_param(base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
|
||||
};
|
||||
distances[splits] = max_distance;
|
||||
|
||||
Color colors[4] = {
|
||||
Color(1.0, 0.0, 0.0, 0.1),
|
||||
Color(0.0, 1.0, 0.0, 0.1),
|
||||
Color(0.0, 0.0, 1.0, 0.1),
|
||||
Color(1.0, 1.0, 0.0, 0.1),
|
||||
};
|
||||
|
||||
for (int split = 0; split < splits; split++) {
|
||||
// Load frustum points into vertex buffer.
|
||||
uint8_t *w = points.ptrw();
|
||||
Vector3 *vw = (Vector3 *)w;
|
||||
|
||||
Projection projection;
|
||||
|
||||
if (is_orthogonal) {
|
||||
projection.set_orthogonal(vp_he.y * 2.0, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], false);
|
||||
} else {
|
||||
projection.set_perspective(fov, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], true);
|
||||
}
|
||||
|
||||
bool res = projection.get_endpoints(p_cam_transform, vw);
|
||||
ERR_CONTINUE(!res);
|
||||
|
||||
RD::get_singleton()->buffer_update(frustum.vertex_buffer, 0, 8 * sizeof(float) * 3, w);
|
||||
|
||||
// Get our light projection info.
|
||||
Projection light_projection = light_storage->light_instance_get_shadow_camera(p_light, split);
|
||||
Transform3D light_transform = light_storage->light_instance_get_shadow_transform(p_light, split);
|
||||
Rect2 atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, split);
|
||||
|
||||
if (!is_orthogonal) {
|
||||
light_transform.orthogonalize();
|
||||
}
|
||||
|
||||
// Setup our push constant.
|
||||
ShadowFrustumPushConstant push_constant;
|
||||
MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
|
||||
push_constant.color[0] = colors[split].r;
|
||||
push_constant.color[1] = colors[split].g;
|
||||
push_constant.color[2] = colors[split].b;
|
||||
push_constant.color[3] = colors[split].a;
|
||||
|
||||
// Adjust our rect to our atlas position.
|
||||
Rect2 rect = p_rect;
|
||||
rect.position.x += atlas_rect_norm.position.x * rect.size.x;
|
||||
rect.position.y += atlas_rect_norm.position.y * rect.size.y;
|
||||
rect.size.x *= atlas_rect_norm.size.x;
|
||||
rect.size.y *= atlas_rect_norm.size.y;
|
||||
|
||||
// And draw our frustum.
|
||||
RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::DRAW_DEFAULT_ALL, Vector<Color>(), 1.0f, 0, rect);
|
||||
|
||||
RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, true);
|
||||
|
||||
pipeline = shadow_frustum.pipelines[SFP_WIREFRAME].get_render_pipeline(frustum.vertex_format, fb_format_id);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.lines_array);
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, true);
|
||||
|
||||
RD::get_singleton()->draw_list_end();
|
||||
|
||||
if (split < (splits - 1) && splits > 1) {
|
||||
// Also draw it in the last split so we get a proper overview of the whole view frustum...
|
||||
|
||||
// Get our light projection info.
|
||||
light_projection = light_storage->light_instance_get_shadow_camera(p_light, (splits - 1));
|
||||
light_transform = light_storage->light_instance_get_shadow_transform(p_light, (splits - 1));
|
||||
atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, (splits - 1));
|
||||
|
||||
if (!is_orthogonal) {
|
||||
light_transform.orthogonalize();
|
||||
}
|
||||
|
||||
// Update our push constant.
|
||||
MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
|
||||
push_constant.color[0] = colors[split].r;
|
||||
push_constant.color[1] = colors[split].g;
|
||||
push_constant.color[2] = colors[split].b;
|
||||
push_constant.color[3] = colors[split].a;
|
||||
|
||||
// Adjust our rect to our atlas position.
|
||||
rect = p_rect;
|
||||
rect.position.x += atlas_rect_norm.position.x * rect.size.x;
|
||||
rect.position.y += atlas_rect_norm.position.y * rect.size.y;
|
||||
rect.size.x *= atlas_rect_norm.size.x;
|
||||
rect.size.y *= atlas_rect_norm.size.y;
|
||||
|
||||
draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::DRAW_DEFAULT_ALL, Vector<Color>(), 1.0f, 0, rect);
|
||||
|
||||
pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, true);
|
||||
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution) {
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
RD::Uniform u_source_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity }));
|
||||
RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_depth }));
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass()));
|
||||
|
||||
Projection correction;
|
||||
correction.set_depth_correction(true, true, false);
|
||||
Projection reprojection = (correction * p_previous_projection) * p_previous_transform.affine_inverse() * p_current_transform * (correction * p_current_projection).inverse();
|
||||
RendererRD::MaterialStorage::store_camera(reprojection, motion_vectors.push_constant.reprojection_matrix);
|
||||
|
||||
motion_vectors.push_constant.resolution[0] = p_resolution.width;
|
||||
motion_vectors.push_constant.resolution[1] = p_resolution.height;
|
||||
motion_vectors.push_constant.force_derive_from_depth = false;
|
||||
|
||||
RID shader = motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_velocity, u_source_depth), 0);
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
|
||||
#ifdef DRAW_DERIVATION_FROM_DEPTH_ON_TOP
|
||||
motion_vectors.push_constant.force_derive_from_depth = true;
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
#endif
|
||||
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
95
servers/rendering/renderer_rd/effects/debug_effects.h
Normal file
95
servers/rendering/renderer_rd/effects/debug_effects.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**************************************************************************/
|
||||
/* debug_effects.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class DebugEffects {
|
||||
private:
|
||||
struct {
|
||||
RD::VertexFormatID vertex_format;
|
||||
RID vertex_buffer;
|
||||
RID vertex_array;
|
||||
|
||||
RID index_buffer;
|
||||
RID index_array;
|
||||
|
||||
RID lines_buffer;
|
||||
RID lines_array;
|
||||
} frustum;
|
||||
|
||||
struct ShadowFrustumPushConstant {
|
||||
float mvp[16];
|
||||
float color[4];
|
||||
};
|
||||
|
||||
enum ShadowFrustumPipelines {
|
||||
SFP_TRANSPARENT,
|
||||
SFP_WIREFRAME,
|
||||
SFP_MAX
|
||||
};
|
||||
|
||||
struct {
|
||||
ShadowFrustumShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[SFP_MAX];
|
||||
} shadow_frustum;
|
||||
|
||||
struct MotionVectorsPushConstant {
|
||||
float reprojection_matrix[16];
|
||||
float resolution[2];
|
||||
uint32_t force_derive_from_depth;
|
||||
float pad;
|
||||
};
|
||||
|
||||
struct {
|
||||
MotionVectorsShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipeline;
|
||||
MotionVectorsPushConstant push_constant;
|
||||
} motion_vectors;
|
||||
|
||||
void _create_frustum_arrays();
|
||||
|
||||
protected:
|
||||
public:
|
||||
DebugEffects();
|
||||
~DebugEffects();
|
||||
|
||||
void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect);
|
||||
void draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
124
servers/rendering/renderer_rd/effects/fsr.cpp
Normal file
124
servers/rendering/renderer_rd/effects/fsr.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/**************************************************************************/
|
||||
/* fsr.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "fsr.h"
|
||||
#include "../storage_rd/material_storage.h"
|
||||
#include "../uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
FSR::FSR() {
|
||||
Vector<String> fsr_upscale_modes;
|
||||
fsr_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
|
||||
fsr_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
|
||||
fsr_shader.initialize(fsr_upscale_modes);
|
||||
|
||||
FSRShaderVariant variant;
|
||||
if (RD::get_singleton()->has_feature(RD::SUPPORTS_HALF_FLOAT)) {
|
||||
variant = FSR_SHADER_VARIANT_NORMAL;
|
||||
} else {
|
||||
variant = FSR_SHADER_VARIANT_FALLBACK;
|
||||
}
|
||||
|
||||
shader_version = fsr_shader.version_create();
|
||||
pipeline = RD::get_singleton()->compute_pipeline_create(fsr_shader.version_get_shader(shader_version, variant));
|
||||
}
|
||||
|
||||
FSR::~FSR() {
|
||||
fsr_shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void FSR::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
Size2i internal_size = p_render_buffers->get_internal_size();
|
||||
Size2i target_size = p_render_buffers->get_target_size();
|
||||
float fsr_upscale_sharpness = p_render_buffers->get_fsr_sharpness();
|
||||
|
||||
if (!p_render_buffers->has_texture(SNAME("FSR"), SNAME("upscale_texture"))) {
|
||||
RD::DataFormat format = p_render_buffers->get_base_data_format();
|
||||
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
uint32_t layers = 1; // we only need one layer, in multiview we're processing one layer at a time.
|
||||
|
||||
p_render_buffers->create_texture(SNAME("FSR"), SNAME("upscale_texture"), format, usage_bits, RD::TEXTURE_SAMPLES_1, target_size, layers);
|
||||
}
|
||||
|
||||
RID upscale_texture = p_render_buffers->get_texture(SNAME("FSR"), SNAME("upscale_texture"));
|
||||
|
||||
FSRUpscalePushConstant push_constant;
|
||||
memset(&push_constant, 0, sizeof(FSRUpscalePushConstant));
|
||||
|
||||
int dispatch_x = (target_size.x + 15) / 16;
|
||||
int dispatch_y = (target_size.y + 15) / 16;
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
|
||||
|
||||
push_constant.resolution_width = internal_size.width;
|
||||
push_constant.resolution_height = internal_size.height;
|
||||
push_constant.upscaled_width = target_size.width;
|
||||
push_constant.upscaled_height = target_size.height;
|
||||
push_constant.sharpness = fsr_upscale_sharpness;
|
||||
|
||||
RID shader = fsr_shader.version_get_shader(shader_version, 0);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
//FSR Easc
|
||||
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, p_source_rd_texture });
|
||||
RD::Uniform u_upscale_texture(RD::UNIFORM_TYPE_IMAGE, 0, { upscale_texture });
|
||||
|
||||
push_constant.pass = FSR_UPSCALE_PASS_EASU;
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_upscale_texture), 1);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(FSRUpscalePushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
//FSR Rcas
|
||||
RD::Uniform u_upscale_texture_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, upscale_texture });
|
||||
RD::Uniform u_destination_texture(RD::UNIFORM_TYPE_IMAGE, 0, { p_destination_texture });
|
||||
|
||||
push_constant.pass = FSR_UPSCALE_PASS_RCAS;
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_texture_with_sampler), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_destination_texture), 1);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(FSRUpscalePushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
75
servers/rendering/renderer_rd/effects/fsr.h
Normal file
75
servers/rendering/renderer_rd/effects/fsr.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/**************************************************************************/
|
||||
/* fsr.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spatial_upscaler.h"
|
||||
|
||||
#include "../storage_rd/render_scene_buffers_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class FSR : public SpatialUpscaler {
|
||||
public:
|
||||
FSR();
|
||||
~FSR();
|
||||
|
||||
virtual const Span<char> get_label() const final { return "FSR 1.0 Upscale"; }
|
||||
virtual void ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) final {}
|
||||
virtual void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) final;
|
||||
|
||||
private:
|
||||
enum FSRShaderVariant {
|
||||
FSR_SHADER_VARIANT_NORMAL,
|
||||
FSR_SHADER_VARIANT_FALLBACK,
|
||||
};
|
||||
|
||||
enum FSRUpscalePass {
|
||||
FSR_UPSCALE_PASS_EASU = 0,
|
||||
FSR_UPSCALE_PASS_RCAS = 1
|
||||
};
|
||||
|
||||
struct FSRUpscalePushConstant {
|
||||
float resolution_width;
|
||||
float resolution_height;
|
||||
float upscaled_width;
|
||||
float upscaled_height;
|
||||
float sharpness;
|
||||
int pass;
|
||||
int _unused0, _unused1;
|
||||
};
|
||||
|
||||
FsrUpscaleShaderRD fsr_shader;
|
||||
RID shader_version;
|
||||
RID pipeline;
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
880
servers/rendering/renderer_rd/effects/fsr2.cpp
Normal file
880
servers/rendering/renderer_rd/effects/fsr2.cpp
Normal file
@@ -0,0 +1,880 @@
|
||||
/**************************************************************************/
|
||||
/* fsr2.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "fsr2.h"
|
||||
|
||||
#include "../storage_rd/material_storage.h"
|
||||
#include "../uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <cwchar>
|
||||
#define wcscpy_s wcscpy
|
||||
#endif
|
||||
|
||||
static RD::TextureType ffx_resource_type_to_rd_texture_type(FfxResourceType p_type) {
|
||||
switch (p_type) {
|
||||
case FFX_RESOURCE_TYPE_TEXTURE1D:
|
||||
return RD::TEXTURE_TYPE_1D;
|
||||
case FFX_RESOURCE_TYPE_TEXTURE2D:
|
||||
return RD::TEXTURE_TYPE_2D;
|
||||
case FFX_RESOURCE_TYPE_TEXTURE3D:
|
||||
return RD::TEXTURE_TYPE_3D;
|
||||
default:
|
||||
return RD::TEXTURE_TYPE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static FfxResourceType rd_texture_type_to_ffx_resource_type(RD::TextureType p_type) {
|
||||
switch (p_type) {
|
||||
case RD::TEXTURE_TYPE_1D:
|
||||
return FFX_RESOURCE_TYPE_TEXTURE1D;
|
||||
case RD::TEXTURE_TYPE_2D:
|
||||
return FFX_RESOURCE_TYPE_TEXTURE2D;
|
||||
case RD::TEXTURE_TYPE_3D:
|
||||
return FFX_RESOURCE_TYPE_TEXTURE3D;
|
||||
default:
|
||||
return FFX_RESOURCE_TYPE_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
static RD::DataFormat ffx_surface_format_to_rd_format(FfxSurfaceFormat p_format) {
|
||||
switch (p_format) {
|
||||
case FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS:
|
||||
return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT:
|
||||
return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT:
|
||||
return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R16G16B16A16_UNORM:
|
||||
return RD::DATA_FORMAT_R16G16B16A16_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R32G32_FLOAT:
|
||||
return RD::DATA_FORMAT_R32G32_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R32_UINT:
|
||||
return RD::DATA_FORMAT_R32_UINT;
|
||||
case FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS:
|
||||
return RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R8G8B8A8_UNORM:
|
||||
return RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R11G11B10_FLOAT:
|
||||
return RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
case FFX_SURFACE_FORMAT_R16G16_FLOAT:
|
||||
return RD::DATA_FORMAT_R16G16_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R16G16_UINT:
|
||||
return RD::DATA_FORMAT_R16G16_UINT;
|
||||
case FFX_SURFACE_FORMAT_R16_FLOAT:
|
||||
return RD::DATA_FORMAT_R16_SFLOAT;
|
||||
case FFX_SURFACE_FORMAT_R16_UINT:
|
||||
return RD::DATA_FORMAT_R16_UINT;
|
||||
case FFX_SURFACE_FORMAT_R16_UNORM:
|
||||
return RD::DATA_FORMAT_R16_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R16_SNORM:
|
||||
return RD::DATA_FORMAT_R16_SNORM;
|
||||
case FFX_SURFACE_FORMAT_R8_UNORM:
|
||||
return RD::DATA_FORMAT_R8_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R8_UINT:
|
||||
return RD::DATA_FORMAT_R8_UINT;
|
||||
case FFX_SURFACE_FORMAT_R8G8_UNORM:
|
||||
return RD::DATA_FORMAT_R8G8_UNORM;
|
||||
case FFX_SURFACE_FORMAT_R32_FLOAT:
|
||||
return RD::DATA_FORMAT_R32_SFLOAT;
|
||||
default:
|
||||
return RD::DATA_FORMAT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static FfxSurfaceFormat rd_format_to_ffx_surface_format(RD::DataFormat p_format) {
|
||||
switch (p_format) {
|
||||
case RD::DATA_FORMAT_R32G32B32A32_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT;
|
||||
case RD::DATA_FORMAT_R16G16B16A16_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT;
|
||||
case RD::DATA_FORMAT_R16G16B16A16_UNORM:
|
||||
return FFX_SURFACE_FORMAT_R16G16B16A16_UNORM;
|
||||
case RD::DATA_FORMAT_R32G32_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R32G32_FLOAT;
|
||||
case RD::DATA_FORMAT_R32_UINT:
|
||||
return FFX_SURFACE_FORMAT_R32_UINT;
|
||||
case RD::DATA_FORMAT_R8G8B8A8_UNORM:
|
||||
return FFX_SURFACE_FORMAT_R8G8B8A8_UNORM;
|
||||
case RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
|
||||
return FFX_SURFACE_FORMAT_R11G11B10_FLOAT;
|
||||
case RD::DATA_FORMAT_R16G16_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R16G16_FLOAT;
|
||||
case RD::DATA_FORMAT_R16G16_UINT:
|
||||
return FFX_SURFACE_FORMAT_R16G16_UINT;
|
||||
case RD::DATA_FORMAT_R16_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R16_FLOAT;
|
||||
case RD::DATA_FORMAT_R16_UINT:
|
||||
return FFX_SURFACE_FORMAT_R16_UINT;
|
||||
case RD::DATA_FORMAT_R16_UNORM:
|
||||
return FFX_SURFACE_FORMAT_R16_UNORM;
|
||||
case RD::DATA_FORMAT_R16_SNORM:
|
||||
return FFX_SURFACE_FORMAT_R16_SNORM;
|
||||
case RD::DATA_FORMAT_R8_UNORM:
|
||||
return FFX_SURFACE_FORMAT_R8_UNORM;
|
||||
case RD::DATA_FORMAT_R8_UINT:
|
||||
return FFX_SURFACE_FORMAT_R8_UINT;
|
||||
case RD::DATA_FORMAT_R8G8_UNORM:
|
||||
return FFX_SURFACE_FORMAT_R8G8_UNORM;
|
||||
case RD::DATA_FORMAT_R32_SFLOAT:
|
||||
return FFX_SURFACE_FORMAT_R32_FLOAT;
|
||||
default:
|
||||
return FFX_SURFACE_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ffx_usage_to_rd_usage_flags(uint32_t p_flags) {
|
||||
uint32_t ret = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
|
||||
|
||||
if (p_flags & FFX_RESOURCE_USAGE_RENDERTARGET) {
|
||||
ret |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (p_flags & FFX_RESOURCE_USAGE_UAV) {
|
||||
ret |= RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
ret |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
|
||||
ret |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FfxErrorCode create_backend_context_rd(FfxFsr2Interface *p_backend_interface, FfxDevice p_device) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
|
||||
// Store pointer to the device common to all contexts.
|
||||
scratch.device = p_device;
|
||||
|
||||
// Create a ring buffer of uniform buffers.
|
||||
// FIXME: This could be optimized to be a single memory block if it was possible for RD to create views into a particular memory range of a UBO.
|
||||
for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
|
||||
scratch.ubo_ring_buffer[i] = RD::get_singleton()->uniform_buffer_create(FFX_MAX_CONST_SIZE * sizeof(uint32_t));
|
||||
ERR_FAIL_COND_V(scratch.ubo_ring_buffer[i].is_null(), FFX_ERROR_BACKEND_API_ERROR);
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode get_device_capabilities_rd(FfxFsr2Interface *p_backend_interface, FfxDeviceCapabilities *p_out_device_capabilities, FfxDevice p_device) {
|
||||
FSR2Effect::Device &effect_device = *reinterpret_cast<FSR2Effect::Device *>(p_device);
|
||||
|
||||
*p_out_device_capabilities = effect_device.capabilities;
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode destroy_backend_context_rd(FfxFsr2Interface *p_backend_interface) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
|
||||
for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
|
||||
RD::get_singleton()->free(scratch.ubo_ring_buffer[i]);
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode create_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxCreateResourceDescription *p_create_resource_description, FfxResourceInternal *p_out_resource) {
|
||||
// FSR2's base implementation won't issue a call to create a heap type that isn't just default on its own,
|
||||
// so we can safely ignore it as RD does not expose this concept.
|
||||
ERR_FAIL_COND_V(p_create_resource_description->heapType != FFX_HEAP_TYPE_DEFAULT, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
RenderingDevice *rd = RD::get_singleton();
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
FfxResourceDescription res_desc = p_create_resource_description->resourceDescription;
|
||||
|
||||
// FSR2's base implementation never requests buffer creation.
|
||||
ERR_FAIL_COND_V(res_desc.type != FFX_RESOURCE_TYPE_TEXTURE1D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE2D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE3D, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
if (res_desc.mipCount == 0) {
|
||||
// Mipmap count must be derived from the resource's dimensions.
|
||||
res_desc.mipCount = uint32_t(1 + std::floor(std::log2(MAX(MAX(res_desc.width, res_desc.height), res_desc.depth))));
|
||||
}
|
||||
|
||||
Vector<PackedByteArray> initial_data;
|
||||
if (p_create_resource_description->initDataSize) {
|
||||
PackedByteArray byte_array;
|
||||
byte_array.resize(p_create_resource_description->initDataSize);
|
||||
memcpy(byte_array.ptrw(), p_create_resource_description->initData, p_create_resource_description->initDataSize);
|
||||
initial_data.push_back(byte_array);
|
||||
}
|
||||
|
||||
RD::TextureFormat texture_format;
|
||||
texture_format.texture_type = ffx_resource_type_to_rd_texture_type(res_desc.type);
|
||||
texture_format.format = ffx_surface_format_to_rd_format(res_desc.format);
|
||||
texture_format.usage_bits = ffx_usage_to_rd_usage_flags(p_create_resource_description->usage);
|
||||
texture_format.width = res_desc.width;
|
||||
texture_format.height = res_desc.height;
|
||||
texture_format.depth = res_desc.depth;
|
||||
texture_format.mipmaps = res_desc.mipCount;
|
||||
texture_format.is_discardable = true;
|
||||
|
||||
RID texture = rd->texture_create(texture_format, RD::TextureView(), initial_data);
|
||||
ERR_FAIL_COND_V(texture.is_null(), FFX_ERROR_BACKEND_API_ERROR);
|
||||
|
||||
rd->set_resource_name(texture, String(p_create_resource_description->name));
|
||||
|
||||
// Add the resource to the storage and use the internal index to reference it.
|
||||
p_out_resource->internalIndex = scratch.resources.add(texture, false, p_create_resource_description->id, res_desc);
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode register_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxResource *p_in_resource, FfxResourceInternal *p_out_resource) {
|
||||
if (p_in_resource->resource == nullptr) {
|
||||
// Null resource case.
|
||||
p_out_resource->internalIndex = -1;
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
const RID &rid = *reinterpret_cast<const RID *>(p_in_resource->resource);
|
||||
ERR_FAIL_COND_V(rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
// Add the resource to the storage and use the internal index to reference it.
|
||||
p_out_resource->internalIndex = scratch.resources.add(rid, true, FSR2Context::RESOURCE_ID_DYNAMIC, p_in_resource->description);
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode unregister_resources_rd(FfxFsr2Interface *p_backend_interface) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
LocalVector<uint32_t> dynamic_list_copy = scratch.resources.dynamic_list;
|
||||
for (uint32_t i : dynamic_list_copy) {
|
||||
scratch.resources.remove(i);
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxResourceDescription get_resource_description_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
|
||||
if (p_resource.internalIndex != -1) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
return scratch.resources.descriptions[p_resource.internalIndex];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static FfxErrorCode destroy_resource_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
|
||||
if (p_resource.internalIndex != -1) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
if (scratch.resources.rids[p_resource.internalIndex].is_valid()) {
|
||||
RD::get_singleton()->free(scratch.resources.rids[p_resource.internalIndex]);
|
||||
scratch.resources.remove(p_resource.internalIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode create_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxFsr2Pass p_pass, const FfxPipelineDescription *p_pipeline_description, FfxPipelineState *p_out_pipeline) {
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(scratch.device);
|
||||
FSR2Effect::Pass &effect_pass = device.passes[p_pass];
|
||||
|
||||
if (effect_pass.pipeline.pipeline_rid.is_null()) {
|
||||
// Create pipeline for the device if it hasn't been created yet.
|
||||
effect_pass.root_signature.shader_rid = effect_pass.shader->version_get_shader(effect_pass.shader_version, effect_pass.shader_variant);
|
||||
ERR_FAIL_COND_V(effect_pass.root_signature.shader_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
|
||||
|
||||
effect_pass.pipeline.pipeline_rid = RD::get_singleton()->compute_pipeline_create(effect_pass.root_signature.shader_rid);
|
||||
ERR_FAIL_COND_V(effect_pass.pipeline.pipeline_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
|
||||
}
|
||||
|
||||
// While this is not their intended use, we use the pipeline and root signature pointers to store the
|
||||
// RIDs to the pipeline and shader that RD needs for the compute pipeline.
|
||||
p_out_pipeline->pipeline = reinterpret_cast<FfxPipeline>(&effect_pass.pipeline);
|
||||
p_out_pipeline->rootSignature = reinterpret_cast<FfxRootSignature>(&effect_pass.root_signature);
|
||||
|
||||
p_out_pipeline->srvCount = effect_pass.sampled_bindings.size();
|
||||
ERR_FAIL_COND_V(p_out_pipeline->srvCount > FFX_MAX_NUM_SRVS, FFX_ERROR_OUT_OF_RANGE);
|
||||
memcpy(p_out_pipeline->srvResourceBindings, effect_pass.sampled_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->srvCount);
|
||||
|
||||
p_out_pipeline->uavCount = effect_pass.storage_bindings.size();
|
||||
ERR_FAIL_COND_V(p_out_pipeline->uavCount > FFX_MAX_NUM_UAVS, FFX_ERROR_OUT_OF_RANGE);
|
||||
memcpy(p_out_pipeline->uavResourceBindings, effect_pass.storage_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->uavCount);
|
||||
|
||||
p_out_pipeline->constCount = effect_pass.uniform_bindings.size();
|
||||
ERR_FAIL_COND_V(p_out_pipeline->constCount > FFX_MAX_NUM_CONST_BUFFERS, FFX_ERROR_OUT_OF_RANGE);
|
||||
memcpy(p_out_pipeline->cbResourceBindings, effect_pass.uniform_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->constCount);
|
||||
|
||||
bool low_resolution_mvs = (p_pipeline_description->contextFlags & FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) == 0;
|
||||
|
||||
if (p_pass == FFX_FSR2_PASS_ACCUMULATE || p_pass == FFX_FSR2_PASS_ACCUMULATE_SHARPEN) {
|
||||
// Change the binding for motion vectors in this particular pass if low resolution MVs are used.
|
||||
if (low_resolution_mvs) {
|
||||
FfxResourceBinding &binding = p_out_pipeline->srvResourceBindings[2];
|
||||
wcscpy_s(binding.name, L"r_dilated_motion_vectors");
|
||||
}
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode destroy_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxPipelineState *p_pipeline) {
|
||||
// We don't want to destroy pipelines when the FSR2 API deems it necessary as it'll do so whenever the context is destroyed.
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode schedule_gpu_job_rd(FfxFsr2Interface *p_backend_interface, const FfxGpuJobDescription *p_job) {
|
||||
ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
|
||||
ERR_FAIL_NULL_V(p_job, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
scratch.gpu_jobs.push_back(*p_job);
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode execute_gpu_job_clear_float_rd(FSR2Context::Scratch &p_scratch, const FfxClearFloatJobDescription &p_job) {
|
||||
RID resource = p_scratch.resources.rids[p_job.target.internalIndex];
|
||||
FfxResourceDescription &desc = p_scratch.resources.descriptions[p_job.target.internalIndex];
|
||||
|
||||
ERR_FAIL_COND_V(desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
Color color(p_job.color[0], p_job.color[1], p_job.color[2], p_job.color[3]);
|
||||
RD::get_singleton()->texture_clear(resource, color, 0, desc.mipCount, 0, 1);
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, const FfxCopyJobDescription &p_job) {
|
||||
RID src = p_scratch.resources.rids[p_job.src.internalIndex];
|
||||
RID dst = p_scratch.resources.rids[p_job.dst.internalIndex];
|
||||
FfxResourceDescription &src_desc = p_scratch.resources.descriptions[p_job.src.internalIndex];
|
||||
FfxResourceDescription &dst_desc = p_scratch.resources.descriptions[p_job.dst.internalIndex];
|
||||
|
||||
ERR_FAIL_COND_V(src_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
|
||||
ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) {
|
||||
RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0);
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch, const FfxComputeJobDescription &p_job) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL_V(uniform_set_cache, FFX_ERROR_BACKEND_API_ERROR);
|
||||
|
||||
FSR2Effect::RootSignature &root_signature = *reinterpret_cast<FSR2Effect::RootSignature *>(p_job.pipeline.rootSignature);
|
||||
ERR_FAIL_COND_V(root_signature.shader_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
FSR2Effect::Pipeline &backend_pipeline = *reinterpret_cast<FSR2Effect::Pipeline *>(p_job.pipeline.pipeline);
|
||||
ERR_FAIL_COND_V(backend_pipeline.pipeline_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
thread_local LocalVector<RD::Uniform> compute_uniforms;
|
||||
compute_uniforms.clear();
|
||||
|
||||
for (uint32_t i = 0; i < p_job.pipeline.srvCount; i++) {
|
||||
RID texture_rid = p_scratch.resources.rids[p_job.srvs[i].internalIndex];
|
||||
RD::Uniform texture_uniform(RD::UNIFORM_TYPE_TEXTURE, p_job.pipeline.srvResourceBindings[i].slotIndex, texture_rid);
|
||||
compute_uniforms.push_back(texture_uniform);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < p_job.pipeline.uavCount; i++) {
|
||||
RID image_rid = p_scratch.resources.rids[p_job.uavs[i].internalIndex];
|
||||
RD::Uniform storage_uniform;
|
||||
storage_uniform.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
storage_uniform.binding = p_job.pipeline.uavResourceBindings[i].slotIndex;
|
||||
|
||||
if (p_job.uavMip[i] > 0) {
|
||||
LocalVector<RID> &mip_slice_rids = p_scratch.resources.mip_slice_rids[p_job.uavs[i].internalIndex];
|
||||
if (mip_slice_rids.is_empty()) {
|
||||
mip_slice_rids.resize(p_scratch.resources.descriptions[p_job.uavs[i].internalIndex].mipCount);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(p_job.uavMip[i] >= mip_slice_rids.size(), FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
if (mip_slice_rids[p_job.uavMip[i]].is_null()) {
|
||||
mip_slice_rids[p_job.uavMip[i]] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), image_rid, 0, p_job.uavMip[i]);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(mip_slice_rids[p_job.uavMip[i]].is_null(), FFX_ERROR_BACKEND_API_ERROR);
|
||||
|
||||
storage_uniform.append_id(mip_slice_rids[p_job.uavMip[i]]);
|
||||
} else {
|
||||
storage_uniform.append_id(image_rid);
|
||||
}
|
||||
|
||||
compute_uniforms.push_back(storage_uniform);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < p_job.pipeline.constCount; i++) {
|
||||
RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index];
|
||||
p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE;
|
||||
|
||||
RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data);
|
||||
|
||||
RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid);
|
||||
compute_uniforms.push_back(buffer_uniform);
|
||||
}
|
||||
|
||||
FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(p_scratch.device);
|
||||
RD::Uniform u_point_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 0, device.point_clamp_sampler);
|
||||
RD::Uniform u_linear_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 1, device.linear_clamp_sampler);
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, backend_pipeline.pipeline_rid);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(root_signature.shader_rid, 0, u_point_clamp_sampler, u_linear_clamp_sampler), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache_vec(root_signature.shader_rid, 1, compute_uniforms), 1);
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, p_job.dimensions[0], p_job.dimensions[1], p_job.dimensions[2]);
|
||||
RD::get_singleton()->compute_list_end();
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxErrorCode execute_gpu_jobs_rd(FfxFsr2Interface *p_backend_interface, FfxCommandList p_command_list) {
|
||||
ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
|
||||
FfxErrorCode error_code = FFX_OK;
|
||||
for (const FfxGpuJobDescription &job : scratch.gpu_jobs) {
|
||||
switch (job.jobType) {
|
||||
case FFX_GPU_JOB_CLEAR_FLOAT: {
|
||||
error_code = execute_gpu_job_clear_float_rd(scratch, job.clearJobDescriptor);
|
||||
} break;
|
||||
case FFX_GPU_JOB_COPY: {
|
||||
error_code = execute_gpu_job_copy_rd(scratch, job.copyJobDescriptor);
|
||||
} break;
|
||||
case FFX_GPU_JOB_COMPUTE: {
|
||||
error_code = execute_gpu_job_compute_rd(scratch, job.computeJobDescriptor);
|
||||
} break;
|
||||
default: {
|
||||
error_code = FFX_ERROR_INVALID_ARGUMENT;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (error_code != FFX_OK) {
|
||||
scratch.gpu_jobs.clear();
|
||||
return error_code;
|
||||
}
|
||||
}
|
||||
|
||||
scratch.gpu_jobs.clear();
|
||||
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
static FfxResource get_resource_rd(RID *p_rid, const wchar_t *p_name) {
|
||||
FfxResource res = {};
|
||||
if (p_rid->is_null()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
wcscpy_s(res.name, p_name);
|
||||
|
||||
RD::TextureFormat texture_format = RD::get_singleton()->texture_get_format(*p_rid);
|
||||
res.description.type = rd_texture_type_to_ffx_resource_type(texture_format.texture_type);
|
||||
res.description.format = rd_format_to_ffx_surface_format(texture_format.format);
|
||||
res.description.width = texture_format.width;
|
||||
res.description.height = texture_format.height;
|
||||
res.description.depth = texture_format.depth;
|
||||
res.description.mipCount = texture_format.mipmaps;
|
||||
res.description.flags = FFX_RESOURCE_FLAGS_NONE;
|
||||
res.resource = reinterpret_cast<void *>(p_rid);
|
||||
res.isDepth = texture_format.usage_bits & RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
FSR2Context::~FSR2Context() {
|
||||
ffxFsr2ContextDestroy(&fsr_context);
|
||||
}
|
||||
|
||||
FSR2Effect::FSR2Effect() {
|
||||
FfxDeviceCapabilities &capabilities = device.capabilities;
|
||||
capabilities.minimumSupportedShaderModel = FFX_SHADER_MODEL_5_1;
|
||||
capabilities.waveLaneCountMin = 32;
|
||||
capabilities.waveLaneCountMax = 32;
|
||||
capabilities.fp16Supported = RD::get_singleton()->has_feature(RD::Features::SUPPORTS_HALF_FLOAT);
|
||||
capabilities.raytracingSupported = false;
|
||||
|
||||
String general_defines =
|
||||
"\n#define FFX_GPU\n"
|
||||
"\n#define FFX_GLSL 1\n"
|
||||
"\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n"
|
||||
"\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n"
|
||||
"\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n"
|
||||
"\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n"
|
||||
"\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n";
|
||||
|
||||
Vector<String> modes_single;
|
||||
modes_single.push_back("");
|
||||
|
||||
Vector<String> modes_with_fp16;
|
||||
modes_with_fp16.push_back("");
|
||||
modes_with_fp16.push_back("\n#define FFX_HALF 1\n");
|
||||
|
||||
// Since Godot currently lacks a shader reflection mechanism to persist the name of the bindings in the shader cache and
|
||||
// there's also no mechanism to compile the shaders offline, the bindings are created manually by looking at the GLSL
|
||||
// files included in FSR2 and mapping the macro bindings (#define FSR2_BIND_*) to their respective implementation names.
|
||||
//
|
||||
// It is not guaranteed these will remain consistent at all between versions of FSR2, so it'll be necessary to keep these
|
||||
// bindings up to date whenever the library is updated. In such cases, it is very likely the validation layer will throw an
|
||||
// error if the bindings do not match.
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_DEPTH_CLIP];
|
||||
pass.shader = &shaders.depth_clip;
|
||||
pass.shader->initialize(modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported ? 1 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_reconstructed_previous_nearest_depth" },
|
||||
FfxResourceBinding{ 1, 0, L"r_dilated_motion_vectors" },
|
||||
FfxResourceBinding{ 2, 0, L"r_dilatedDepth" },
|
||||
FfxResourceBinding{ 3, 0, L"r_reactive_mask" },
|
||||
FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" },
|
||||
FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" },
|
||||
FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" },
|
||||
FfxResourceBinding{ 8, 0, L"r_input_color_jittered" },
|
||||
FfxResourceBinding{ 9, 0, L"r_input_depth" },
|
||||
FfxResourceBinding{ 10, 0, L"r_input_exposure" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
// FSR2_BIND_UAV_DEPTH_CLIP (11) does not point to anything.
|
||||
FfxResourceBinding{ 12, 0, L"rw_dilated_reactive_masks" },
|
||||
FfxResourceBinding{ 13, 0, L"rw_prepared_input_color" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 14, 0, L"cbFSR2" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH];
|
||||
pass.shader = &shaders.reconstruct_previous_depth;
|
||||
pass.shader->initialize(modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported ? 1 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_motion_vectors" },
|
||||
FfxResourceBinding{ 1, 0, L"r_input_depth" },
|
||||
FfxResourceBinding{ 2, 0, L"r_input_color_jittered" },
|
||||
FfxResourceBinding{ 3, 0, L"r_input_exposure" },
|
||||
FfxResourceBinding{ 4, 0, L"r_luma_history" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 5, 0, L"rw_reconstructed_previous_nearest_depth" },
|
||||
FfxResourceBinding{ 6, 0, L"rw_dilated_motion_vectors" },
|
||||
FfxResourceBinding{ 7, 0, L"rw_dilatedDepth" },
|
||||
FfxResourceBinding{ 8, 0, L"rw_prepared_input_color" },
|
||||
FfxResourceBinding{ 9, 0, L"rw_luma_history" },
|
||||
// FSR2_BIND_UAV_LUMA_INSTABILITY (10) does not point to anything.
|
||||
FfxResourceBinding{ 11, 0, L"rw_lock_input_luma" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 12, 0, L"cbFSR2" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_LOCK];
|
||||
pass.shader = &shaders.lock;
|
||||
pass.shader->initialize(modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported ? 1 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_lock_input_luma" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 1, 0, L"rw_new_locks" },
|
||||
FfxResourceBinding{ 2, 0, L"rw_reconstructed_previous_nearest_depth" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 3, 0, L"cbFSR2" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Vector<String> accumulate_modes_with_fp16;
|
||||
accumulate_modes_with_fp16.push_back("\n");
|
||||
accumulate_modes_with_fp16.push_back("\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
|
||||
accumulate_modes_with_fp16.push_back("\n#define FFX_HALF 1\n");
|
||||
accumulate_modes_with_fp16.push_back("\n#define FFX_HALF 1\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
|
||||
|
||||
// Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
|
||||
const bool fp16_path_supported = RD::get_singleton()->get_device_vendor_name() != "NVIDIA";
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_ACCUMULATE];
|
||||
pass.shader = &shaders.accumulate;
|
||||
pass.shader->initialize(accumulate_modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported && fp16_path_supported ? 2 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_exposure" },
|
||||
FfxResourceBinding{ 1, 0, L"r_dilated_reactive_masks" },
|
||||
FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
|
||||
FfxResourceBinding{ 3, 0, L"r_internal_upscaled_color" },
|
||||
FfxResourceBinding{ 4, 0, L"r_lock_status" },
|
||||
FfxResourceBinding{ 5, 0, L"r_input_depth" },
|
||||
FfxResourceBinding{ 6, 0, L"r_prepared_input_color" },
|
||||
// FSR2_BIND_SRV_LUMA_INSTABILITY(7) does not point to anything.
|
||||
FfxResourceBinding{ 8, 0, L"r_lanczos_lut" },
|
||||
FfxResourceBinding{ 9, 0, L"r_upsample_maximum_bias_lut" },
|
||||
FfxResourceBinding{ 10, 0, L"r_imgMips" },
|
||||
FfxResourceBinding{ 11, 0, L"r_auto_exposure" },
|
||||
FfxResourceBinding{ 12, 0, L"r_luma_history" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 13, 0, L"rw_internal_upscaled_color" },
|
||||
FfxResourceBinding{ 14, 0, L"rw_lock_status" },
|
||||
FfxResourceBinding{ 15, 0, L"rw_upscaled_output" },
|
||||
FfxResourceBinding{ 16, 0, L"rw_new_locks" },
|
||||
FfxResourceBinding{ 17, 0, L"rw_luma_history" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 18, 0, L"cbFSR2" }
|
||||
};
|
||||
|
||||
// Sharpen pass is a clone of the accumulate pass with the sharpening variant.
|
||||
Pass &sharpen_pass = device.passes[FFX_FSR2_PASS_ACCUMULATE_SHARPEN];
|
||||
sharpen_pass = pass;
|
||||
sharpen_pass.shader_variant = pass.shader_variant + 1;
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_RCAS];
|
||||
pass.shader = &shaders.rcas;
|
||||
pass.shader->initialize(modes_single, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_exposure" },
|
||||
FfxResourceBinding{ 1, 0, L"r_rcas_input" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 2, 0, L"rw_upscaled_output" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 3, 0, L"cbFSR2" },
|
||||
FfxResourceBinding{ 4, 0, L"cbRCAS" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID];
|
||||
pass.shader = &shaders.compute_luminance_pyramid;
|
||||
pass.shader->initialize(modes_single, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_color_jittered" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 1, 0, L"rw_spd_global_atomic" },
|
||||
FfxResourceBinding{ 2, 0, L"rw_img_mip_shading_change" },
|
||||
FfxResourceBinding{ 3, 0, L"rw_img_mip_5" },
|
||||
FfxResourceBinding{ 4, 0, L"rw_auto_exposure" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 5, 0, L"cbFSR2" },
|
||||
FfxResourceBinding{ 6, 0, L"cbSPD" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_GENERATE_REACTIVE];
|
||||
pass.shader = &shaders.autogen_reactive;
|
||||
pass.shader->initialize(modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported ? 1 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
|
||||
FfxResourceBinding{ 1, 0, L"r_input_color_jittered" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 2, 0, L"rw_output_autoreactive" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 3, 0, L"cbGenerateReactive" },
|
||||
FfxResourceBinding{ 4, 0, L"cbFSR2" }
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_TCR_AUTOGENERATE];
|
||||
pass.shader = &shaders.tcr_autogen;
|
||||
pass.shader->initialize(modes_with_fp16, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
pass.shader_variant = capabilities.fp16Supported ? 1 : 0;
|
||||
|
||||
pass.sampled_bindings = {
|
||||
FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
|
||||
FfxResourceBinding{ 1, 0, L"r_input_color_jittered" },
|
||||
FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
|
||||
FfxResourceBinding{ 3, 0, L"r_input_prev_color_pre_alpha" },
|
||||
FfxResourceBinding{ 4, 0, L"r_input_prev_color_post_alpha" },
|
||||
FfxResourceBinding{ 5, 0, L"r_reactive_mask" },
|
||||
FfxResourceBinding{ 6, 0, L"r_transparency_and_composition_mask" },
|
||||
FfxResourceBinding{ 13, 0, L"r_input_depth" }
|
||||
};
|
||||
|
||||
pass.storage_bindings = {
|
||||
FfxResourceBinding{ 7, 0, L"rw_output_autoreactive" },
|
||||
FfxResourceBinding{ 8, 0, L"rw_output_autocomposition" },
|
||||
FfxResourceBinding{ 9, 0, L"rw_output_prev_color_pre_alpha" },
|
||||
FfxResourceBinding{ 10, 0, L"rw_output_prev_color_post_alpha" }
|
||||
};
|
||||
|
||||
pass.uniform_bindings = {
|
||||
FfxResourceBinding{ 11, 0, L"cbFSR2" },
|
||||
FfxResourceBinding{ 12, 0, L"cbGenerateReactive" }
|
||||
};
|
||||
}
|
||||
|
||||
RD::SamplerState state;
|
||||
state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
|
||||
state.min_filter = RD::SAMPLER_FILTER_NEAREST;
|
||||
state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
|
||||
state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
|
||||
state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
|
||||
state.min_lod = -1000.0f;
|
||||
state.max_lod = 1000.0f;
|
||||
state.anisotropy_max = 1.0;
|
||||
device.point_clamp_sampler = RD::get_singleton()->sampler_create(state);
|
||||
ERR_FAIL_COND(device.point_clamp_sampler.is_null());
|
||||
|
||||
state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
state.min_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
device.linear_clamp_sampler = RD::get_singleton()->sampler_create(state);
|
||||
ERR_FAIL_COND(device.linear_clamp_sampler.is_null());
|
||||
}
|
||||
|
||||
FSR2Effect::~FSR2Effect() {
|
||||
RD::get_singleton()->free(device.point_clamp_sampler);
|
||||
RD::get_singleton()->free(device.linear_clamp_sampler);
|
||||
|
||||
for (uint32_t i = 0; i < FFX_FSR2_PASS_COUNT; i++) {
|
||||
device.passes[i].shader->version_free(device.passes[i].shader_version);
|
||||
}
|
||||
}
|
||||
|
||||
FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) {
|
||||
FSR2Context *context = memnew(RendererRD::FSR2Context);
|
||||
context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED;
|
||||
context->fsr_desc.maxRenderSize.width = p_internal_size.x;
|
||||
context->fsr_desc.maxRenderSize.height = p_internal_size.y;
|
||||
context->fsr_desc.displaySize.width = p_target_size.x;
|
||||
context->fsr_desc.displaySize.height = p_target_size.y;
|
||||
context->fsr_desc.device = &device;
|
||||
|
||||
FfxFsr2Interface &functions = context->fsr_desc.callbacks;
|
||||
functions.fpCreateBackendContext = create_backend_context_rd;
|
||||
functions.fpGetDeviceCapabilities = get_device_capabilities_rd;
|
||||
functions.fpDestroyBackendContext = destroy_backend_context_rd;
|
||||
functions.fpCreateResource = create_resource_rd;
|
||||
functions.fpRegisterResource = register_resource_rd;
|
||||
functions.fpUnregisterResources = unregister_resources_rd;
|
||||
functions.fpGetResourceDescription = get_resource_description_rd;
|
||||
functions.fpDestroyResource = destroy_resource_rd;
|
||||
functions.fpCreatePipeline = create_pipeline_rd;
|
||||
functions.fpDestroyPipeline = destroy_pipeline_rd;
|
||||
functions.fpScheduleGpuJob = schedule_gpu_job_rd;
|
||||
functions.fpExecuteGpuJobs = execute_gpu_jobs_rd;
|
||||
functions.scratchBuffer = &context->scratch;
|
||||
functions.scratchBufferSize = sizeof(context->scratch);
|
||||
|
||||
FfxErrorCode result = ffxFsr2ContextCreate(&context->fsr_context, &context->fsr_desc);
|
||||
if (result == FFX_OK) {
|
||||
return context;
|
||||
} else {
|
||||
memdelete(context);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FSR2Effect::upscale(const Parameters &p_params) {
|
||||
// TODO: Transparency & Composition mask is not implemented.
|
||||
FfxFsr2DispatchDescription dispatch_desc = {};
|
||||
RID color = p_params.color;
|
||||
RID depth = p_params.depth;
|
||||
RID velocity = p_params.velocity;
|
||||
RID reactive = p_params.reactive;
|
||||
RID exposure = p_params.exposure;
|
||||
RID output = p_params.output;
|
||||
dispatch_desc.commandList = nullptr;
|
||||
dispatch_desc.color = get_resource_rd(&color, L"color");
|
||||
dispatch_desc.depth = get_resource_rd(&depth, L"depth");
|
||||
dispatch_desc.motionVectors = get_resource_rd(&velocity, L"velocity");
|
||||
dispatch_desc.reactive = get_resource_rd(&reactive, L"reactive");
|
||||
dispatch_desc.exposure = get_resource_rd(&exposure, L"exposure");
|
||||
dispatch_desc.transparencyAndComposition = {};
|
||||
dispatch_desc.output = get_resource_rd(&output, L"output");
|
||||
dispatch_desc.colorOpaqueOnly = {};
|
||||
dispatch_desc.jitterOffset.x = p_params.jitter.x;
|
||||
dispatch_desc.jitterOffset.y = p_params.jitter.y;
|
||||
dispatch_desc.motionVectorScale.x = float(p_params.internal_size.width);
|
||||
dispatch_desc.motionVectorScale.y = float(p_params.internal_size.height);
|
||||
dispatch_desc.reset = p_params.reset_accumulation;
|
||||
dispatch_desc.renderSize.width = p_params.internal_size.width;
|
||||
dispatch_desc.renderSize.height = p_params.internal_size.height;
|
||||
dispatch_desc.enableSharpening = (p_params.sharpness > 1e-6f);
|
||||
dispatch_desc.sharpness = p_params.sharpness;
|
||||
dispatch_desc.frameTimeDelta = p_params.delta_time;
|
||||
dispatch_desc.preExposure = 1.0f;
|
||||
dispatch_desc.cameraNear = p_params.z_near;
|
||||
dispatch_desc.cameraFar = p_params.z_far;
|
||||
dispatch_desc.cameraFovAngleVertical = p_params.fovy;
|
||||
dispatch_desc.viewSpaceToMetersFactor = 1.0f;
|
||||
dispatch_desc.enableAutoReactive = false;
|
||||
dispatch_desc.autoTcThreshold = 1.0f;
|
||||
dispatch_desc.autoTcScale = 1.0f;
|
||||
dispatch_desc.autoReactiveScale = 1.0f;
|
||||
dispatch_desc.autoReactiveMax = 1.0f;
|
||||
|
||||
RendererRD::MaterialStorage::store_camera(p_params.reprojection, dispatch_desc.reprojectionMatrix);
|
||||
|
||||
FfxErrorCode result = ffxFsr2ContextDispatch(&p_params.context->fsr_context, &dispatch_desc);
|
||||
ERR_FAIL_COND(result != FFX_OK);
|
||||
}
|
196
servers/rendering/renderer_rd/effects/fsr2.h
Normal file
196
servers/rendering/renderer_rd/effects/fsr2.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/**************************************************************************/
|
||||
/* fsr2.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl.gen.h"
|
||||
|
||||
// This flag doesn't actually control anything GCC specific in FSR2. It determines
|
||||
// if symbols should be exported, which is not required for Godot.
|
||||
#ifndef FFX_GCC
|
||||
#define FFX_GCC
|
||||
#endif
|
||||
|
||||
#include "thirdparty/amd-fsr2/ffx_fsr2.h"
|
||||
|
||||
#define FSR2_MAX_QUEUED_FRAMES (4)
|
||||
#define FSR2_MAX_UNIFORM_BUFFERS (4)
|
||||
#define FSR2_MAX_BUFFERED_DESCRIPTORS (FFX_FSR2_PASS_COUNT * FSR2_MAX_QUEUED_FRAMES)
|
||||
#define FSR2_UBO_RING_BUFFER_SIZE (FSR2_MAX_BUFFERED_DESCRIPTORS * FSR2_MAX_UNIFORM_BUFFERS)
|
||||
|
||||
namespace RendererRD {
|
||||
class FSR2Context {
|
||||
public:
|
||||
enum ResourceID : uint32_t {
|
||||
RESOURCE_ID_DYNAMIC = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
struct Resources {
|
||||
LocalVector<RID> rids;
|
||||
LocalVector<LocalVector<RID>> mip_slice_rids;
|
||||
LocalVector<uint32_t> ids;
|
||||
LocalVector<FfxResourceDescription> descriptions;
|
||||
LocalVector<uint32_t> dynamic_list;
|
||||
LocalVector<uint32_t> free_list;
|
||||
|
||||
uint32_t add(RID p_rid, bool p_dynamic, uint32_t p_id, FfxResourceDescription p_description) {
|
||||
uint32_t ret_index;
|
||||
if (free_list.is_empty()) {
|
||||
ret_index = rids.size();
|
||||
uint32_t new_size = ret_index + 1;
|
||||
rids.resize(new_size);
|
||||
mip_slice_rids.resize(new_size);
|
||||
ids.resize(new_size);
|
||||
descriptions.resize(new_size);
|
||||
} else {
|
||||
uint32_t end_index = free_list.size() - 1;
|
||||
ret_index = free_list[end_index];
|
||||
free_list.resize(end_index);
|
||||
}
|
||||
|
||||
rids[ret_index] = p_rid;
|
||||
mip_slice_rids[ret_index].clear();
|
||||
ids[ret_index] = p_id;
|
||||
descriptions[ret_index] = p_description;
|
||||
|
||||
if (p_dynamic) {
|
||||
dynamic_list.push_back(ret_index);
|
||||
}
|
||||
|
||||
return ret_index;
|
||||
}
|
||||
|
||||
void remove(uint32_t p_index) {
|
||||
DEV_ASSERT(p_index < rids.size());
|
||||
free_list.push_back(p_index);
|
||||
rids[p_index] = RID();
|
||||
mip_slice_rids[p_index].clear();
|
||||
ids[p_index] = 0;
|
||||
descriptions[p_index] = {};
|
||||
dynamic_list.erase(p_index);
|
||||
}
|
||||
|
||||
uint32_t size() const {
|
||||
return rids.size();
|
||||
}
|
||||
};
|
||||
|
||||
struct Scratch {
|
||||
Resources resources;
|
||||
LocalVector<FfxGpuJobDescription> gpu_jobs;
|
||||
RID ubo_ring_buffer[FSR2_UBO_RING_BUFFER_SIZE];
|
||||
uint32_t ubo_ring_buffer_index = 0;
|
||||
FfxDevice device = nullptr;
|
||||
};
|
||||
|
||||
Scratch scratch;
|
||||
FfxFsr2Context fsr_context;
|
||||
FfxFsr2ContextDescription fsr_desc;
|
||||
|
||||
~FSR2Context();
|
||||
};
|
||||
|
||||
class FSR2Effect {
|
||||
public:
|
||||
struct RootSignature {
|
||||
// Proxy structure to store the shader required by RD that uses the terminology used by the FSR2 API.
|
||||
RID shader_rid;
|
||||
};
|
||||
|
||||
struct Pipeline {
|
||||
RID pipeline_rid;
|
||||
};
|
||||
|
||||
struct Pass {
|
||||
ShaderRD *shader;
|
||||
RID shader_version;
|
||||
RootSignature root_signature;
|
||||
uint32_t shader_variant = 0;
|
||||
Pipeline pipeline;
|
||||
Vector<FfxResourceBinding> sampled_bindings;
|
||||
Vector<FfxResourceBinding> storage_bindings;
|
||||
Vector<FfxResourceBinding> uniform_bindings;
|
||||
};
|
||||
|
||||
struct Device {
|
||||
Pass passes[FFX_FSR2_PASS_COUNT];
|
||||
FfxDeviceCapabilities capabilities;
|
||||
RID point_clamp_sampler;
|
||||
RID linear_clamp_sampler;
|
||||
};
|
||||
|
||||
struct Parameters {
|
||||
FSR2Context *context;
|
||||
Size2i internal_size;
|
||||
RID color;
|
||||
RID depth;
|
||||
RID velocity;
|
||||
RID reactive;
|
||||
RID exposure;
|
||||
RID output;
|
||||
float z_near = 0.0f;
|
||||
float z_far = 0.0f;
|
||||
float fovy = 0.0f;
|
||||
Vector2 jitter;
|
||||
float delta_time = 0.0f;
|
||||
float sharpness = 0.0f;
|
||||
bool reset_accumulation = false;
|
||||
Projection reprojection;
|
||||
};
|
||||
|
||||
FSR2Effect();
|
||||
~FSR2Effect();
|
||||
FSR2Context *create_context(Size2i p_internal_size, Size2i p_target_size);
|
||||
void upscale(const Parameters &p_params);
|
||||
|
||||
private:
|
||||
struct {
|
||||
Fsr2DepthClipPassShaderRD depth_clip;
|
||||
Fsr2ReconstructPreviousDepthPassShaderRD reconstruct_previous_depth;
|
||||
Fsr2LockPassShaderRD lock;
|
||||
Fsr2AccumulatePassShaderRD accumulate;
|
||||
Fsr2AccumulatePassShaderRD accumulate_sharpen;
|
||||
Fsr2RcasPassShaderRD rcas;
|
||||
Fsr2ComputeLuminancePyramidPassShaderRD compute_luminance_pyramid;
|
||||
Fsr2AutogenReactivePassShaderRD autogen_reactive;
|
||||
Fsr2TcrAutogenPassShaderRD tcr_autogen;
|
||||
} shaders;
|
||||
|
||||
Device device;
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
256
servers/rendering/renderer_rd/effects/luminance.cpp
Normal file
256
servers/rendering/renderer_rd/effects/luminance.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/**************************************************************************/
|
||||
/* luminance.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "luminance.h"
|
||||
#include "../framebuffer_cache_rd.h"
|
||||
#include "../uniform_set_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
Luminance::Luminance(bool p_prefer_raster_effects) {
|
||||
prefer_raster_effects = p_prefer_raster_effects;
|
||||
|
||||
if (prefer_raster_effects) {
|
||||
Vector<String> luminance_reduce_modes;
|
||||
luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST
|
||||
luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT
|
||||
luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL
|
||||
|
||||
luminance_reduce_raster.shader.initialize(luminance_reduce_modes);
|
||||
luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create();
|
||||
|
||||
for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
|
||||
luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
}
|
||||
} else {
|
||||
// Initialize luminance_reduce
|
||||
Vector<String> luminance_reduce_modes;
|
||||
luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n");
|
||||
luminance_reduce_modes.push_back("\n");
|
||||
luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n");
|
||||
|
||||
luminance_reduce.shader.initialize(luminance_reduce_modes);
|
||||
luminance_reduce.shader_version = luminance_reduce.shader.version_create();
|
||||
|
||||
for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) {
|
||||
luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
|
||||
luminance_reduce_raster.pipelines[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Luminance::~Luminance() {
|
||||
if (prefer_raster_effects) {
|
||||
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
|
||||
} else {
|
||||
luminance_reduce.shader.version_free(luminance_reduce.shader_version);
|
||||
}
|
||||
}
|
||||
|
||||
void Luminance::LuminanceBuffers::set_prefer_raster_effects(bool p_prefer_raster_effects) {
|
||||
prefer_raster_effects = p_prefer_raster_effects;
|
||||
}
|
||||
|
||||
void Luminance::LuminanceBuffers::configure(RenderSceneBuffersRD *p_render_buffers) {
|
||||
Size2i internal_size = p_render_buffers->get_internal_size();
|
||||
int w = internal_size.x;
|
||||
int h = internal_size.y;
|
||||
|
||||
while (true) {
|
||||
w = MAX(w / 8, 1);
|
||||
h = MAX(h / 8, 1);
|
||||
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
|
||||
tf.width = w;
|
||||
tf.height = h;
|
||||
|
||||
bool final = w == 1 && h == 1;
|
||||
|
||||
if (prefer_raster_effects) {
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
} else {
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
|
||||
if (final) {
|
||||
tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
|
||||
}
|
||||
|
||||
RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
reduce.push_back(texture);
|
||||
|
||||
if (final) {
|
||||
current = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
RD::get_singleton()->texture_clear(current, Color(0.0, 0.0, 0.0), 0u, 1u, 0u, 1u);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Luminance::LuminanceBuffers::free_data() {
|
||||
for (int i = 0; i < reduce.size(); i++) {
|
||||
RD::get_singleton()->free(reduce[i]);
|
||||
}
|
||||
reduce.clear();
|
||||
|
||||
if (current.is_valid()) {
|
||||
RD::get_singleton()->free(current);
|
||||
current = RID();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Luminance::LuminanceBuffers> Luminance::get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers) {
|
||||
if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) {
|
||||
return p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS);
|
||||
}
|
||||
|
||||
Ref<LuminanceBuffers> buffers;
|
||||
buffers.instantiate();
|
||||
buffers->set_prefer_raster_effects(prefer_raster_effects);
|
||||
buffers->configure(p_render_buffers.ptr());
|
||||
|
||||
p_render_buffers->set_custom_data(RB_LUMINANCE_BUFFERS, buffers);
|
||||
|
||||
return buffers;
|
||||
}
|
||||
|
||||
RID Luminance::get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers) {
|
||||
if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) {
|
||||
Ref<LuminanceBuffers> buffers = p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS);
|
||||
return buffers->current;
|
||||
}
|
||||
|
||||
return RID();
|
||||
}
|
||||
|
||||
void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
// setup our uniforms
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
if (prefer_raster_effects) {
|
||||
LuminanceReduceRasterPushConstant push_constant;
|
||||
memset(&push_constant, 0, sizeof(LuminanceReduceRasterPushConstant));
|
||||
|
||||
push_constant.max_luminance = p_max_luminance;
|
||||
push_constant.min_luminance = p_min_luminance;
|
||||
push_constant.exposure_adjust = p_adjust;
|
||||
|
||||
for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) {
|
||||
push_constant.source_size[0] = i == 0 ? p_source_size.x : push_constant.dest_size[0];
|
||||
push_constant.source_size[1] = i == 0 ? p_source_size.y : push_constant.dest_size[1];
|
||||
push_constant.dest_size[0] = MAX(push_constant.source_size[0] / 8, 1);
|
||||
push_constant.dest_size[1] = MAX(push_constant.source_size[1] / 8, 1);
|
||||
|
||||
bool final = !p_set && (push_constant.dest_size[0] == 1) && (push_constant.dest_size[1] == 1);
|
||||
LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT);
|
||||
RID shader = luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, mode);
|
||||
|
||||
RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_luminance_buffers->reduce[i]);
|
||||
|
||||
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, i == 0 ? p_source_texture : p_luminance_buffers->reduce[i - 1] }));
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
|
||||
if (final) {
|
||||
RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current }));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_current_texture), 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(LuminanceReduceRasterPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
} else {
|
||||
LuminanceReducePushConstant push_constant;
|
||||
memset(&push_constant, 0, sizeof(LuminanceReducePushConstant));
|
||||
|
||||
push_constant.source_size[0] = p_source_size.x;
|
||||
push_constant.source_size[1] = p_source_size.y;
|
||||
push_constant.max_luminance = p_max_luminance;
|
||||
push_constant.min_luminance = p_min_luminance;
|
||||
push_constant.exposure_adjust = p_adjust;
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) {
|
||||
RID shader;
|
||||
|
||||
if (i == 0) {
|
||||
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_READ);
|
||||
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_texture }));
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
|
||||
} else {
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done
|
||||
|
||||
if (i == p_luminance_buffers->reduce.size() - 1 && !p_set) {
|
||||
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_WRITE);
|
||||
RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current }));
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_current_texture), 2);
|
||||
} else {
|
||||
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE);
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]);
|
||||
}
|
||||
|
||||
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i - 1]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
|
||||
}
|
||||
|
||||
RD::Uniform u_reduce_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_reduce_texture), 1);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(LuminanceReducePushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.source_size[0], push_constant.source_size[1], 1);
|
||||
|
||||
push_constant.source_size[0] = MAX(push_constant.source_size[0] / 8, 1);
|
||||
push_constant.source_size[1] = MAX(push_constant.source_size[1] / 8, 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
SWAP(p_luminance_buffers->current, p_luminance_buffers->reduce.write[p_luminance_buffers->reduce.size() - 1]);
|
||||
}
|
114
servers/rendering/renderer_rd/effects/luminance.h
Normal file
114
servers/rendering/renderer_rd/effects/luminance.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/* luminance.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
|
||||
|
||||
#define RB_LUMINANCE_BUFFERS SNAME("luminance_buffers")
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class Luminance {
|
||||
private:
|
||||
bool prefer_raster_effects;
|
||||
|
||||
enum LuminanceReduceMode {
|
||||
LUMINANCE_REDUCE_READ,
|
||||
LUMINANCE_REDUCE,
|
||||
LUMINANCE_REDUCE_WRITE,
|
||||
LUMINANCE_REDUCE_MAX
|
||||
};
|
||||
|
||||
struct LuminanceReducePushConstant {
|
||||
int32_t source_size[2];
|
||||
float max_luminance;
|
||||
float min_luminance;
|
||||
float exposure_adjust;
|
||||
float pad[3];
|
||||
};
|
||||
|
||||
struct LuminanceReduce {
|
||||
LuminanceReduceShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[LUMINANCE_REDUCE_MAX];
|
||||
} luminance_reduce;
|
||||
|
||||
enum LuminanceReduceRasterMode {
|
||||
LUMINANCE_REDUCE_FRAGMENT_FIRST,
|
||||
LUMINANCE_REDUCE_FRAGMENT,
|
||||
LUMINANCE_REDUCE_FRAGMENT_FINAL,
|
||||
LUMINANCE_REDUCE_FRAGMENT_MAX
|
||||
};
|
||||
|
||||
struct LuminanceReduceRasterPushConstant {
|
||||
int32_t source_size[2];
|
||||
int32_t dest_size[2];
|
||||
float exposure_adjust;
|
||||
float min_luminance;
|
||||
float max_luminance;
|
||||
uint32_t pad1;
|
||||
};
|
||||
|
||||
struct LuminanceReduceFragment {
|
||||
LuminanceReduceRasterShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
|
||||
} luminance_reduce_raster;
|
||||
|
||||
public:
|
||||
class LuminanceBuffers : public RenderBufferCustomDataRD {
|
||||
GDCLASS(LuminanceBuffers, RenderBufferCustomDataRD);
|
||||
|
||||
private:
|
||||
bool prefer_raster_effects;
|
||||
|
||||
public:
|
||||
Vector<RID> reduce;
|
||||
RID current;
|
||||
|
||||
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
|
||||
virtual void free_data() override;
|
||||
|
||||
void set_prefer_raster_effects(bool p_prefer_raster_effects);
|
||||
};
|
||||
|
||||
Ref<LuminanceBuffers> get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers);
|
||||
RID get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers);
|
||||
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
|
||||
|
||||
Luminance(bool p_prefer_raster_effects);
|
||||
~Luminance();
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
186
servers/rendering/renderer_rd/effects/metal_fx.h
Normal file
186
servers/rendering/renderer_rd/effects/metal_fx.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/**************************************************************************/
|
||||
/* metal_fx.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(METAL_ENABLED) && !defined(VISIONOS_ENABLED)
|
||||
#define METAL_MFXTEMPORAL_ENABLED
|
||||
#endif
|
||||
|
||||
#ifdef METAL_ENABLED
|
||||
|
||||
#include "spatial_upscaler.h"
|
||||
|
||||
#include "core/templates/paged_allocator.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
@protocol MTLFXSpatialScaler;
|
||||
@protocol MTLFXTemporalScaler;
|
||||
#endif
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
struct MFXSpatialContext {
|
||||
#ifdef __OBJC__
|
||||
id<MTLFXSpatialScaler> scaler = nullptr;
|
||||
#else
|
||||
void *scaler = nullptr;
|
||||
#endif
|
||||
MFXSpatialContext() = default;
|
||||
~MFXSpatialContext();
|
||||
};
|
||||
|
||||
class MFXSpatialEffect : public SpatialUpscaler {
|
||||
struct CallbackArgs {
|
||||
MFXSpatialEffect *owner;
|
||||
RDD::TextureID src;
|
||||
RDD::TextureID dst;
|
||||
MFXSpatialContext ctx;
|
||||
|
||||
CallbackArgs(MFXSpatialEffect *p_owner, RDD::TextureID p_src, RDD::TextureID p_dst, MFXSpatialContext p_ctx) :
|
||||
owner(p_owner), src(p_src), dst(p_dst), ctx(p_ctx) {}
|
||||
|
||||
static void free(CallbackArgs **p_args) {
|
||||
(*p_args)->owner->args_allocator.free(*p_args);
|
||||
*p_args = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
PagedAllocator<CallbackArgs, true, 16> args_allocator;
|
||||
static void callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata);
|
||||
|
||||
public:
|
||||
virtual const Span<char> get_label() const final { return "MetalFX Spatial Upscale"; }
|
||||
virtual void ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) final;
|
||||
virtual void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_src, RID p_dst) final;
|
||||
|
||||
struct CreateParams {
|
||||
Vector2i input_size;
|
||||
Vector2i output_size;
|
||||
RD::DataFormat input_format;
|
||||
RD::DataFormat output_format;
|
||||
};
|
||||
|
||||
MFXSpatialContext *create_context(CreateParams p_params) const;
|
||||
|
||||
MFXSpatialEffect();
|
||||
~MFXSpatialEffect();
|
||||
};
|
||||
|
||||
#ifdef METAL_MFXTEMPORAL_ENABLED
|
||||
|
||||
struct MFXTemporalContext {
|
||||
#ifdef __OBJC__
|
||||
id<MTLFXTemporalScaler> scaler = nullptr;
|
||||
#else
|
||||
void *scaler = nullptr;
|
||||
#endif
|
||||
MFXTemporalContext() = default;
|
||||
~MFXTemporalContext();
|
||||
};
|
||||
|
||||
class MFXTemporalEffect {
|
||||
struct CallbackArgs {
|
||||
MFXTemporalEffect *owner;
|
||||
RDD::TextureID src;
|
||||
RDD::TextureID depth;
|
||||
RDD::TextureID motion;
|
||||
RDD::TextureID exposure;
|
||||
Vector2 jitter_offset;
|
||||
RDD::TextureID dst;
|
||||
MFXTemporalContext ctx;
|
||||
bool reset = false;
|
||||
|
||||
CallbackArgs(
|
||||
MFXTemporalEffect *p_owner,
|
||||
RDD::TextureID p_src,
|
||||
RDD::TextureID p_depth,
|
||||
RDD::TextureID p_motion,
|
||||
RDD::TextureID p_exposure,
|
||||
Vector2 p_jitter_offset,
|
||||
RDD::TextureID p_dst,
|
||||
MFXTemporalContext p_ctx,
|
||||
bool p_reset) :
|
||||
owner(p_owner),
|
||||
src(p_src),
|
||||
depth(p_depth),
|
||||
motion(p_motion),
|
||||
exposure(p_exposure),
|
||||
jitter_offset(p_jitter_offset),
|
||||
dst(p_dst),
|
||||
ctx(p_ctx),
|
||||
reset(p_reset) {}
|
||||
|
||||
static void free(CallbackArgs **p_args) {
|
||||
(*p_args)->owner->args_allocator.free(*p_args);
|
||||
*p_args = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
PagedAllocator<CallbackArgs, true, 16> args_allocator;
|
||||
|
||||
static void callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata);
|
||||
|
||||
public:
|
||||
MFXTemporalEffect();
|
||||
~MFXTemporalEffect();
|
||||
|
||||
struct CreateParams {
|
||||
Vector2i input_size;
|
||||
Vector2i output_size;
|
||||
RD::DataFormat input_format;
|
||||
RD::DataFormat depth_format;
|
||||
RD::DataFormat motion_format;
|
||||
RD::DataFormat reactive_format;
|
||||
RD::DataFormat output_format;
|
||||
Vector2 motion_vector_scale;
|
||||
};
|
||||
|
||||
MFXTemporalContext *create_context(CreateParams p_params) const;
|
||||
|
||||
struct Params {
|
||||
RID src;
|
||||
RID depth;
|
||||
RID motion;
|
||||
RID exposure;
|
||||
RID dst;
|
||||
Vector2 jitter_offset;
|
||||
bool reset = false;
|
||||
};
|
||||
|
||||
void process(MFXTemporalContext *p_ctx, Params p_params);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace RendererRD
|
||||
|
||||
#endif // METAL_ENABLED
|
225
servers/rendering/renderer_rd/effects/metal_fx.mm
Normal file
225
servers/rendering/renderer_rd/effects/metal_fx.mm
Normal file
@@ -0,0 +1,225 @@
|
||||
/**************************************************************************/
|
||||
/* metal_fx.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "metal_fx.h"
|
||||
|
||||
#import "../storage_rd/render_scene_buffers_rd.h"
|
||||
#import "drivers/metal/pixel_formats.h"
|
||||
#import "drivers/metal/rendering_device_driver_metal.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalFX/MetalFX.h>
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
#pragma mark - Spatial Scaler
|
||||
|
||||
MFXSpatialContext::~MFXSpatialContext() {
|
||||
}
|
||||
|
||||
MFXSpatialEffect::MFXSpatialEffect() {
|
||||
}
|
||||
|
||||
MFXSpatialEffect::~MFXSpatialEffect() {
|
||||
}
|
||||
|
||||
void MFXSpatialEffect::callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
MDCommandBuffer *obj = (MDCommandBuffer *)(p_command_buffer.id);
|
||||
obj->end();
|
||||
|
||||
id<MTLTexture> src_texture = rid::get(p_userdata->src);
|
||||
id<MTLTexture> dst_texture = rid::get(p_userdata->dst);
|
||||
|
||||
__block id<MTLFXSpatialScaler> scaler = p_userdata->ctx.scaler;
|
||||
scaler.colorTexture = src_texture;
|
||||
scaler.outputTexture = dst_texture;
|
||||
[scaler encodeToCommandBuffer:obj->get_command_buffer()];
|
||||
// TODO(sgc): add API to retain objects until the command buffer completes
|
||||
[obj->get_command_buffer() addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
|
||||
// This block retains a reference to the scaler until the command buffer.
|
||||
// completes.
|
||||
scaler = nil;
|
||||
}];
|
||||
|
||||
CallbackArgs::free(&p_userdata);
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
}
|
||||
|
||||
void MFXSpatialEffect::ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) {
|
||||
p_render_buffers->ensure_mfx(this);
|
||||
}
|
||||
|
||||
void MFXSpatialEffect::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_src, RID p_dst) {
|
||||
MFXSpatialContext *ctx = p_render_buffers->get_mfx_spatial_context();
|
||||
DEV_ASSERT(ctx); // this should have been done by the caller via ensure_context
|
||||
|
||||
CallbackArgs *userdata = args_allocator.alloc(
|
||||
this,
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_src)),
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_dst)),
|
||||
*ctx);
|
||||
RD::CallbackResource res[2] = {
|
||||
{ .rid = p_src, .usage = RD::CALLBACK_RESOURCE_USAGE_TEXTURE_SAMPLE },
|
||||
{ .rid = p_dst, .usage = RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE }
|
||||
};
|
||||
RD::get_singleton()->driver_callback_add((RDD::DriverCallback)MFXSpatialEffect::callback, userdata, VectorView<RD::CallbackResource>(res, 2));
|
||||
}
|
||||
|
||||
MFXSpatialContext *MFXSpatialEffect::create_context(CreateParams p_params) const {
|
||||
DEV_ASSERT(RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_SPATIAL));
|
||||
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
RenderingDeviceDriverMetal *rdd = (RenderingDeviceDriverMetal *)RD::get_singleton()->get_device_driver();
|
||||
PixelFormats &pf = rdd->get_pixel_formats();
|
||||
id<MTLDevice> dev = rdd->get_device();
|
||||
|
||||
MTLFXSpatialScalerDescriptor *desc = [MTLFXSpatialScalerDescriptor new];
|
||||
desc.inputWidth = (NSUInteger)p_params.input_size.width;
|
||||
desc.inputHeight = (NSUInteger)p_params.input_size.height;
|
||||
|
||||
desc.outputWidth = (NSUInteger)p_params.output_size.width;
|
||||
desc.outputHeight = (NSUInteger)p_params.output_size.height;
|
||||
|
||||
desc.colorTextureFormat = pf.getMTLPixelFormat(p_params.input_format);
|
||||
desc.outputTextureFormat = pf.getMTLPixelFormat(p_params.output_format);
|
||||
desc.colorProcessingMode = MTLFXSpatialScalerColorProcessingModeLinear;
|
||||
id<MTLFXSpatialScaler> scaler = [desc newSpatialScalerWithDevice:dev];
|
||||
MFXSpatialContext *context = memnew(MFXSpatialContext);
|
||||
context->scaler = scaler;
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
#ifdef METAL_MFXTEMPORAL_ENABLED
|
||||
|
||||
#pragma mark - Temporal Scaler
|
||||
|
||||
MFXTemporalContext::~MFXTemporalContext() {}
|
||||
|
||||
MFXTemporalEffect::MFXTemporalEffect() {}
|
||||
MFXTemporalEffect::~MFXTemporalEffect() {}
|
||||
|
||||
MFXTemporalContext *MFXTemporalEffect::create_context(CreateParams p_params) const {
|
||||
DEV_ASSERT(RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_TEMPORAL));
|
||||
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
RenderingDeviceDriverMetal *rdd = (RenderingDeviceDriverMetal *)RD::get_singleton()->get_device_driver();
|
||||
PixelFormats &pf = rdd->get_pixel_formats();
|
||||
id<MTLDevice> dev = rdd->get_device();
|
||||
|
||||
MTLFXTemporalScalerDescriptor *desc = [MTLFXTemporalScalerDescriptor new];
|
||||
desc.inputWidth = (NSUInteger)p_params.input_size.width;
|
||||
desc.inputHeight = (NSUInteger)p_params.input_size.height;
|
||||
|
||||
desc.outputWidth = (NSUInteger)p_params.output_size.width;
|
||||
desc.outputHeight = (NSUInteger)p_params.output_size.height;
|
||||
|
||||
desc.colorTextureFormat = pf.getMTLPixelFormat(p_params.input_format);
|
||||
desc.depthTextureFormat = pf.getMTLPixelFormat(p_params.depth_format);
|
||||
desc.motionTextureFormat = pf.getMTLPixelFormat(p_params.motion_format);
|
||||
desc.autoExposureEnabled = NO;
|
||||
|
||||
desc.outputTextureFormat = pf.getMTLPixelFormat(p_params.output_format);
|
||||
|
||||
id<MTLFXTemporalScaler> scaler = [desc newTemporalScalerWithDevice:dev];
|
||||
MFXTemporalContext *context = memnew(MFXTemporalContext);
|
||||
context->scaler = scaler;
|
||||
|
||||
scaler.motionVectorScaleX = p_params.motion_vector_scale.x;
|
||||
scaler.motionVectorScaleY = p_params.motion_vector_scale.y;
|
||||
scaler.depthReversed = true; // Godot uses reverse Z per https://github.com/godotengine/godot/pull/88328
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void MFXTemporalEffect::process(RendererRD::MFXTemporalContext *p_ctx, RendererRD::MFXTemporalEffect::Params p_params) {
|
||||
CallbackArgs *userdata = args_allocator.alloc(
|
||||
this,
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_params.src)),
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_params.depth)),
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_params.motion)),
|
||||
p_params.exposure.is_valid() ? RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_params.exposure)) : RDD::TextureID(),
|
||||
p_params.jitter_offset,
|
||||
RDD::TextureID(RD::get_singleton()->get_driver_resource(RDC::DRIVER_RESOURCE_TEXTURE, p_params.dst)),
|
||||
*p_ctx,
|
||||
p_params.reset);
|
||||
RD::CallbackResource res[3] = {
|
||||
{ .rid = p_params.src, .usage = RD::CALLBACK_RESOURCE_USAGE_TEXTURE_SAMPLE },
|
||||
{ .rid = p_params.depth, .usage = RD::CALLBACK_RESOURCE_USAGE_TEXTURE_SAMPLE },
|
||||
{ .rid = p_params.dst, .usage = RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE },
|
||||
};
|
||||
RD::get_singleton()->driver_callback_add((RDD::DriverCallback)MFXTemporalEffect::callback, userdata, VectorView<RD::CallbackResource>(res, 3));
|
||||
}
|
||||
|
||||
void MFXTemporalEffect::callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
MDCommandBuffer *obj = (MDCommandBuffer *)(p_command_buffer.id);
|
||||
obj->end();
|
||||
|
||||
id<MTLTexture> src_texture = rid::get(p_userdata->src);
|
||||
id<MTLTexture> depth = rid::get(p_userdata->depth);
|
||||
id<MTLTexture> motion = rid::get(p_userdata->motion);
|
||||
id<MTLTexture> exposure = rid::get(p_userdata->exposure);
|
||||
|
||||
id<MTLTexture> dst_texture = rid::get(p_userdata->dst);
|
||||
|
||||
__block id<MTLFXTemporalScaler> scaler = p_userdata->ctx.scaler;
|
||||
scaler.reset = p_userdata->reset;
|
||||
scaler.colorTexture = src_texture;
|
||||
scaler.depthTexture = depth;
|
||||
scaler.motionTexture = motion;
|
||||
scaler.exposureTexture = exposure;
|
||||
scaler.jitterOffsetX = p_userdata->jitter_offset.x;
|
||||
scaler.jitterOffsetY = p_userdata->jitter_offset.y;
|
||||
scaler.outputTexture = dst_texture;
|
||||
[scaler encodeToCommandBuffer:obj->get_command_buffer()];
|
||||
// TODO(sgc): add API to retain objects until the command buffer completes
|
||||
[obj->get_command_buffer() addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
|
||||
// This block retains a reference to the scaler until the command buffer.
|
||||
// completes.
|
||||
scaler = nil;
|
||||
}];
|
||||
|
||||
CallbackArgs::free(&p_userdata);
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
}
|
||||
|
||||
#endif
|
101
servers/rendering/renderer_rd/effects/motion_vectors_store.cpp
Normal file
101
servers/rendering/renderer_rd/effects/motion_vectors_store.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/**************************************************************************/
|
||||
/* motion_vectors_store.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "motion_vectors_store.h"
|
||||
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
MotionVectorsStore::MotionVectorsStore() {
|
||||
Vector<String> modes;
|
||||
modes.push_back("");
|
||||
|
||||
motion_shader.initialize(modes);
|
||||
shader_version = motion_shader.version_create();
|
||||
|
||||
pipeline = RD::get_singleton()->compute_pipeline_create(motion_shader.version_get_shader(shader_version, 0));
|
||||
}
|
||||
|
||||
MotionVectorsStore::~MotionVectorsStore() {
|
||||
motion_shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void MotionVectorsStore::process(Ref<RenderSceneBuffersRD> p_render_buffers,
|
||||
const Projection &p_current_projection, const Transform3D &p_current_transform,
|
||||
const Projection &p_previous_projection, const Transform3D &p_previous_transform) {
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
|
||||
uint32_t view_count = p_render_buffers->get_view_count();
|
||||
Size2i internal_size = p_render_buffers->get_internal_size();
|
||||
|
||||
PushConstant push_constant;
|
||||
{
|
||||
push_constant.resolution[0] = internal_size.width;
|
||||
push_constant.resolution[1] = internal_size.height;
|
||||
|
||||
Projection correction;
|
||||
correction.set_depth_correction(true, true, false);
|
||||
Projection reprojection = (correction * p_previous_projection) * p_previous_transform.affine_inverse() * p_current_transform * (correction * p_current_projection).inverse();
|
||||
RendererRD::MaterialStorage::store_camera(reprojection, push_constant.reprojection_matrix);
|
||||
}
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
RD::get_singleton()->draw_command_begin_label("Motion Vector Store");
|
||||
|
||||
RID shader = motion_shader.version_get_shader(shader_version, 0);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
|
||||
|
||||
for (uint32_t v = 0; v < view_count; v++) {
|
||||
RID velocity = p_render_buffers->get_velocity_buffer(false, v);
|
||||
RID depth = p_render_buffers->get_depth_texture(v);
|
||||
RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, depth }));
|
||||
RD::Uniform u_velocity(RD::UNIFORM_TYPE_IMAGE, 1, velocity);
|
||||
|
||||
RID uniform_set = uniform_set_cache->get_cache(shader, 0, u_depth, u_velocity);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, internal_size.width, internal_size.height, 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
|
||||
RD::get_singleton()->draw_command_end_label();
|
||||
}
|
||||
|
||||
} //namespace RendererRD
|
59
servers/rendering/renderer_rd/effects/motion_vectors_store.h
Normal file
59
servers/rendering/renderer_rd/effects/motion_vectors_store.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**************************************************************************/
|
||||
/* motion_vectors_store.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/motion_vectors_store.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
namespace RendererRD {
|
||||
class MotionVectorsStore {
|
||||
struct PushConstant {
|
||||
float reprojection_matrix[16];
|
||||
float resolution[2];
|
||||
uint32_t pad[2];
|
||||
};
|
||||
|
||||
MotionVectorsStoreShaderRD motion_shader;
|
||||
RID shader_version;
|
||||
RID pipeline;
|
||||
|
||||
public:
|
||||
MotionVectorsStore();
|
||||
~MotionVectorsStore();
|
||||
|
||||
void process(Ref<RenderSceneBuffersRD> p_render_buffers,
|
||||
const Projection &p_current_projection, const Transform3D &p_current_transform,
|
||||
const Projection &p_previous_projection, const Transform3D &p_previous_transform);
|
||||
};
|
||||
} //namespace RendererRD
|
129
servers/rendering/renderer_rd/effects/resolve.cpp
Normal file
129
servers/rendering/renderer_rd/effects/resolve.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/**************************************************************************/
|
||||
/* resolve.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "resolve.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
Resolve::Resolve() {
|
||||
Vector<String> resolve_modes;
|
||||
resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
|
||||
resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n");
|
||||
resolve_modes.push_back("\n#define MODE_RESOLVE_DEPTH\n");
|
||||
|
||||
resolve.shader.initialize(resolve_modes);
|
||||
|
||||
resolve.shader_version = resolve.shader.version_create();
|
||||
|
||||
for (int i = 0; i < RESOLVE_MODE_MAX; i++) {
|
||||
resolve.pipelines[i] = RD::get_singleton()->compute_pipeline_create(resolve.shader.version_get_shader(resolve.shader_version, i));
|
||||
}
|
||||
}
|
||||
|
||||
Resolve::~Resolve() {
|
||||
resolve.shader.version_free(resolve.shader_version);
|
||||
}
|
||||
|
||||
void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
ResolvePushConstant push_constant;
|
||||
push_constant.screen_size[0] = p_screen_size.x;
|
||||
push_constant.screen_size[1] = p_screen_size.y;
|
||||
push_constant.samples = p_samples;
|
||||
|
||||
// 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_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_depth }));
|
||||
RD::Uniform u_source_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_source_normal_roughness }));
|
||||
RD::Uniform u_dest_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_depth }));
|
||||
RD::Uniform u_dest_normal_roughness(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_dest_normal_roughness }));
|
||||
|
||||
ResolveMode mode = p_source_voxel_gi.is_valid() ? RESOLVE_MODE_GI_VOXEL_GI : RESOLVE_MODE_GI;
|
||||
RID shader = resolve.shader.version_get_shader(resolve.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[mode]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_depth, u_source_normal_roughness), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_depth, u_dest_normal_roughness), 1);
|
||||
if (p_source_voxel_gi.is_valid()) {
|
||||
RD::Uniform u_source_voxel_gi(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_voxel_gi }));
|
||||
RD::Uniform u_dest_voxel_gi(RD::UNIFORM_TYPE_IMAGE, 0, p_dest_voxel_gi);
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_source_voxel_gi), 2);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_voxel_gi), 3);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
ResolvePushConstant push_constant;
|
||||
push_constant.screen_size[0] = p_screen_size.x;
|
||||
push_constant.screen_size[1] = p_screen_size.y;
|
||||
push_constant.samples = p_samples;
|
||||
|
||||
// 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_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_depth }));
|
||||
RD::Uniform u_dest_depth(RD::UNIFORM_TYPE_IMAGE, 0, p_dest_depth);
|
||||
|
||||
ResolveMode mode = RESOLVE_MODE_DEPTH;
|
||||
RID shader = resolve.shader.version_get_shader(resolve.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[mode]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_depth), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_depth), 1);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant));
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
67
servers/rendering/renderer_rd/effects/resolve.h
Normal file
67
servers/rendering/renderer_rd/effects/resolve.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**************************************************************************/
|
||||
/* resolve.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/resolve.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class Resolve {
|
||||
private:
|
||||
struct ResolvePushConstant {
|
||||
int32_t screen_size[2];
|
||||
int32_t samples;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
enum ResolveMode {
|
||||
RESOLVE_MODE_GI,
|
||||
RESOLVE_MODE_GI_VOXEL_GI,
|
||||
RESOLVE_MODE_DEPTH,
|
||||
RESOLVE_MODE_MAX
|
||||
};
|
||||
|
||||
struct ResolveShader {
|
||||
ResolvePushConstant push_constant;
|
||||
ResolveShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels
|
||||
} resolve;
|
||||
|
||||
public:
|
||||
Resolve();
|
||||
~Resolve();
|
||||
|
||||
void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples);
|
||||
void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
79
servers/rendering/renderer_rd/effects/roughness_limiter.cpp
Normal file
79
servers/rendering/renderer_rd/effects/roughness_limiter.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/**************************************************************************/
|
||||
/* roughness_limiter.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "roughness_limiter.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
RoughnessLimiter::RoughnessLimiter() {
|
||||
// Initialize roughness limiter
|
||||
Vector<String> shader_modes;
|
||||
shader_modes.push_back("");
|
||||
|
||||
shader.initialize(shader_modes);
|
||||
|
||||
shader_version = shader.version_create();
|
||||
|
||||
pipeline = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, 0));
|
||||
}
|
||||
|
||||
RoughnessLimiter::~RoughnessLimiter() {
|
||||
shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void RoughnessLimiter::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
push_constant.screen_size[0] = p_size.x;
|
||||
push_constant.screen_size[1] = p_size.y;
|
||||
push_constant.curve = p_curve;
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
RID rl_shader = shader.version_get_shader(shader_version, 0);
|
||||
|
||||
RD::Uniform u_source_normal(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_normal }));
|
||||
RD::Uniform u_roughness(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_roughness }));
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(rl_shader, 0, u_source_normal), 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(rl_shader, 1, u_roughness), 1);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RoughnessLimiterPushConstant)); //not used but set anyway
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_size.x, p_size.y, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
60
servers/rendering/renderer_rd/effects/roughness_limiter.h
Normal file
60
servers/rendering/renderer_rd/effects/roughness_limiter.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/**************************************************************************/
|
||||
/* roughness_limiter.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/roughness_limiter.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
// Note, this logic is unused at the time of writing. It should be re-incorporated into the renderer at some point.
|
||||
|
||||
class RoughnessLimiter {
|
||||
private:
|
||||
struct RoughnessLimiterPushConstant {
|
||||
int32_t screen_size[2];
|
||||
float curve;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
RoughnessLimiterPushConstant push_constant;
|
||||
RoughnessLimiterShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipeline;
|
||||
|
||||
protected:
|
||||
public:
|
||||
RoughnessLimiter();
|
||||
~RoughnessLimiter();
|
||||
|
||||
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
273
servers/rendering/renderer_rd/effects/smaa.cpp
Normal file
273
servers/rendering/renderer_rd/effects/smaa.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
/**************************************************************************/
|
||||
/* smaa.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "smaa.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/image_loader.h"
|
||||
#include "servers/rendering/renderer_rd/effects/smaa_area_tex.gen.h"
|
||||
#include "servers/rendering/renderer_rd/effects/smaa_search_tex.gen.h"
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
SMAA::SMAA() {
|
||||
{
|
||||
// Initialize edge detection.
|
||||
Vector<String> smaa_modes;
|
||||
smaa_modes.push_back("\n");
|
||||
smaa.edge_shader.initialize(smaa_modes);
|
||||
|
||||
smaa.edge_shader_version = smaa.edge_shader.version_create();
|
||||
|
||||
RD::PipelineDepthStencilState stencil_state = RD::PipelineDepthStencilState();
|
||||
stencil_state.enable_stencil = true;
|
||||
stencil_state.back_op.reference = 0xff;
|
||||
stencil_state.back_op.write_mask = 0xff;
|
||||
stencil_state.back_op.compare_mask = 0xff;
|
||||
stencil_state.back_op.pass = RD::STENCIL_OP_REPLACE;
|
||||
stencil_state.front_op.reference = 0xff;
|
||||
stencil_state.front_op.write_mask = 0xff;
|
||||
stencil_state.front_op.compare_mask = 0xff;
|
||||
stencil_state.front_op.pass = RD::STENCIL_OP_REPLACE;
|
||||
|
||||
for (int i = SMAA_EDGE_DETECTION_COLOR; i <= SMAA_EDGE_DETECTION_COLOR; i++) {
|
||||
smaa.pipelines[i].setup(smaa.edge_shader.version_get_shader(smaa.edge_shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
}
|
||||
|
||||
edge_detection_threshold = GLOBAL_GET("rendering/anti_aliasing/quality/smaa_edge_detection_threshold");
|
||||
}
|
||||
|
||||
{
|
||||
// Initialize weight calculation.
|
||||
Vector<String> smaa_modes;
|
||||
smaa_modes.push_back("\n");
|
||||
smaa.weight_shader.initialize(smaa_modes);
|
||||
|
||||
smaa.weight_shader_version = smaa.weight_shader.version_create();
|
||||
|
||||
RD::PipelineDepthStencilState stencil_state;
|
||||
stencil_state.enable_stencil = true;
|
||||
stencil_state.back_op.reference = 0xff;
|
||||
stencil_state.back_op.compare_mask = 0xff;
|
||||
stencil_state.back_op.compare = RD::COMPARE_OP_EQUAL;
|
||||
stencil_state.front_op.reference = 0xff;
|
||||
stencil_state.front_op.compare_mask = 0xff;
|
||||
stencil_state.front_op.compare = RD::COMPARE_OP_EQUAL;
|
||||
|
||||
for (int i = SMAA_WEIGHT_FULL; i <= SMAA_WEIGHT_FULL; i++) {
|
||||
smaa.pipelines[i].setup(smaa.weight_shader.version_get_shader(smaa.weight_shader_version, i - SMAA_WEIGHT_FULL), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Initialize color blending.
|
||||
Vector<String> smaa_modes;
|
||||
smaa_modes.push_back("\n");
|
||||
smaa.blend_shader.initialize(smaa_modes);
|
||||
|
||||
smaa.blend_shader_version = smaa.blend_shader.version_create();
|
||||
|
||||
for (int i = SMAA_BLENDING; i <= SMAA_BLENDING; i++) {
|
||||
smaa.pipelines[i].setup(smaa.blend_shader.version_get_shader(smaa.blend_shader_version, i - SMAA_BLENDING), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Initialize SearchTex.
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R8_UNORM;
|
||||
tf.width = SEARCHTEX_WIDTH;
|
||||
tf.height = SEARCHTEX_HEIGHT;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
|
||||
smaa.search_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(search_tex_png).get_data() });
|
||||
}
|
||||
|
||||
{
|
||||
// Initialize AreaTex.
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R8G8_UNORM;
|
||||
tf.width = AREATEX_WIDTH;
|
||||
tf.height = AREATEX_HEIGHT;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
|
||||
smaa.area_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(area_tex_png).get_data() });
|
||||
}
|
||||
|
||||
{
|
||||
// Find smallest stencil texture format.
|
||||
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
|
||||
smaa.stencil_format = RD::DATA_FORMAT_D16_UNORM_S8_UINT;
|
||||
} else if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
|
||||
smaa.stencil_format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
|
||||
} else {
|
||||
smaa.stencil_format = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SMAA::~SMAA() {
|
||||
RD::get_singleton()->free(smaa.search_tex);
|
||||
RD::get_singleton()->free(smaa.area_tex);
|
||||
|
||||
smaa.edge_shader.version_free(smaa.edge_shader_version);
|
||||
smaa.weight_shader.version_free(smaa.weight_shader_version);
|
||||
smaa.blend_shader.version_free(smaa.blend_shader_version);
|
||||
}
|
||||
|
||||
void SMAA::allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers) {
|
||||
Size2i full_size = p_render_buffers->get_internal_size();
|
||||
|
||||
// As we're not clearing these, and render buffers will return the cached texture if it already exists,
|
||||
// we don't first check has_texture here.
|
||||
|
||||
p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_EDGES, RD::DATA_FORMAT_R8G8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
|
||||
p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_BLEND, RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
|
||||
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) {
|
||||
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(&smaa.edge_push_constant, 0, sizeof(SMAAEdgePushConstant));
|
||||
memset(&smaa.weight_push_constant, 0, sizeof(SMAAWeightPushConstant));
|
||||
memset(&smaa.blend_push_constant, 0, sizeof(SMAABlendPushConstant));
|
||||
|
||||
Size2i size = p_render_buffers->get_internal_size();
|
||||
Size2 inv_size = Size2(1.0f / (float)size.x, 1.0f / (float)size.y);
|
||||
|
||||
smaa.edge_push_constant.inv_size[0] = inv_size.x;
|
||||
smaa.edge_push_constant.inv_size[1] = inv_size.y;
|
||||
smaa.edge_push_constant.threshold = edge_detection_threshold;
|
||||
|
||||
smaa.weight_push_constant.inv_size[0] = inv_size.x;
|
||||
smaa.weight_push_constant.inv_size[1] = inv_size.y;
|
||||
smaa.weight_push_constant.size[0] = size.x;
|
||||
smaa.weight_push_constant.size[1] = size.y;
|
||||
|
||||
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);
|
||||
|
||||
allocate_render_targets(p_render_buffers);
|
||||
RID edges_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_EDGES);
|
||||
RID blend_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_BLEND);
|
||||
RID stencil_buffer = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_STENCIL);
|
||||
|
||||
RID edges_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(edges_tex, stencil_buffer);
|
||||
RID blend_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(blend_tex, stencil_buffer);
|
||||
|
||||
RD::Uniform u_source_color;
|
||||
u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
|
||||
u_source_color.binding = 0;
|
||||
u_source_color.append_id(linear_sampler);
|
||||
u_source_color.append_id(p_source_color);
|
||||
|
||||
RD::Uniform u_edges_texture;
|
||||
u_edges_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
|
||||
u_edges_texture.binding = 0;
|
||||
u_edges_texture.append_id(linear_sampler);
|
||||
u_edges_texture.append_id(edges_tex);
|
||||
|
||||
RD::Uniform u_area_texture;
|
||||
u_area_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
|
||||
u_area_texture.binding = 0;
|
||||
u_area_texture.append_id(linear_sampler);
|
||||
u_area_texture.append_id(smaa.area_tex);
|
||||
|
||||
RD::Uniform u_search_texture;
|
||||
u_search_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
|
||||
u_search_texture.binding = 1;
|
||||
u_search_texture.append_id(linear_sampler);
|
||||
u_search_texture.append_id(smaa.search_tex);
|
||||
|
||||
RD::Uniform u_blend_texture;
|
||||
u_blend_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
|
||||
u_blend_texture.binding = 0;
|
||||
u_blend_texture.append_id(linear_sampler);
|
||||
u_blend_texture.append_id(blend_tex);
|
||||
|
||||
{
|
||||
int mode = SMAA_EDGE_DETECTION_COLOR;
|
||||
RID shader = smaa.edge_shader.version_get_shader(smaa.edge_shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(edges_framebuffer, RD::DRAW_CLEAR_COLOR_0 | RD::DRAW_CLEAR_STENCIL, Vector<Color>({ Color(0, 0, 0, 0) }), 1.0f, 0);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(edges_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
|
||||
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_set_push_constant(draw_list, &smaa.edge_push_constant, sizeof(SMAAEdgePushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
{
|
||||
int mode = SMAA_WEIGHT_FULL;
|
||||
RID shader = smaa.weight_shader.version_get_shader(smaa.weight_shader_version, mode - SMAA_WEIGHT_FULL);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(blend_framebuffer, RD::DRAW_CLEAR_COLOR_0, Vector<Color>({ Color(0, 0, 0, 0) }));
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(blend_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_edges_texture), 0);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_area_texture, u_search_texture), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.weight_push_constant, sizeof(SMAAWeightPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
{
|
||||
int mode = SMAA_BLENDING;
|
||||
RID shader = smaa.blend_shader.version_get_shader(smaa.blend_shader_version, mode - SMAA_BLENDING);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::DRAW_IGNORE_COLOR_0);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.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()));
|
||||
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_blend_texture), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.blend_push_constant, sizeof(SMAABlendPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
}
|
121
servers/rendering/renderer_rd/effects/smaa.h
Normal file
121
servers/rendering/renderer_rd/effects/smaa.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/**************************************************************************/
|
||||
/* smaa.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/smaa_blending.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/smaa_edge_detection.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/smaa_weight_calculation.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
#define RB_SCOPE_SMAA SNAME("rb_smaa")
|
||||
|
||||
#define RB_EDGES SNAME("edges")
|
||||
#define RB_BLEND SNAME("blend")
|
||||
#define RB_STENCIL SNAME("stencil")
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class SMAA {
|
||||
private:
|
||||
enum SMAAMode {
|
||||
SMAA_EDGE_DETECTION_COLOR,
|
||||
SMAA_WEIGHT_FULL,
|
||||
SMAA_BLENDING,
|
||||
SMAA_MAX,
|
||||
};
|
||||
|
||||
struct SMAAEdgePushConstant {
|
||||
float inv_size[2];
|
||||
float threshold;
|
||||
float pad;
|
||||
};
|
||||
|
||||
struct SMAAWeightPushConstant {
|
||||
float inv_size[2];
|
||||
uint32_t size[2];
|
||||
|
||||
float subsample_indices[4];
|
||||
};
|
||||
|
||||
struct SMAABlendPushConstant {
|
||||
float inv_size[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 {
|
||||
SMAAEdgePushConstant edge_push_constant;
|
||||
SmaaEdgeDetectionShaderRD edge_shader;
|
||||
RID edge_shader_version;
|
||||
|
||||
SMAAWeightPushConstant weight_push_constant;
|
||||
SmaaWeightCalculationShaderRD weight_shader;
|
||||
RID weight_shader_version;
|
||||
|
||||
SMAABlendPushConstant blend_push_constant;
|
||||
SmaaBlendingShaderRD blend_shader;
|
||||
RID blend_shader_version;
|
||||
|
||||
RID search_tex;
|
||||
RID area_tex;
|
||||
|
||||
RD::DataFormat stencil_format;
|
||||
|
||||
PipelineCacheRD pipelines[SMAA_MAX];
|
||||
} smaa;
|
||||
|
||||
float edge_detection_threshold;
|
||||
|
||||
public:
|
||||
SMAA();
|
||||
~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;
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
122
servers/rendering/renderer_rd/effects/sort_effects.cpp
Normal file
122
servers/rendering/renderer_rd/effects/sort_effects.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/**************************************************************************/
|
||||
/* sort_effects.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "sort_effects.h"
|
||||
// #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
SortEffects::SortEffects() {
|
||||
Vector<String> sort_modes;
|
||||
sort_modes.push_back("\n#define MODE_SORT_BLOCK\n");
|
||||
sort_modes.push_back("\n#define MODE_SORT_STEP\n");
|
||||
sort_modes.push_back("\n#define MODE_SORT_INNER\n");
|
||||
|
||||
shader.initialize(sort_modes);
|
||||
|
||||
shader_version = shader.version_create();
|
||||
|
||||
for (int i = 0; i < SORT_MODE_MAX; i++) {
|
||||
pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i));
|
||||
}
|
||||
}
|
||||
|
||||
SortEffects::~SortEffects() {
|
||||
shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void SortEffects::sort_buffer(RID p_uniform_set, int p_size) {
|
||||
PushConstant push_constant;
|
||||
push_constant.total_elements = p_size;
|
||||
|
||||
bool done = true;
|
||||
|
||||
int numThreadGroups = ((p_size - 1) >> 9) + 1;
|
||||
|
||||
if (numThreadGroups > 1) {
|
||||
done = false;
|
||||
}
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_BLOCK]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_uniform_set, 1);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
|
||||
|
||||
int presorted = 512;
|
||||
|
||||
while (!done) {
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
done = true;
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_STEP]);
|
||||
|
||||
numThreadGroups = 0;
|
||||
|
||||
if (p_size > presorted) {
|
||||
if (p_size > presorted * 2) {
|
||||
done = false;
|
||||
}
|
||||
|
||||
int pow2 = presorted;
|
||||
while (pow2 < p_size) {
|
||||
pow2 *= 2;
|
||||
}
|
||||
numThreadGroups = pow2 >> 9;
|
||||
}
|
||||
|
||||
unsigned int nMergeSize = presorted * 2;
|
||||
|
||||
for (unsigned int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1) {
|
||||
push_constant.job_params[0] = nMergeSubSize;
|
||||
if (nMergeSubSize == nMergeSize >> 1) {
|
||||
push_constant.job_params[1] = (2 * nMergeSubSize - 1);
|
||||
push_constant.job_params[2] = -1;
|
||||
} else {
|
||||
push_constant.job_params[1] = nMergeSubSize;
|
||||
push_constant.job_params[2] = 1;
|
||||
}
|
||||
push_constant.job_params[3] = 0;
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_INNER]);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
|
||||
|
||||
presorted *= 2;
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
65
servers/rendering/renderer_rd/effects/sort_effects.h
Normal file
65
servers/rendering/renderer_rd/effects/sort_effects.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/**************************************************************************/
|
||||
/* sort_effects.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shader_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/sort.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class SortEffects {
|
||||
private:
|
||||
enum SortMode {
|
||||
SORT_MODE_BLOCK,
|
||||
SORT_MODE_STEP,
|
||||
SORT_MODE_INNER,
|
||||
SORT_MODE_MAX
|
||||
};
|
||||
|
||||
struct PushConstant {
|
||||
uint32_t total_elements;
|
||||
uint32_t pad[3];
|
||||
int32_t job_params[4];
|
||||
};
|
||||
|
||||
SortShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[SORT_MODE_MAX];
|
||||
|
||||
protected:
|
||||
public:
|
||||
SortEffects();
|
||||
~SortEffects();
|
||||
|
||||
void sort_buffer(RID p_uniform_set, int p_size);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
45
servers/rendering/renderer_rd/effects/spatial_upscaler.h
Normal file
45
servers/rendering/renderer_rd/effects/spatial_upscaler.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/**************************************************************************/
|
||||
/* spatial_upscaler.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class RenderSceneBuffersRD;
|
||||
|
||||
class SpatialUpscaler {
|
||||
public:
|
||||
virtual const Span<char> get_label() const = 0;
|
||||
virtual void ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
|
||||
virtual void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) = 0;
|
||||
|
||||
SpatialUpscaler() = default;
|
||||
virtual ~SpatialUpscaler() = default;
|
||||
};
|
1692
servers/rendering/renderer_rd/effects/ss_effects.cpp
Normal file
1692
servers/rendering/renderer_rd/effects/ss_effects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
528
servers/rendering/renderer_rd/effects/ss_effects.h
Normal file
528
servers/rendering/renderer_rd/effects/ss_effects.h
Normal file
@@ -0,0 +1,528 @@
|
||||
/**************************************************************************/
|
||||
/* ss_effects.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssao.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssil.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl.gen.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
#define RB_SCOPE_SSDS SNAME("rb_ssds")
|
||||
#define RB_SCOPE_SSIL SNAME("rb_ssil")
|
||||
#define RB_SCOPE_SSAO SNAME("rb_ssao")
|
||||
#define RB_SCOPE_SSR SNAME("rb_ssr")
|
||||
|
||||
#define RB_LINEAR_DEPTH SNAME("linear_depth")
|
||||
#define RB_FINAL SNAME("final")
|
||||
#define RB_LAST_FRAME SNAME("last_frame")
|
||||
#define RB_DEINTERLEAVED SNAME("deinterleaved")
|
||||
#define RB_DEINTERLEAVED_PONG SNAME("deinterleaved_pong")
|
||||
#define RB_EDGES SNAME("edges")
|
||||
#define RB_IMPORTANCE_MAP SNAME("importance_map")
|
||||
#define RB_IMPORTANCE_PONG SNAME("importance_pong")
|
||||
|
||||
#define RB_DEPTH_SCALED SNAME("depth_scaled")
|
||||
#define RB_NORMAL_SCALED SNAME("normal_scaled")
|
||||
#define RB_BLUR_RADIUS SNAME("blur_radius")
|
||||
#define RB_INTERMEDIATE SNAME("intermediate")
|
||||
#define RB_OUTPUT SNAME("output")
|
||||
|
||||
class RenderSceneBuffersRD;
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class SSEffects {
|
||||
private:
|
||||
static SSEffects *singleton;
|
||||
|
||||
public:
|
||||
static SSEffects *get_singleton() { return singleton; }
|
||||
|
||||
SSEffects();
|
||||
~SSEffects();
|
||||
|
||||
/* SS Downsampler */
|
||||
|
||||
void downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_view, const Projection &p_projection);
|
||||
|
||||
/* SSIL */
|
||||
void ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
|
||||
|
||||
struct SSILRenderBuffers {
|
||||
bool half_size = false;
|
||||
int buffer_width;
|
||||
int buffer_height;
|
||||
int half_buffer_width;
|
||||
int half_buffer_height;
|
||||
};
|
||||
|
||||
struct SSILSettings {
|
||||
float radius = 1.0;
|
||||
float intensity = 2.0;
|
||||
float sharpness = 0.98;
|
||||
float normal_rejection = 1.0;
|
||||
|
||||
Size2i full_screen_size;
|
||||
};
|
||||
|
||||
void ssil_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings);
|
||||
void screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const Projection &p_last_projection, const SSILSettings &p_settings);
|
||||
|
||||
/* SSAO */
|
||||
void ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
|
||||
|
||||
struct SSAORenderBuffers {
|
||||
bool half_size = false;
|
||||
int buffer_width;
|
||||
int buffer_height;
|
||||
int half_buffer_width;
|
||||
int half_buffer_height;
|
||||
};
|
||||
|
||||
struct SSAOSettings {
|
||||
float radius = 1.0;
|
||||
float intensity = 2.0;
|
||||
float power = 1.5;
|
||||
float detail = 0.5;
|
||||
float horizon = 0.06;
|
||||
float sharpness = 0.98;
|
||||
|
||||
Size2i full_screen_size;
|
||||
};
|
||||
|
||||
void ssao_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings);
|
||||
void generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const SSAOSettings &p_settings);
|
||||
|
||||
/* Screen Space Reflection */
|
||||
void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
|
||||
|
||||
struct SSRRenderBuffers {
|
||||
Size2i size;
|
||||
RenderingServer::EnvironmentSSRRoughnessQuality roughness_quality = RenderingServer::ENV_SSR_ROUGHNESS_QUALITY_DISABLED;
|
||||
};
|
||||
|
||||
void ssr_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format);
|
||||
void screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const Projection *p_projections, const Vector3 *p_eye_offsets);
|
||||
|
||||
/* subsurface scattering */
|
||||
void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality);
|
||||
RS::SubSurfaceScatteringQuality sss_get_quality() const;
|
||||
void sss_set_scale(float p_scale, float p_depth_scale);
|
||||
|
||||
void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size);
|
||||
|
||||
private:
|
||||
/* Settings */
|
||||
|
||||
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
|
||||
bool ssao_half_size = false;
|
||||
float ssao_adaptive_target = 0.5;
|
||||
int ssao_blur_passes = 2;
|
||||
float ssao_fadeout_from = 50.0;
|
||||
float ssao_fadeout_to = 300.0;
|
||||
|
||||
RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
|
||||
bool ssil_half_size = false;
|
||||
float ssil_adaptive_target = 0.5;
|
||||
int ssil_blur_passes = 4;
|
||||
float ssil_fadeout_from = 50.0;
|
||||
float ssil_fadeout_to = 300.0;
|
||||
|
||||
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
|
||||
|
||||
RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
|
||||
float sss_scale = 0.05;
|
||||
float sss_depth_scale = 0.01;
|
||||
|
||||
/* SS Downsampler */
|
||||
|
||||
struct SSEffectsDownsamplePushConstant {
|
||||
float pixel_size[2];
|
||||
float z_far;
|
||||
float z_near;
|
||||
uint32_t orthogonal;
|
||||
float radius_sq;
|
||||
uint32_t pad[2];
|
||||
};
|
||||
|
||||
enum SSEffectsMode {
|
||||
SS_EFFECTS_DOWNSAMPLE,
|
||||
SS_EFFECTS_DOWNSAMPLE_HALF_RES,
|
||||
SS_EFFECTS_DOWNSAMPLE_MIPMAP,
|
||||
SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES,
|
||||
SS_EFFECTS_DOWNSAMPLE_HALF,
|
||||
SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF,
|
||||
SS_EFFECTS_DOWNSAMPLE_FULL_MIPS,
|
||||
SS_EFFECTS_MAX
|
||||
};
|
||||
|
||||
struct SSEffectsGatherConstants {
|
||||
float rotation_matrices[80]; //5 vec4s * 4
|
||||
};
|
||||
|
||||
struct SSEffectsShader {
|
||||
SSEffectsDownsamplePushConstant downsample_push_constant;
|
||||
SsEffectsDownsampleShaderRD downsample_shader;
|
||||
RID downsample_shader_version;
|
||||
bool used_half_size_last_frame = false;
|
||||
bool used_mips_last_frame = false;
|
||||
bool used_full_mips_last_frame = false;
|
||||
|
||||
RID gather_constants_buffer;
|
||||
|
||||
RID mirror_sampler;
|
||||
|
||||
RID pipelines[SS_EFFECTS_MAX];
|
||||
} ss_effects;
|
||||
|
||||
/* SSIL */
|
||||
|
||||
enum SSILMode {
|
||||
SSIL_GATHER,
|
||||
SSIL_GATHER_BASE,
|
||||
SSIL_GATHER_ADAPTIVE,
|
||||
SSIL_GENERATE_IMPORTANCE_MAP,
|
||||
SSIL_PROCESS_IMPORTANCE_MAPA,
|
||||
SSIL_PROCESS_IMPORTANCE_MAPB,
|
||||
SSIL_BLUR_PASS,
|
||||
SSIL_BLUR_PASS_SMART,
|
||||
SSIL_BLUR_PASS_WIDE,
|
||||
SSIL_INTERLEAVE,
|
||||
SSIL_INTERLEAVE_SMART,
|
||||
SSIL_INTERLEAVE_HALF,
|
||||
SSIL_MAX
|
||||
};
|
||||
|
||||
struct SSILGatherPushConstant {
|
||||
int32_t screen_size[2];
|
||||
int pass;
|
||||
int quality;
|
||||
|
||||
float half_screen_pixel_size[2];
|
||||
float half_screen_pixel_size_x025[2];
|
||||
|
||||
float NDC_to_view_mul[2];
|
||||
float NDC_to_view_add[2];
|
||||
|
||||
float pad2[2];
|
||||
float z_near;
|
||||
float z_far;
|
||||
|
||||
float radius;
|
||||
float intensity;
|
||||
int size_multiplier;
|
||||
int pad;
|
||||
|
||||
float fade_out_mul;
|
||||
float fade_out_add;
|
||||
float normal_rejection_amount;
|
||||
float inv_radius_near_limit;
|
||||
|
||||
uint32_t is_orthogonal;
|
||||
float neg_inv_radius;
|
||||
float load_counter_avg_div;
|
||||
float adaptive_sample_limit;
|
||||
|
||||
int32_t pass_coord_offset[2];
|
||||
float pass_uv_offset[2];
|
||||
};
|
||||
|
||||
struct SSILImportanceMapPushConstant {
|
||||
float half_screen_pixel_size[2];
|
||||
float intensity;
|
||||
float pad;
|
||||
};
|
||||
|
||||
struct SSILBlurPushConstant {
|
||||
float edge_sharpness;
|
||||
float pad;
|
||||
float half_screen_pixel_size[2];
|
||||
};
|
||||
|
||||
struct SSILInterleavePushConstant {
|
||||
float inv_sharpness;
|
||||
uint32_t size_modifier;
|
||||
float pixel_size[2];
|
||||
};
|
||||
|
||||
struct SSILProjectionUniforms {
|
||||
float inv_last_frame_projection_matrix[16];
|
||||
};
|
||||
|
||||
struct SSIL {
|
||||
SSILGatherPushConstant gather_push_constant;
|
||||
SsilShaderRD gather_shader;
|
||||
RID gather_shader_version;
|
||||
RID projection_uniform_buffer;
|
||||
|
||||
SSILImportanceMapPushConstant importance_map_push_constant;
|
||||
SsilImportanceMapShaderRD importance_map_shader;
|
||||
RID importance_map_shader_version;
|
||||
RID importance_map_load_counter;
|
||||
RID counter_uniform_set;
|
||||
|
||||
SSILBlurPushConstant blur_push_constant;
|
||||
SsilBlurShaderRD blur_shader;
|
||||
RID blur_shader_version;
|
||||
|
||||
SSILInterleavePushConstant interleave_push_constant;
|
||||
SsilInterleaveShaderRD interleave_shader;
|
||||
RID interleave_shader_version;
|
||||
|
||||
RID pipelines[SSIL_MAX];
|
||||
} ssil;
|
||||
|
||||
void gather_ssil(RD::ComputeListID p_compute_list, const RID *p_ssil_slices, const RID *p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set);
|
||||
|
||||
/* SSAO */
|
||||
|
||||
enum SSAOMode {
|
||||
SSAO_GATHER,
|
||||
SSAO_GATHER_BASE,
|
||||
SSAO_GATHER_ADAPTIVE,
|
||||
SSAO_GENERATE_IMPORTANCE_MAP,
|
||||
SSAO_PROCESS_IMPORTANCE_MAPA,
|
||||
SSAO_PROCESS_IMPORTANCE_MAPB,
|
||||
SSAO_BLUR_PASS,
|
||||
SSAO_BLUR_PASS_SMART,
|
||||
SSAO_BLUR_PASS_WIDE,
|
||||
SSAO_INTERLEAVE,
|
||||
SSAO_INTERLEAVE_SMART,
|
||||
SSAO_INTERLEAVE_HALF,
|
||||
SSAO_MAX
|
||||
};
|
||||
|
||||
struct SSAOGatherPushConstant {
|
||||
int32_t screen_size[2];
|
||||
int pass;
|
||||
int quality;
|
||||
|
||||
float half_screen_pixel_size[2];
|
||||
int size_multiplier;
|
||||
float detail_intensity;
|
||||
|
||||
float NDC_to_view_mul[2];
|
||||
float NDC_to_view_add[2];
|
||||
|
||||
float pad[2];
|
||||
float half_screen_pixel_size_x025[2];
|
||||
|
||||
float radius;
|
||||
float intensity;
|
||||
float shadow_power;
|
||||
float shadow_clamp;
|
||||
|
||||
float fade_out_mul;
|
||||
float fade_out_add;
|
||||
float horizon_angle_threshold;
|
||||
float inv_radius_near_limit;
|
||||
|
||||
uint32_t is_orthogonal;
|
||||
float neg_inv_radius;
|
||||
float load_counter_avg_div;
|
||||
float adaptive_sample_limit;
|
||||
|
||||
int32_t pass_coord_offset[2];
|
||||
float pass_uv_offset[2];
|
||||
};
|
||||
|
||||
struct SSAOImportanceMapPushConstant {
|
||||
float half_screen_pixel_size[2];
|
||||
float intensity;
|
||||
float power;
|
||||
};
|
||||
|
||||
struct SSAOBlurPushConstant {
|
||||
float edge_sharpness;
|
||||
float pad;
|
||||
float half_screen_pixel_size[2];
|
||||
};
|
||||
|
||||
struct SSAOInterleavePushConstant {
|
||||
float inv_sharpness;
|
||||
uint32_t size_modifier;
|
||||
float pixel_size[2];
|
||||
};
|
||||
|
||||
struct SSAO {
|
||||
SSAOGatherPushConstant gather_push_constant;
|
||||
SsaoShaderRD gather_shader;
|
||||
RID gather_shader_version;
|
||||
|
||||
SSAOImportanceMapPushConstant importance_map_push_constant;
|
||||
SsaoImportanceMapShaderRD importance_map_shader;
|
||||
RID importance_map_shader_version;
|
||||
RID importance_map_load_counter;
|
||||
RID counter_uniform_set;
|
||||
|
||||
SSAOBlurPushConstant blur_push_constant;
|
||||
SsaoBlurShaderRD blur_shader;
|
||||
RID blur_shader_version;
|
||||
|
||||
SSAOInterleavePushConstant interleave_push_constant;
|
||||
SsaoInterleaveShaderRD interleave_shader;
|
||||
RID interleave_shader_version;
|
||||
|
||||
RID pipelines[SSAO_MAX];
|
||||
} ssao;
|
||||
|
||||
void gather_ssao(RD::ComputeListID p_compute_list, const RID *p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
|
||||
|
||||
/* Screen Space Reflection */
|
||||
|
||||
enum SSRShaderSpecializations {
|
||||
SSR_MULTIVIEW = 1 << 0,
|
||||
SSR_VARIATIONS = 2,
|
||||
};
|
||||
|
||||
struct ScreenSpaceReflectionSceneData {
|
||||
float projection[2][16];
|
||||
float inv_projection[2][16];
|
||||
float eye_offset[2][4];
|
||||
};
|
||||
|
||||
// SSR Scale
|
||||
|
||||
struct ScreenSpaceReflectionScalePushConstant {
|
||||
int32_t screen_size[2];
|
||||
float camera_z_near;
|
||||
float camera_z_far;
|
||||
|
||||
uint32_t orthogonal;
|
||||
uint32_t filter;
|
||||
uint32_t view_index;
|
||||
uint32_t pad1;
|
||||
};
|
||||
|
||||
struct ScreenSpaceReflectionScale {
|
||||
ScreenSpaceReflectionScaleShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[SSR_VARIATIONS];
|
||||
} ssr_scale;
|
||||
|
||||
// SSR main
|
||||
|
||||
enum ScreenSpaceReflectionMode {
|
||||
SCREEN_SPACE_REFLECTION_NORMAL,
|
||||
SCREEN_SPACE_REFLECTION_ROUGH,
|
||||
SCREEN_SPACE_REFLECTION_MAX,
|
||||
};
|
||||
|
||||
struct ScreenSpaceReflectionPushConstant {
|
||||
float proj_info[4]; // 16 - 16
|
||||
|
||||
int32_t screen_size[2]; // 8 - 24
|
||||
float camera_z_near; // 4 - 28
|
||||
float camera_z_far; // 4 - 32
|
||||
|
||||
int32_t num_steps; // 4 - 36
|
||||
float depth_tolerance; // 4 - 40
|
||||
float distance_fade; // 4 - 44
|
||||
float curve_fade_in; // 4 - 48
|
||||
|
||||
uint32_t orthogonal; // 4 - 52
|
||||
float filter_mipmap_levels; // 4 - 56
|
||||
uint32_t use_half_res; // 4 - 60
|
||||
uint32_t view_index; // 4 - 64
|
||||
|
||||
// float projection[16]; // this is in our ScreenSpaceReflectionSceneData now
|
||||
};
|
||||
|
||||
struct ScreenSpaceReflection {
|
||||
ScreenSpaceReflectionShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
|
||||
|
||||
RID ubo;
|
||||
} ssr;
|
||||
|
||||
// SSR Filter
|
||||
|
||||
struct ScreenSpaceReflectionFilterPushConstant {
|
||||
float proj_info[4]; // 16 - 16
|
||||
|
||||
uint32_t orthogonal; // 4 - 20
|
||||
float edge_tolerance; // 4 - 24
|
||||
int32_t increment; // 4 - 28
|
||||
uint32_t view_index; // 4 - 32
|
||||
|
||||
int32_t screen_size[2]; // 8 - 40
|
||||
uint32_t vertical; // 4 - 44
|
||||
uint32_t steps; // 4 - 48
|
||||
};
|
||||
|
||||
enum SSRReflectionMode {
|
||||
SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
|
||||
SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
|
||||
SCREEN_SPACE_REFLECTION_FILTER_MAX,
|
||||
};
|
||||
|
||||
struct ScreenSpaceReflectionFilter {
|
||||
ScreenSpaceReflectionFilterShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
|
||||
} ssr_filter;
|
||||
|
||||
/* Subsurface scattering */
|
||||
|
||||
struct SubSurfaceScatteringPushConstant {
|
||||
int32_t screen_size[2];
|
||||
float camera_z_far;
|
||||
float camera_z_near;
|
||||
|
||||
uint32_t vertical;
|
||||
uint32_t orthogonal;
|
||||
float unit_size;
|
||||
float scale;
|
||||
|
||||
float depth_scale;
|
||||
uint32_t pad[3];
|
||||
};
|
||||
|
||||
struct SubSurfaceScattering {
|
||||
SubSurfaceScatteringPushConstant push_constant;
|
||||
SubsurfaceScatteringShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[3]; //3 quality levels
|
||||
} sss;
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
124
servers/rendering/renderer_rd/effects/taa.cpp
Normal file
124
servers/rendering/renderer_rd/effects/taa.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/**************************************************************************/
|
||||
/* taa.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "taa.h"
|
||||
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
TAA::TAA() {
|
||||
Vector<String> taa_modes;
|
||||
taa_modes.push_back("\n#define MODE_TAA_RESOLVE");
|
||||
taa_shader.initialize(taa_modes);
|
||||
shader_version = taa_shader.version_create();
|
||||
pipeline = RD::get_singleton()->compute_pipeline_create(taa_shader.version_get_shader(shader_version, 0));
|
||||
}
|
||||
|
||||
TAA::~TAA() {
|
||||
taa_shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void TAA::resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far) {
|
||||
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 shader = taa_shader.version_get_shader(shader_version, 0);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
TAAResolvePushConstant push_constant;
|
||||
memset(&push_constant, 0, sizeof(TAAResolvePushConstant));
|
||||
push_constant.resolution_width = p_resolution.width;
|
||||
push_constant.resolution_height = p_resolution.height;
|
||||
push_constant.disocclusion_threshold = 2.5f; // If velocity changes by less than this amount of texels we can retain the accumulation buffer.
|
||||
push_constant.disocclusion_scale = 0.01f; // Scale the weight of this pixel calculated as (change in velocity - threshold) * scale.
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
|
||||
|
||||
RD::Uniform u_frame_source(RD::UNIFORM_TYPE_IMAGE, 0, { p_frame });
|
||||
RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, { default_sampler, p_depth });
|
||||
RD::Uniform u_velocity(RD::UNIFORM_TYPE_IMAGE, 2, { p_velocity });
|
||||
RD::Uniform u_prev_velocity(RD::UNIFORM_TYPE_IMAGE, 3, { p_prev_velocity });
|
||||
RD::Uniform u_history(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 4, { default_sampler, p_history });
|
||||
RD::Uniform u_frame_dest(RD::UNIFORM_TYPE_IMAGE, 5, { p_temp });
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_frame_source, u_depth, u_velocity, u_prev_velocity, u_history, u_frame_dest), 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(TAAResolvePushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_resolution.width, p_resolution.height, 1);
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void TAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far) {
|
||||
CopyEffects *copy_effects = CopyEffects::get_singleton();
|
||||
|
||||
uint32_t view_count = p_render_buffers->get_view_count();
|
||||
Size2i internal_size = p_render_buffers->get_internal_size();
|
||||
Size2i target_size = p_render_buffers->get_target_size();
|
||||
|
||||
bool just_allocated = false;
|
||||
if (!p_render_buffers->has_texture(SNAME("taa"), SNAME("history"))) {
|
||||
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
p_render_buffers->create_texture(SNAME("taa"), SNAME("history"), p_format, usage_bits);
|
||||
p_render_buffers->create_texture(SNAME("taa"), SNAME("temp"), p_format, usage_bits);
|
||||
|
||||
p_render_buffers->create_texture(SNAME("taa"), SNAME("prev_velocity"), RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
|
||||
|
||||
just_allocated = true;
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_command_begin_label("TAA");
|
||||
|
||||
for (uint32_t v = 0; v < view_count; v++) {
|
||||
// Get our (cached) slices
|
||||
RID internal_texture = p_render_buffers->get_internal_texture(v);
|
||||
RID velocity_buffer = p_render_buffers->get_velocity_buffer(false, v);
|
||||
RID taa_history = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("history"), v, 0);
|
||||
RID taa_prev_velocity = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("prev_velocity"), v, 0);
|
||||
|
||||
if (!just_allocated) {
|
||||
RID depth_texture = p_render_buffers->get_depth_texture(v);
|
||||
RID taa_temp = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("temp"), v, 0);
|
||||
resolve(internal_texture, taa_temp, depth_texture, velocity_buffer, taa_prev_velocity, taa_history, Size2(internal_size.x, internal_size.y), p_z_near, p_z_far);
|
||||
copy_effects->copy_to_rect(taa_temp, internal_texture, Rect2(0, 0, internal_size.x, internal_size.y));
|
||||
}
|
||||
|
||||
copy_effects->copy_to_rect(internal_texture, taa_history, Rect2(0, 0, internal_size.x, internal_size.y));
|
||||
copy_effects->copy_to_rect(velocity_buffer, taa_prev_velocity, Rect2(0, 0, target_size.x, target_size.y));
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_command_end_label();
|
||||
}
|
60
servers/rendering/renderer_rd/effects/taa.h
Normal file
60
servers/rendering/renderer_rd/effects/taa.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/**************************************************************************/
|
||||
/* taa.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class TAA {
|
||||
public:
|
||||
TAA();
|
||||
~TAA();
|
||||
|
||||
void process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far);
|
||||
|
||||
private:
|
||||
struct TAAResolvePushConstant {
|
||||
float resolution_width;
|
||||
float resolution_height;
|
||||
float disocclusion_threshold;
|
||||
float disocclusion_scale;
|
||||
};
|
||||
|
||||
TaaResolveShaderRD taa_shader;
|
||||
RID shader_version;
|
||||
RID pipeline;
|
||||
|
||||
void resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
266
servers/rendering/renderer_rd/effects/tone_mapper.cpp
Normal file
266
servers/rendering/renderer_rd/effects/tone_mapper.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/**************************************************************************/
|
||||
/* tone_mapper.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tone_mapper.h"
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
ToneMapper::ToneMapper() {
|
||||
{
|
||||
// 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);
|
||||
|
||||
if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
|
||||
tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false);
|
||||
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();
|
||||
|
||||
for (int i = 0; i < TONEMAP_MODE_MAX; i++) {
|
||||
if (tonemap.shader.is_variant_enabled(i)) {
|
||||
tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
} else {
|
||||
tonemap.pipelines[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToneMapper::~ToneMapper() {
|
||||
tonemap.shader.version_free(tonemap.shader_version);
|
||||
}
|
||||
|
||||
void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, 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);
|
||||
|
||||
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
|
||||
|
||||
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.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
|
||||
tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1];
|
||||
tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2];
|
||||
tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3];
|
||||
tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4];
|
||||
tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5];
|
||||
tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6];
|
||||
tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x;
|
||||
tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;
|
||||
tonemap.push_constant.glow_mode = p_settings.glow_mode;
|
||||
|
||||
int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
|
||||
if (p_settings.use_1d_color_correction) {
|
||||
mode += 2;
|
||||
}
|
||||
|
||||
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.luminance_multiplier = p_settings.luminance_multiplier;
|
||||
|
||||
tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
|
||||
|
||||
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;
|
||||
|
||||
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
|
||||
|
||||
if (p_settings.view_count > 1) {
|
||||
// Use USE_MULTIVIEW versions
|
||||
mode += 6;
|
||||
}
|
||||
|
||||
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(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, 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_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.shader.version_get_shader(tonemap.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.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()));
|
||||
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_exposure_texture), 1);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
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) {
|
||||
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));
|
||||
|
||||
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.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) {
|
||||
// Use USE_MULTIVIEW versions
|
||||
mode += 6;
|
||||
}
|
||||
|
||||
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_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.shader.version_get_shader(tonemap.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::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(p_subpass_draw_list, false, 1u, 3u);
|
||||
}
|
161
servers/rendering/renderer_rd/effects/tone_mapper.h
Normal file
161
servers/rendering/renderer_rd/effects/tone_mapper.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/**************************************************************************/
|
||||
/* tone_mapper.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/tonemap.glsl.gen.h"
|
||||
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class ToneMapper {
|
||||
private:
|
||||
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 {
|
||||
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),
|
||||
};
|
||||
|
||||
struct TonemapPushConstant {
|
||||
float bcs[3]; // 12 - 12
|
||||
uint32_t flags; // 4 - 16
|
||||
|
||||
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
|
||||
float glow_map_strength; // 4 - 48
|
||||
|
||||
uint32_t glow_mode; // 4 - 52
|
||||
float glow_levels[7]; // 28 - 80
|
||||
|
||||
float exposure; // 4 - 84
|
||||
float white; // 4 - 88
|
||||
float auto_exposure_scale; // 4 - 92
|
||||
float luminance_multiplier; // 4 - 96
|
||||
};
|
||||
|
||||
/* 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
|
||||
*/
|
||||
struct Tonemap {
|
||||
TonemapPushConstant push_constant;
|
||||
TonemapShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[TONEMAP_MODE_MAX];
|
||||
} tonemap;
|
||||
|
||||
public:
|
||||
ToneMapper();
|
||||
~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_ADD;
|
||||
float glow_intensity = 1.0;
|
||||
float glow_map_strength = 0.0f;
|
||||
float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 };
|
||||
Vector2i glow_texture_size;
|
||||
bool glow_use_bicubic_upscale = false;
|
||||
RID glow_texture;
|
||||
RID glow_map;
|
||||
|
||||
RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR;
|
||||
float exposure = 1.0;
|
||||
float white = 1.0;
|
||||
|
||||
bool use_auto_exposure = false;
|
||||
float auto_exposure_scale = 0.5;
|
||||
RID exposure_texture;
|
||||
float luminance_multiplier = 1.0;
|
||||
|
||||
bool use_bcs = false;
|
||||
float brightness = 1.0;
|
||||
float contrast = 1.0;
|
||||
float saturation = 1.0;
|
||||
|
||||
bool use_color_correction = false;
|
||||
bool use_1d_color_correction = false;
|
||||
RID color_correction_texture;
|
||||
|
||||
bool use_fxaa = false;
|
||||
enum DebandingMode {
|
||||
DEBANDING_MODE_DISABLED,
|
||||
DEBANDING_MODE_8_BIT,
|
||||
DEBANDING_MODE_10_BIT,
|
||||
};
|
||||
DebandingMode debanding_mode = DEBANDING_MODE_DISABLED;
|
||||
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);
|
||||
void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
156
servers/rendering/renderer_rd/effects/vrs.cpp
Normal file
156
servers/rendering/renderer_rd/effects/vrs.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/**************************************************************************/
|
||||
/* vrs.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "vrs.h"
|
||||
#include "../renderer_compositor_rd.h"
|
||||
#include "../storage_rd/texture_storage.h"
|
||||
#include "../uniform_set_cache_rd.h"
|
||||
|
||||
#ifndef XR_DISABLED
|
||||
#include "servers/xr_server.h"
|
||||
#endif // XR_DISABLED
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
VRS::VRS() {
|
||||
{
|
||||
Vector<String> vrs_modes;
|
||||
vrs_modes.push_back("\n"); // VRS_DEFAULT
|
||||
vrs_modes.push_back("\n#define USE_MULTIVIEW\n"); // VRS_MULTIVIEW
|
||||
vrs_modes.push_back("\n#define SPLIT_RG\n"); // VRS_RG
|
||||
vrs_modes.push_back("\n#define SPLIT_RG\n#define USE_MULTIVIEW\n"); // VRS_RG_MULTIVIEW
|
||||
|
||||
vrs_shader.shader.initialize(vrs_modes);
|
||||
|
||||
if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
|
||||
vrs_shader.shader.set_variant_enabled(VRS_MULTIVIEW, false);
|
||||
}
|
||||
|
||||
vrs_shader.shader_version = vrs_shader.shader.version_create();
|
||||
|
||||
//use additive
|
||||
|
||||
for (int i = 0; i < VRS_MAX; i++) {
|
||||
if (vrs_shader.shader.is_variant_enabled(i)) {
|
||||
vrs_shader.pipelines[i].setup(vrs_shader.shader.version_get_shader(vrs_shader.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
} else {
|
||||
vrs_shader.pipelines[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VRS::~VRS() {
|
||||
vrs_shader.shader.version_free(vrs_shader.shader_version);
|
||||
}
|
||||
|
||||
void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview) {
|
||||
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
|
||||
ERR_FAIL_NULL(uniform_set_cache);
|
||||
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||
ERR_FAIL_NULL(material_storage);
|
||||
|
||||
// setup our uniforms
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, 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 }));
|
||||
|
||||
int mode = 0;
|
||||
VRSPushConstant push_constant = {};
|
||||
bool uses_rg_format = RD::get_singleton()->vrs_get_format() == RD::DATA_FORMAT_R8G8_UNORM;
|
||||
if (uses_rg_format) {
|
||||
mode = p_multiview ? VRS_RG_MULTIVIEW : VRS_RG;
|
||||
} else {
|
||||
mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT;
|
||||
|
||||
// Default to 4x4 as it's not possible to query the max fragment size from RenderingDevice. This can be improved to use the largest size
|
||||
// available if this code is moved over to RenderingDevice at some point.
|
||||
push_constant.max_texel_factor = 2.0;
|
||||
}
|
||||
|
||||
RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode);
|
||||
ERR_FAIL_COND(shader.is_null());
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(VRSPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
|
||||
Size2i vrs_texel_size = RD::get_singleton()->vrs_get_texel_size();
|
||||
return Size2i((p_base_size.x + vrs_texel_size.x - 1) / vrs_texel_size.x, (p_base_size.y + vrs_texel_size.y - 1) / vrs_texel_size.y);
|
||||
}
|
||||
|
||||
void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
|
||||
TextureStorage *texture_storage = TextureStorage::get_singleton();
|
||||
RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target);
|
||||
RS::ViewportVRSUpdateMode vrs_update_mode = texture_storage->render_target_get_vrs_update_mode(p_render_target);
|
||||
|
||||
if (vrs_mode != RS::VIEWPORT_VRS_DISABLED && vrs_update_mode != RS::VIEWPORT_VRS_UPDATE_DISABLED) {
|
||||
RD::get_singleton()->draw_command_begin_label("VRS Setup");
|
||||
|
||||
if (vrs_mode == RS::VIEWPORT_VRS_TEXTURE) {
|
||||
RID vrs_texture = texture_storage->render_target_get_vrs_texture(p_render_target);
|
||||
if (vrs_texture.is_valid()) {
|
||||
RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
|
||||
int layers = texture_storage->texture_get_layers(vrs_texture);
|
||||
if (rd_texture.is_valid()) {
|
||||
// Copy into our density buffer
|
||||
copy_vrs(rd_texture, p_vrs_fb, layers > 1);
|
||||
}
|
||||
}
|
||||
#ifndef XR_DISABLED
|
||||
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
|
||||
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
|
||||
if (interface.is_valid() && interface->get_vrs_texture_format() == XRInterface::XR_VRS_TEXTURE_FORMAT_UNIFIED) {
|
||||
RID vrs_texture = interface->get_vrs_texture();
|
||||
if (vrs_texture.is_valid()) {
|
||||
RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
|
||||
int layers = texture_storage->texture_get_layers(vrs_texture);
|
||||
|
||||
if (rd_texture.is_valid()) {
|
||||
// Copy into our density buffer
|
||||
copy_vrs(rd_texture, p_vrs_fb, layers > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // XR_DISABLED
|
||||
}
|
||||
|
||||
if (vrs_update_mode == RS::VIEWPORT_VRS_UPDATE_ONCE) {
|
||||
texture_storage->render_target_set_vrs_update_mode(p_render_target, RS::VIEWPORT_VRS_UPDATE_DISABLED);
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_command_end_label();
|
||||
}
|
||||
}
|
72
servers/rendering/renderer_rd/effects/vrs.h
Normal file
72
servers/rendering/renderer_rd/effects/vrs.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************/
|
||||
/* vrs.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/vrs.glsl.gen.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class VRS {
|
||||
private:
|
||||
enum VRSMode {
|
||||
VRS_DEFAULT,
|
||||
VRS_MULTIVIEW,
|
||||
VRS_RG,
|
||||
VRS_RG_MULTIVIEW,
|
||||
VRS_MAX,
|
||||
};
|
||||
|
||||
struct VRSPushConstant {
|
||||
float max_texel_factor; // 4x8, 8x4 and 8x8 are only available on some GPUs.
|
||||
float res1;
|
||||
float res2;
|
||||
float res3;
|
||||
};
|
||||
|
||||
struct VRSShader {
|
||||
// VRSPushConstant push_constant;
|
||||
VrsShaderRD shader;
|
||||
RID shader_version;
|
||||
PipelineCacheRD pipelines[VRS_MAX];
|
||||
} vrs_shader;
|
||||
|
||||
public:
|
||||
VRS();
|
||||
~VRS();
|
||||
|
||||
void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false);
|
||||
|
||||
Size2i get_vrs_texture_size(const Size2i p_base_size) const;
|
||||
void update_vrs_texture(RID p_vrs_fb, RID p_render_target);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
Reference in New Issue
Block a user