1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-06 17:25:19 +00:00

Metal: Add MetalFX upscaling support

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
Stuart Carnie
2024-11-24 09:11:43 +11:00
parent bdf625bd54
commit 11dc4f2e5e
36 changed files with 1180 additions and 48 deletions

View File

@@ -88,6 +88,25 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_fsr2(Rende
}
}
#ifdef METAL_ENABLED
bool RenderForwardClustered::RenderBufferDataForwardClustered::ensure_mfx_temporal(RendererRD::MFXTemporalEffect *p_effect) {
if (mfx_temporal_context == nullptr) {
RendererRD::MFXTemporalEffect::CreateParams params;
params.input_size = render_buffers->get_internal_size();
params.output_size = render_buffers->get_target_size();
params.input_format = render_buffers->get_base_data_format();
params.depth_format = render_buffers->get_depth_format(false, false, render_buffers->get_can_be_storage());
params.motion_format = render_buffers->get_velocity_format();
params.reactive_format = render_buffers->get_base_data_format(); // Reactive is derived from input.
params.output_format = render_buffers->get_base_data_format();
params.motion_vector_scale = render_buffers->get_internal_size();
mfx_temporal_context = p_effect->create_context(params);
return true;
}
return false;
}
#endif
void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
// JIC, should already have been cleared
if (render_buffers) {
@@ -108,6 +127,13 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
fsr2_context = nullptr;
}
#ifdef METAL_ENABLED
if (mfx_temporal_context) {
memdelete(mfx_temporal_context);
mfx_temporal_context = nullptr;
}
#endif
if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) {
RD::get_singleton()->free(render_sdfgi_uniform_set);
}
@@ -1706,7 +1732,29 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool using_debug_mvs = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS;
bool using_taa = rb->get_use_taa();
bool using_fsr2 = rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR2;
enum {
SCALE_NONE,
SCALE_FSR2,
SCALE_MFX,
} scale_type = SCALE_NONE;
switch (rb->get_scaling_3d_mode()) {
case RS::VIEWPORT_SCALING_3D_MODE_FSR2:
scale_type = SCALE_FSR2;
break;
case RS::VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL:
#ifdef METAL_ENABLED
scale_type = SCALE_MFX;
#else
scale_type = SCALE_NONE;
#endif
break;
default:
break;
}
bool using_upscaling = scale_type != SCALE_NONE;
// check if we need motion vectors
bool motion_vectors_required;
@@ -1716,7 +1764,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
motion_vectors_required = true;
} else if (!is_reflection_probe && using_taa) {
motion_vectors_required = true;
} else if (!is_reflection_probe && using_fsr2) {
} else if (!is_reflection_probe && using_upscaling) {
motion_vectors_required = true;
} else {
motion_vectors_required = false;
@@ -1742,7 +1790,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool using_voxelgi = false;
bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
bool using_ssil = !is_reflection_probe && p_render_data->environment.is_valid() && environment_get_ssil_enabled(p_render_data->environment);
bool using_motion_pass = rb_data.is_valid() && using_fsr2;
bool using_motion_pass = rb_data.is_valid() && using_upscaling;
if (is_reflection_probe) {
uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
@@ -2111,10 +2159,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
if (using_motion_pass) {
Vector<Color> motion_vector_clear_colors;
motion_vector_clear_colors.push_back(Color(-1, -1, 0, 0));
RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::DRAW_CLEAR_ALL, motion_vector_clear_colors);
RD::get_singleton()->draw_list_end();
if (scale_type == SCALE_MFX) {
motion_vectors_store->process(rb,
p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform,
p_render_data->scene_data->prev_cam_projection, p_render_data->scene_data->prev_cam_transform);
} else {
Vector<Color> motion_vector_clear_colors;
motion_vector_clear_colors.push_back(Color(-1, -1, 0, 0));
RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::DRAW_CLEAR_ALL, motion_vector_clear_colors);
RD::get_singleton()->draw_list_end();
}
}
if (render_motion_pass) {
@@ -2244,7 +2298,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_list_end();
}
if (rb_data.is_valid() && using_fsr2) {
if (rb_data.is_valid() && using_upscaling) {
// Make sure the upscaled texture is initialized, but not necessarily filled, before running screen copies
// so it properly detect if a dedicated copy texture should be used.
rb->ensure_upscaled();
@@ -2314,7 +2368,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Resolve");
if (rb_data.is_valid() && use_msaa) {
bool resolve_velocity_buffer = (using_taa || using_fsr2 || ce_needs_motion_vectors) && rb->has_velocity_buffer(true);
bool resolve_velocity_buffer = (using_taa || using_upscaling || ce_needs_motion_vectors) && rb->has_velocity_buffer(true);
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
RD::get_singleton()->texture_resolve_multisample(rb->get_color_msaa(v), rb->get_internal_texture(v));
resolve_effects->resolve_depth(rb->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[msaa]);
@@ -2339,8 +2393,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
if (rb_data.is_valid() && (using_fsr2 || using_taa)) {
if (using_fsr2) {
if (rb_data.is_valid() && (using_upscaling || using_taa)) {
if (scale_type == SCALE_FSR2) {
rb_data->ensure_fsr2(fsr2_effect);
RID exposure;
@@ -2386,6 +2440,35 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
} else if (scale_type == SCALE_MFX) {
#ifdef METAL_ENABLED
bool reset = rb_data->ensure_mfx_temporal(mfx_temporal_effect);
RID exposure;
if (RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes)) {
exposure = luminance->get_current_luminance_buffer(rb);
}
RD::get_singleton()->draw_command_begin_label("MetalFX Temporal");
// Scale to ±0.5.
Vector2 jitter = p_render_data->scene_data->taa_jitter * 0.5f;
jitter *= Vector2(1.0, -1.0); // Flip y-axis as bottom left is origin.
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
RendererRD::MFXTemporalEffect::Params params;
params.src = rb->get_internal_texture(v);
params.depth = rb->get_depth_texture(v);
params.motion = rb->get_velocity_buffer(false, v);
params.exposure = exposure;
params.dst = rb->get_upscaled_texture(v);
params.jitter_offset = jitter;
params.reset = reset;
mfx_temporal_effect->process(rb_data->get_mfx_temporal_context(), params);
}
RD::get_singleton()->draw_command_end_label();
#endif
} else if (using_taa) {
RD::get_singleton()->draw_command_begin_label("TAA");
RENDER_TIMESTAMP("TAA");
@@ -4846,6 +4929,10 @@ RenderForwardClustered::RenderForwardClustered() {
taa = memnew(RendererRD::TAA);
fsr2_effect = memnew(RendererRD::FSR2Effect);
ss_effects = memnew(RendererRD::SSEffects);
#ifdef METAL_ENABLED
motion_vectors_store = memnew(RendererRD::MotionVectorsStore);
mfx_temporal_effect = memnew(RendererRD::MFXTemporalEffect);
#endif
}
RenderForwardClustered::~RenderForwardClustered() {
@@ -4864,6 +4951,18 @@ RenderForwardClustered::~RenderForwardClustered() {
fsr2_effect = nullptr;
}
#ifdef METAL_ENABLED
if (mfx_temporal_effect) {
memdelete(mfx_temporal_effect);
mfx_temporal_effect = nullptr;
}
if (motion_vectors_store) {
memdelete(motion_vectors_store);
motion_vectors_store = nullptr;
}
#endif
if (resolve_effects != nullptr) {
memdelete(resolve_effects);
resolve_effects = nullptr;

View File

@@ -34,6 +34,10 @@
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/fsr2.h"
#ifdef METAL_ENABLED
#include "servers/rendering/renderer_rd/effects/metal_fx.h"
#endif
#include "servers/rendering/renderer_rd/effects/motion_vectors_store.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/taa.h"
@@ -91,6 +95,9 @@ public:
private:
RenderSceneBuffersRD *render_buffers = nullptr;
RendererRD::FSR2Context *fsr2_context = nullptr;
#ifdef METAL_ENABLED
RendererRD::MFXTemporalContext *mfx_temporal_context = nullptr;
#endif
public:
ClusterBuilderRD *cluster_builder = nullptr;
@@ -134,6 +141,11 @@ public:
void ensure_fsr2(RendererRD::FSR2Effect *p_effect);
RendererRD::FSR2Context *get_fsr2_context() const { return fsr2_context; }
#ifdef METAL_ENABLED
bool ensure_mfx_temporal(RendererRD::MFXTemporalEffect *p_effect);
RendererRD::MFXTemporalContext *get_mfx_temporal_context() const { return mfx_temporal_context; }
#endif
RID get_color_only_fb();
RID get_color_pass_fb(uint32_t p_color_pass_flags);
RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
@@ -634,6 +646,11 @@ private:
RendererRD::FSR2Effect *fsr2_effect = nullptr;
RendererRD::SSEffects *ss_effects = nullptr;
#ifdef METAL_ENABLED
RendererRD::MFXTemporalEffect *mfx_temporal_effect = nullptr;
#endif
RendererRD::MotionVectorsStore *motion_vectors_store = nullptr;
/* Cluster builder */
ClusterBuilderSharedDataRD cluster_builder_shared;