Skip to content

Commit f217c16

Browse files
committed
Metal: Add MetalFX via godotengine#99603
1 parent 2810888 commit f217c16

36 files changed

+1118
-70
lines changed

doc/classes/ProjectSettings.xml

+6
Original file line numberDiff line numberDiff line change
@@ -3024,6 +3024,12 @@
30243024
Sets the scaling 3D mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially-aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. On particularly low-end GPUs, the added cost of FSR may not be worth it (compared to using bilinear scaling with a slightly higher resolution scale to match performance).
30253025
[b]Note:[/b] FSR is only effective when using the Forward+ rendering method, not Mobile or Compatibility. If using an incompatible rendering method, FSR will fall back to bilinear scaling.
30263026
</member>
3027+
<member name="rendering/scaling_3d/mode.ios" type="int" setter="" getter="">
3028+
iOS override for [member rendering/scaling_3d/mode]. This allows selecting the MetalFX spatial and MetalFX temporal scaling modes, which are exclusive to platforms where the Metal rendering driver is used.
3029+
</member>
3030+
<member name="rendering/scaling_3d/mode.macos" type="int" setter="" getter="">
3031+
macOS override for [member rendering/scaling_3d/mode]. This allows selecting the MetalFX spatial and MetalFX temporal scaling modes, which are exclusive to platforms where the Metal rendering driver is used.
3032+
</member>
30273033
<member name="rendering/scaling_3d/scale" type="float" setter="" getter="" default="1.0">
30283034
Scales the 3D render buffer based on the viewport size uses an image filter specified in [member rendering/scaling_3d/mode] to scale the output image to the full viewport size. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] are only valid for bilinear mode and can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [member rendering/anti_aliasing/quality/msaa_3d] for multi-sample antialiasing, which is significantly cheaper but only smooths the edges of polygons.
30293035
</member>

doc/classes/RenderingDevice.xml

+8
Original file line numberDiff line numberDiff line change
@@ -2529,6 +2529,14 @@
25292529
<constant name="LIMIT_MAX_VIEWPORT_DIMENSIONS_Y" value="36" enum="Limit">
25302530
Maximum viewport height (in pixels).
25312531
</constant>
2532+
<constant name="LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE" value="46" enum="Limit">
2533+
Returns the smallest value for [member ProjectSettings.rendering/scaling_3d/scale] when using the MetalFX temporal upscaler.
2534+
[b]Note:[/b] The returned value is multiplied by a factor of [code]1000000[/code] to preserve 6 digits of precision. It must be divided by [code]1000000.0[/code] to convert the value to a floating point number.
2535+
</constant>
2536+
<constant name="LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE" value="47" enum="Limit">
2537+
Returns the largest value for [member ProjectSettings.rendering/scaling_3d/scale] when using the MetalFX temporal upscaler.
2538+
[b]Note:[/b] The returned value is multiplied by a factor of [code]1000000[/code] to preserve 6 digits of precision. It must be divided by [code]1000000.0[/code] to convert the value to a floating point number.
2539+
</constant>
25322540
<constant name="MEMORY_TEXTURES" value="0" enum="MemoryType">
25332541
Memory taken by textures.
25342542
</constant>

doc/classes/RenderingServer.xml

+9-1
Original file line numberDiff line numberDiff line change
@@ -4986,7 +4986,15 @@
49864986
<constant name="VIEWPORT_SCALING_3D_MODE_FSR2" value="2" enum="ViewportScaling3DMode">
49874987
Use AMD FidelityFX Super Resolution 2.2 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR2. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use FSR2 at native resolution as a TAA solution.
49884988
</constant>
4989-
<constant name="VIEWPORT_SCALING_3D_MODE_MAX" value="3" enum="ViewportScaling3DMode">
4989+
<constant name="VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL" value="3" enum="ViewportScaling3DMode">
4990+
Use MetalFX spatial upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using MetalFX. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
4991+
[b]Note:[/b] Only supported when the Metal rendering driver is in use, which limits this scaling mode to macOS and iOS.
4992+
</constant>
4993+
<constant name="VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL" value="4" enum="ViewportScaling3DMode">
4994+
Use MetalFX temporal upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using MetalFX. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use MetalFX at native resolution as a TAA solution.
4995+
[b]Note:[/b] Only supported when the Metal rendering driver is in use, which limits this scaling mode to macOS and iOS.
4996+
</constant>
4997+
<constant name="VIEWPORT_SCALING_3D_MODE_MAX" value="5" enum="ViewportScaling3DMode">
49904998
Represents the size of the [enum ViewportScaling3DMode] enum.
49914999
</constant>
49925000
<constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">

doc/classes/Viewport.xml

+15-1
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,21 @@
503503
<constant name="SCALING_3D_MODE_FSR2" value="2" enum="Scaling3DMode">
504504
Use AMD FidelityFX Super Resolution 2.2 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR2. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use FSR2 at native resolution as a TAA solution.
505505
</constant>
506-
<constant name="SCALING_3D_MODE_MAX" value="3" enum="Scaling3DMode">
506+
<constant name="SCALING_3D_MODE_METALFX_SPATIAL" value="3" enum="Scaling3DMode">
507+
Use the [url=https://developer.apple.com/documentation/metalfx/mtlfxspatialscaler#overview]MetalFX spatial upscaler[/url] for the viewport's 3D buffer.
508+
The amount of scaling can be set using [member scaling_3d_scale].
509+
Values less than [code]1.0[/code] will be result in the viewport being upscaled using MetalFX. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
510+
More information: [url=https://developer.apple.com/documentation/metalfx]MetalFX[/url].
511+
[b]Note:[/b] Only supported when the Metal rendering driver is in use, which limits this scaling mode to macOS and iOS.
512+
</constant>
513+
<constant name="SCALING_3D_MODE_METALFX_TEMPORAL" value="4" enum="Scaling3DMode">
514+
Use the [url=https://developer.apple.com/documentation/metalfx/mtlfxtemporalscaler#overview]MetalFX temporal upscaler[/url] for the viewport's 3D buffer.
515+
The amount of scaling can be set using [member scaling_3d_scale]. To determine the minimum input scale, use the [method RenderingDevice.limit_get] method with [constant RenderingDevice.LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE].
516+
Values less than [code]1.0[/code] will be result in the viewport being upscaled using MetalFX. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use MetalFX at native resolution as a TAA solution.
517+
More information: [url=https://developer.apple.com/documentation/metalfx]MetalFX[/url].
518+
[b]Note:[/b] Only supported when the Metal rendering driver is in use, which limits this scaling mode to macOS and iOS.
519+
</constant>
520+
<constant name="SCALING_3D_MODE_MAX" value="5" enum="Scaling3DMode">
507521
Represents the size of the [enum Scaling3DMode] enum.
508522
</constant>
509523
<constant name="MSAA_DISABLED" value="0" enum="MSAA">

drivers/metal/metal_device_properties.h

+7
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) MetalFeatures {
8484
bool tessellationShader = false; /**< If true, tessellation shaders are supported. */
8585
bool imageCubeArray = false; /**< If true, image cube arrays are supported. */
8686
MTLArgumentBuffersTier argument_buffers_tier = MTLArgumentBuffersTier1;
87+
/// If true, argument encoders are required to encode arguments into an argument buffer.
88+
bool needs_arg_encoders = true;
89+
bool metal_fx_spatial = false; /**< If true, Metal FX spatial functions are supported. */
90+
bool metal_fx_temporal = false; /**< If true, Metal FX temporal functions are supported. */
8791
};
8892

8993
struct MetalLimits {
@@ -115,6 +119,9 @@ struct MetalLimits {
115119
uint32_t maxVertexInputBindingStride;
116120
uint32_t maxDrawIndexedIndexValue;
117121

122+
double temporalScalerInputContentMinScale;
123+
double temporalScalerInputContentMaxScale;
124+
118125
uint32_t minSubgroupSize; /**< The minimum number of threads in a SIMD-group. */
119126
uint32_t maxSubgroupSize; /**< The maximum number of threads in a SIMD-group. */
120127
BitField<RDD::ShaderStage> subgroupSupportedShaderStages;

drivers/metal/metal_device_properties.mm

+15
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#import "metal_device_properties.h"
5252

5353
#import <Metal/Metal.h>
54+
#import <MetalFX/MetalFX.h>
5455
#import <spirv_cross.hpp>
5556
#import <spirv_msl.hpp>
5657

@@ -100,6 +101,11 @@
100101
features.simdReduction = [p_device supportsFamily:MTLGPUFamilyApple7];
101102
features.argument_buffers_tier = p_device.argumentBuffersSupport;
102103

104+
if (@available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) {
105+
features.metal_fx_spatial = [MTLFXSpatialScalerDescriptor supportsDevice:p_device];
106+
features.metal_fx_temporal = [MTLFXTemporalScalerDescriptor supportsDevice:p_device];
107+
}
108+
103109
MTLCompileOptions *opts = [MTLCompileOptions new];
104110
features.mslVersionEnum = opts.languageVersion; // By default, Metal uses the most recent language version.
105111

@@ -285,6 +291,15 @@
285291
#endif
286292

287293
limits.maxDrawIndexedIndexValue = std::numeric_limits<uint32_t>::max() - 1;
294+
295+
if (@available(macOS 14.0, iOS 17.0, tvOS 17.0, *)) {
296+
limits.temporalScalerInputContentMinScale = (double)[MTLFXTemporalScalerDescriptor supportedInputContentMinScaleForDevice:p_device];
297+
limits.temporalScalerInputContentMaxScale = (double)[MTLFXTemporalScalerDescriptor supportedInputContentMaxScaleForDevice:p_device];
298+
} else {
299+
// Defaults taken from macOS 14+
300+
limits.temporalScalerInputContentMinScale = 1.0;
301+
limits.temporalScalerInputContentMaxScale = 3.0;
302+
}
288303
}
289304

290305
MetalDeviceProperties::MetalDeviceProperties(id<MTLDevice> p_device) {

platform/ios/detect.py

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ def configure(env: "SConsEnvironment"):
160160
env.Prepend(
161161
CPPPATH=[
162162
"$IOS_SDK_PATH/System/Library/Frameworks/Metal.framework/Headers",
163+
"$IOS_SDK_PATH/System/Library/Frameworks/MetalFX.framework/Headers",
163164
"$IOS_SDK_PATH/System/Library/Frameworks/QuartzCore.framework/Headers",
164165
]
165166
)

platform/macos/detect.py

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ def configure(env: "SConsEnvironment"):
243243
env.AppendUnique(CPPDEFINES=["METAL_ENABLED", "RD_ENABLED"])
244244
extra_frameworks.add("Metal")
245245
extra_frameworks.add("MetalKit")
246+
extra_frameworks.add("MetalFX")
246247
env.Prepend(CPPPATH=["#thirdparty/spirv-cross"])
247248

248249
if env["vulkan"]:

scene/main/viewport.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -4899,7 +4899,7 @@ void Viewport::_bind_methods() {
48994899

49004900
#ifndef _3D_DISABLED
49014901
ADD_GROUP("Scaling 3D", "");
4902-
ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
4902+
ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow),MetalFX (Spatial),MetalFX (Temporal)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
49034903
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scaling_3d_scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), "set_scaling_3d_scale", "get_scaling_3d_scale");
49044904
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.001"), "set_texture_mipmap_bias", "get_texture_mipmap_bias");
49054905
ADD_PROPERTY(PropertyInfo(Variant::INT, "anisotropic_filtering_level", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Faster),4× (Fast),8× (Average),16x (Slow)")), "set_anisotropic_filtering_level", "get_anisotropic_filtering_level");
@@ -4954,6 +4954,8 @@ void Viewport::_bind_methods() {
49544954
BIND_ENUM_CONSTANT(SCALING_3D_MODE_BILINEAR);
49554955
BIND_ENUM_CONSTANT(SCALING_3D_MODE_FSR);
49564956
BIND_ENUM_CONSTANT(SCALING_3D_MODE_FSR2);
4957+
BIND_ENUM_CONSTANT(SCALING_3D_MODE_METALFX_SPATIAL);
4958+
BIND_ENUM_CONSTANT(SCALING_3D_MODE_METALFX_TEMPORAL);
49574959
BIND_ENUM_CONSTANT(SCALING_3D_MODE_MAX);
49584960

49594961
BIND_ENUM_CONSTANT(MSAA_DISABLED);

scene/main/viewport.h

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class Viewport : public Node {
100100
SCALING_3D_MODE_BILINEAR,
101101
SCALING_3D_MODE_FSR,
102102
SCALING_3D_MODE_FSR2,
103+
SCALING_3D_MODE_METALFX_SPATIAL,
104+
SCALING_3D_MODE_METALFX_TEMPORAL,
103105
SCALING_3D_MODE_MAX
104106
};
105107

servers/rendering/renderer_rd/effects/CMakeLists.txt

+11
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@ target_sources(godot-server-rendering-renderer_rd-effects PRIVATE
2020
fsr2.h
2121
luminance.cpp
2222
luminance.h
23+
metal_fx.h
24+
metal_fx.mm
25+
motion_vectors_store.cpp
26+
motion_vectors_store.h
2327
resolve.cpp
2428
resolve.h
2529
roughness_limiter.cpp
2630
roughness_limiter.h
2731
sort_effects.cpp
2832
sort_effects.h
33+
spatial_upscaler.h
2934
ss_effects.cpp
3035
ss_effects.h
3136
taa.cpp
@@ -38,3 +43,9 @@ target_sources(godot-server-rendering-renderer_rd-effects PRIVATE
3843
# [[[end]]]
3944

4045
target_link_libraries(godot-server-rendering-renderer_rd-effects PRIVATE godot-config)
46+
47+
set_property(
48+
SOURCE metal_fx.mm
49+
APPEND
50+
PROPERTY COMPILE_DEFINITIONS $<$<BOOL:${WANT_METAL}>:METAL_ENABLED=1 RD_ENABLED=1>
51+
)

servers/rendering/renderer_rd/effects/SCsub

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ env.servers_sources += thirdparty_obj
2929
module_obj = []
3030

3131
env_effects.add_source_files(module_obj, "*.cpp")
32+
if env["metal"]:
33+
env_effects.add_source_files(module_obj, "metal_fx.mm")
3234
env.servers_sources += module_obj
3335

3436
# Needed to force rebuilding the module files when the thirdparty library is updated.

servers/rendering/renderer_rd/effects/fsr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ FSR::~FSR() {
5252
fsr_shader.version_free(shader_version);
5353
}
5454

55-
void FSR::fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) {
55+
void FSR::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) {
5656
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
5757
ERR_FAIL_NULL(uniform_set_cache);
5858
MaterialStorage *material_storage = MaterialStorage::get_singleton();

servers/rendering/renderer_rd/effects/fsr.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,23 @@
3131
#ifndef FSR_RD_H
3232
#define FSR_RD_H
3333

34+
#include "spatial_upscaler.h"
35+
3436
#include "../storage_rd/render_scene_buffers_rd.h"
3537
#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
3638

3739
namespace RendererRD {
3840

39-
class FSR {
41+
class FSR : public SpatialUpscaler {
42+
String name = "FSR 1.0 Upscale";
43+
4044
public:
4145
FSR();
4246
~FSR();
4347

44-
void fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture);
48+
virtual String get_label() const final { return name; }
49+
virtual void ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) final {}
50+
virtual void process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) final;
4551

4652
private:
4753
enum FSRUpscalePass {

0 commit comments

Comments
 (0)