feat: godot-engine-source-4.3-stable
This commit is contained in:
parent
c59a7dcade
commit
7125d019b5
11149 changed files with 5070401 additions and 0 deletions
34
engine/servers/rendering/renderer_rd/effects/SCsub
Normal file
34
engine/servers/rendering/renderer_rd/effects/SCsub
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
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(CPPPATH=[thirdparty_dir])
|
||||
|
||||
# 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")
|
||||
env.servers_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
||||
499
engine/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
Normal file
499
engine/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
/**************************************************************************/
|
||||
/* 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/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
|
||||
#include "servers/rendering/rendering_server_default.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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
engine/servers/rendering/renderer_rd/effects/bokeh_dof.h
Normal file
125
engine/servers/rendering/renderer_rd/effects/bokeh_dof.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BOKEH_DOF_RD_H
|
||||
#define BOKEH_DOF_RD_H
|
||||
|
||||
#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"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // BOKEH_DOF_RD_H
|
||||
1307
engine/servers/rendering/renderer_rd/effects/copy_effects.cpp
Normal file
1307
engine/servers/rendering/renderer_rd/effects/copy_effects.cpp
Normal file
File diff suppressed because it is too large
Load diff
363
engine/servers/rendering/renderer_rd/effects/copy_effects.h
Normal file
363
engine/servers/rendering/renderer_rd/effects/copy_effects.h
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef COPY_EFFECTS_RD_H
|
||||
#define COPY_EFFECTS_RD_H
|
||||
|
||||
#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];
|
||||
float screen_rect[4];
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
#endif // COPY_EFFECTS_RD_H
|
||||
379
engine/servers/rendering/renderer_rd/effects/debug_effects.cpp
Normal file
379
engine/servers/rendering/renderer_rd/effects/debug_effects.cpp
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/**************************************************************************/
|
||||
/* 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/renderer_compositor_rd.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>(), false);
|
||||
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
|
||||
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();
|
||||
}
|
||||
101
engine/servers/rendering/renderer_rd/effects/debug_effects.h
Normal file
101
engine/servers/rendering/renderer_rd/effects/debug_effects.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_EFFECTS_RD_H
|
||||
#define DEBUG_EFFECTS_RD_H
|
||||
|
||||
#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"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // DEBUG_EFFECTS_RD_H
|
||||
128
engine/servers/rendering/renderer_rd/effects/fsr.cpp
Normal file
128
engine/servers/rendering/renderer_rd/effects/fsr.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/**************************************************************************/
|
||||
/* 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;
|
||||
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
// MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though.
|
||||
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
|
||||
#else
|
||||
// Everyone else can use normal mode when available.
|
||||
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FSR_HALF_FLOAT)) {
|
||||
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
|
||||
} else {
|
||||
FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
fsr_shader.initialize(FSR_upscale_modes);
|
||||
|
||||
shader_version = fsr_shader.version_create();
|
||||
pipeline = RD::get_singleton()->compute_pipeline_create(fsr_shader.version_get_shader(shader_version, 0));
|
||||
}
|
||||
|
||||
FSR::~FSR() {
|
||||
fsr_shader.version_free(shader_version);
|
||||
}
|
||||
|
||||
void FSR::fsr_upscale(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();
|
||||
}
|
||||
72
engine/servers/rendering/renderer_rd/effects/fsr.h
Normal file
72
engine/servers/rendering/renderer_rd/effects/fsr.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FSR_RD_H
|
||||
#define FSR_RD_H
|
||||
|
||||
#include "../pipeline_cache_rd.h"
|
||||
#include "../storage_rd/render_scene_buffers_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class FSR {
|
||||
public:
|
||||
FSR();
|
||||
~FSR();
|
||||
|
||||
void fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture);
|
||||
|
||||
private:
|
||||
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
|
||||
|
||||
#endif // FSR_RD_H
|
||||
887
engine/servers/rendering/renderer_rd/effects/fsr2.cpp
Normal file
887
engine/servers/rendering/renderer_rd/effects/fsr2.cpp
Normal file
|
|
@ -0,0 +1,887 @@
|
|||
/**************************************************************************/
|
||||
/* 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 <wchar.h>
|
||||
#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 + floor(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;
|
||||
|
||||
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);
|
||||
|
||||
Vector<RD::Uniform> compute_uniforms;
|
||||
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;
|
||||
uint64_t default_subgroup_size = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_SIZE);
|
||||
capabilities.minimumSupportedShaderModel = FFX_SHADER_MODEL_5_1;
|
||||
capabilities.waveLaneCountMin = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MIN_SIZE);
|
||||
capabilities.waveLaneCountMax = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MAX_SIZE);
|
||||
capabilities.fp16Supported = RD::get_singleton()->has_feature(RD::Features::SUPPORTS_FSR_HALF_FLOAT);
|
||||
capabilities.raytracingSupported = false;
|
||||
|
||||
bool force_wave_64 = default_subgroup_size == 32 && capabilities.waveLaneCountMax == 64;
|
||||
bool use_lut = force_wave_64 || default_subgroup_size == 64;
|
||||
|
||||
String general_defines_base =
|
||||
"\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";
|
||||
|
||||
if (use_lut) {
|
||||
general_defines_base += "\n#define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1\n";
|
||||
}
|
||||
|
||||
String general_defines = general_defines_base;
|
||||
if (capabilities.fp16Supported) {
|
||||
general_defines += "\n#define FFX_HALF 1\n";
|
||||
}
|
||||
|
||||
Vector<String> modes;
|
||||
modes.push_back("");
|
||||
|
||||
// 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, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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;
|
||||
accumulate_modes.push_back("\n");
|
||||
accumulate_modes.push_back("\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
|
||||
|
||||
String general_defines_accumulate;
|
||||
if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
|
||||
// Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
|
||||
general_defines_accumulate = general_defines_base;
|
||||
} else {
|
||||
general_defines_accumulate = general_defines;
|
||||
}
|
||||
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_ACCUMULATE];
|
||||
pass.shader = &shaders.accumulate;
|
||||
pass.shader->initialize(accumulate_modes, general_defines_accumulate);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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.
|
||||
Pass &sharpen_pass = device.passes[FFX_FSR2_PASS_ACCUMULATE_SHARPEN];
|
||||
sharpen_pass = pass;
|
||||
sharpen_pass.shader_variant = 1;
|
||||
}
|
||||
|
||||
{
|
||||
Pass &pass = device.passes[FFX_FSR2_PASS_RCAS];
|
||||
pass.shader = &shaders.rcas;
|
||||
pass.shader->initialize(modes, general_defines_base);
|
||||
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, general_defines_base);
|
||||
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, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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, general_defines);
|
||||
pass.shader_version = pass.shader->version_create();
|
||||
|
||||
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++) {
|
||||
if (device.passes[i].pipeline.pipeline_rid.is_valid()) {
|
||||
RD::get_singleton()->free(device.passes[i].pipeline.pipeline_rid);
|
||||
}
|
||||
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);
|
||||
}
|
||||
199
engine/servers/rendering/renderer_rd/effects/fsr2.h
Normal file
199
engine/servers/rendering/renderer_rd/effects/fsr2.h
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FSR2_RD_H
|
||||
#define FSR2_RD_H
|
||||
|
||||
#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
|
||||
|
||||
#endif // FSR2_RD_H
|
||||
254
engine/servers/rendering/renderer_rd/effects/luminance.cpp
Normal file
254
engine/servers/rendering/renderer_rd/effects/luminance.cpp
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/**************************************************************************/
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
|
||||
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]);
|
||||
}
|
||||
120
engine/servers/rendering/renderer_rd/effects/luminance.h
Normal file
120
engine/servers/rendering/renderer_rd/effects/luminance.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef LUMINANCE_RD_H
|
||||
#define LUMINANCE_RD_H
|
||||
|
||||
#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"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // LUMINANCE_RD_H
|
||||
130
engine/servers/rendering/renderer_rd/effects/resolve.cpp
Normal file
130
engine/servers/rendering/renderer_rd/effects/resolve.cpp
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/**************************************************************************/
|
||||
/* 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/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;
|
||||
|
||||
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();
|
||||
}
|
||||
74
engine/servers/rendering/renderer_rd/effects/resolve.h
Normal file
74
engine/servers/rendering/renderer_rd/effects/resolve.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef RESOLVE_RD_H
|
||||
#define RESOLVE_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/resolve.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // RESOLVE_RD_H
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ROUGHNESS_LIMITER_RD_H
|
||||
#define ROUGHNESS_LIMITER_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/roughness_limiter.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // ROUGHNESS_LIMITER_RD_H
|
||||
124
engine/servers/rendering/renderer_rd/effects/sort_effects.cpp
Normal file
124
engine/servers/rendering/renderer_rd/effects/sort_effects.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/**************************************************************************/
|
||||
/* 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"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/uniform_set_cache_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();
|
||||
}
|
||||
71
engine/servers/rendering/renderer_rd/effects/sort_effects.h
Normal file
71
engine/servers/rendering/renderer_rd/effects/sort_effects.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SORT_EFFECTS_RD_H
|
||||
#define SORT_EFFECTS_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/sort.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.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
|
||||
|
||||
#endif // SORT_EFFECTS_RD_H
|
||||
1688
engine/servers/rendering/renderer_rd/effects/ss_effects.cpp
Normal file
1688
engine/servers/rendering/renderer_rd/effects/ss_effects.cpp
Normal file
File diff suppressed because it is too large
Load diff
533
engine/servers/rendering/renderer_rd/effects/ss_effects.h
Normal file
533
engine/servers/rendering/renderer_rd/effects/ss_effects.h
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SS_EFFECTS_RD_H
|
||||
#define SS_EFFECTS_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#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/renderer_scene_render.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
|
||||
|
||||
#endif // SS_EFFECTS_RD_H
|
||||
124
engine/servers/rendering/renderer_rd/effects/taa.cpp
Normal file
124
engine/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 = 0.025f;
|
||||
push_constant.disocclusion_scale = 10.0f;
|
||||
|
||||
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();
|
||||
}
|
||||
67
engine/servers/rendering/renderer_rd/effects/taa.h
Normal file
67
engine/servers/rendering/renderer_rd/effects/taa.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TAA_RD_H
|
||||
#define TAA_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/taa_resolve.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 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
|
||||
|
||||
#endif // TAA_RD_H
|
||||
259
engine/servers/rendering/renderer_rd/effects/tone_mapper.cpp
Normal file
259
engine/servers/rendering/renderer_rd/effects/tone_mapper.cpp
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/**************************************************************************/
|
||||
/* 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;
|
||||
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
|
||||
tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x;
|
||||
tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y;
|
||||
|
||||
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
|
||||
|
||||
if (p_settings.view_count > 1) {
|
||||
// Use 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::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
|
||||
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;
|
||||
|
||||
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
|
||||
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
|
||||
|
||||
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
|
||||
|
||||
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
|
||||
|
||||
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);
|
||||
}
|
||||
159
engine/servers/rendering/renderer_rd/effects/tone_mapper.h
Normal file
159
engine/servers/rendering/renderer_rd/effects/tone_mapper.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TONE_MAPPER_RD_H
|
||||
#define TONE_MAPPER_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/tonemap.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.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_DEBANDING = (1 << 5),
|
||||
TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 6),
|
||||
};
|
||||
|
||||
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;
|
||||
bool use_debanding = false;
|
||||
Vector2i texture_size;
|
||||
uint32_t view_count = 1;
|
||||
|
||||
bool convert_to_srgb = false;
|
||||
};
|
||||
|
||||
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
|
||||
void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
|
||||
};
|
||||
|
||||
} // namespace RendererRD
|
||||
|
||||
#endif // TONE_MAPPER_RD_H
|
||||
162
engine/servers/rendering/renderer_rd/effects/vrs.cpp
Normal file
162
engine/servers/rendering/renderer_rd/effects/vrs.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/**************************************************************************/
|
||||
/* 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 _3D_DISABLED
|
||||
#include "servers/xr_server.h"
|
||||
#endif // _3D_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_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 }));
|
||||
|
||||
VRSPushConstant push_constant = {};
|
||||
|
||||
int mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT;
|
||||
|
||||
// Set maximum texel factor based on maximum fragment size, some GPUs do not support 8x8 (fragment shading rate approach).
|
||||
if (MIN(RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_WIDTH), RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_HEIGHT)) > 4) {
|
||||
push_constant.max_texel_factor = 3.0;
|
||||
} else {
|
||||
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::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>());
|
||||
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 {
|
||||
int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH);
|
||||
int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT);
|
||||
|
||||
int width = p_base_size.x / texel_width;
|
||||
if (p_base_size.x % texel_width != 0) {
|
||||
width++;
|
||||
}
|
||||
int height = p_base_size.y / texel_height;
|
||||
if (p_base_size.y % texel_height != 0) {
|
||||
height++;
|
||||
}
|
||||
return Size2i(width, height);
|
||||
}
|
||||
|
||||
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 _3D_DISABLED
|
||||
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
|
||||
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
|
||||
if (interface.is_valid()) {
|
||||
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 // _3D_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();
|
||||
}
|
||||
}
|
||||
76
engine/servers/rendering/renderer_rd/effects/vrs.h
Normal file
76
engine/servers/rendering/renderer_rd/effects/vrs.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VRS_RD_H
|
||||
#define VRS_RD_H
|
||||
|
||||
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
|
||||
#include "servers/rendering/renderer_rd/shaders/effects/vrs.glsl.gen.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
class VRS {
|
||||
private:
|
||||
enum VRSMode {
|
||||
VRS_DEFAULT,
|
||||
VRS_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
|
||||
|
||||
#endif // VRS_RD_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue