mirror of
https://github.com/godotengine/godot.git
synced 2026-02-07 19:32:36 +00:00
Metal: Refactor for future Metal 4, switch to C++; fix dynamic uniforms
This commit is contained in:
@@ -7,6 +7,10 @@ Import("env")
|
||||
|
||||
env_effects = env.Clone()
|
||||
|
||||
# metal-cpp headers for Metal FX
|
||||
if env["metal"]:
|
||||
env_effects.Prepend(CPPPATH=["#thirdparty/metal-cpp"])
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
@@ -69,8 +73,6 @@ env.servers_sources += thirdparty_obj
|
||||
module_obj = []
|
||||
|
||||
env_effects.add_source_files(module_obj, "*.cpp")
|
||||
if env["metal"]:
|
||||
env_effects.add_source_files(module_obj, "metal_fx.mm")
|
||||
env.servers_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**************************************************************************/
|
||||
/* metal_fx.mm */
|
||||
/* metal_fx.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
@@ -28,20 +28,24 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "metal_fx.h"
|
||||
#ifdef METAL_ENABLED
|
||||
|
||||
#import "../storage_rd/render_scene_buffers_rd.h"
|
||||
#import "drivers/metal/pixel_formats.h"
|
||||
#import "drivers/metal/rendering_device_driver_metal.h"
|
||||
#include "metal_fx.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalFX/MetalFX.h>
|
||||
#include "../storage_rd/render_scene_buffers_rd.h"
|
||||
#include "drivers/metal/pixel_formats.h"
|
||||
#include "drivers/metal/rendering_device_driver_metal3.h"
|
||||
|
||||
#include <MetalFX/MetalFX.hpp>
|
||||
|
||||
using namespace RendererRD;
|
||||
|
||||
#pragma mark - Spatial Scaler
|
||||
|
||||
MFXSpatialContext::~MFXSpatialContext() {
|
||||
if (scaler) {
|
||||
scaler->release();
|
||||
}
|
||||
}
|
||||
|
||||
MFXSpatialEffect::MFXSpatialEffect() {
|
||||
@@ -51,28 +55,21 @@ MFXSpatialEffect::~MFXSpatialEffect() {
|
||||
}
|
||||
|
||||
void MFXSpatialEffect::callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
MDCommandBuffer *obj = (MDCommandBuffer *)(p_command_buffer.id);
|
||||
MDCommandBufferBase *obj = (MDCommandBufferBase *)(p_command_buffer.id);
|
||||
obj->end();
|
||||
|
||||
id<MTLTexture> src_texture = rid::get(p_userdata->src);
|
||||
id<MTLTexture> dst_texture = rid::get(p_userdata->dst);
|
||||
MTL::Texture *src_texture = reinterpret_cast<MTL::Texture *>(p_userdata->src.id);
|
||||
MTL::Texture *dst_texture = reinterpret_cast<MTL::Texture *>(p_userdata->dst.id);
|
||||
|
||||
__block id<MTLFXSpatialScaler> scaler = p_userdata->ctx.scaler;
|
||||
scaler.colorTexture = src_texture;
|
||||
scaler.outputTexture = dst_texture;
|
||||
[scaler encodeToCommandBuffer:obj->get_command_buffer()];
|
||||
// TODO(sgc): add API to retain objects until the command buffer completes
|
||||
[obj->get_command_buffer() addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
|
||||
// This block retains a reference to the scaler until the command buffer.
|
||||
// completes.
|
||||
scaler = nil;
|
||||
}];
|
||||
MTLFX::SpatialScalerBase *scaler = p_userdata->scaler;
|
||||
scaler->setColorTexture(src_texture);
|
||||
scaler->setOutputTexture(dst_texture);
|
||||
MTLFX::SpatialScaler *s = static_cast<MTLFX::SpatialScaler *>(scaler);
|
||||
MTL3::MDCommandBuffer *cmd = (MTL3::MDCommandBuffer *)(p_command_buffer.id);
|
||||
s->encodeToCommandBuffer(cmd->get_command_buffer());
|
||||
obj->retain_resource(scaler);
|
||||
|
||||
CallbackArgs::free(&p_userdata);
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
}
|
||||
|
||||
void MFXSpatialEffect::ensure_context(Ref<RenderSceneBuffersRD> p_render_buffers) {
|
||||
@@ -98,27 +95,23 @@ void MFXSpatialEffect::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
|
||||
MFXSpatialContext *MFXSpatialEffect::create_context(CreateParams p_params) const {
|
||||
DEV_ASSERT(RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_SPATIAL));
|
||||
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
RenderingDeviceDriverMetal *rdd = (RenderingDeviceDriverMetal *)RD::get_singleton()->get_device_driver();
|
||||
PixelFormats &pf = rdd->get_pixel_formats();
|
||||
id<MTLDevice> dev = rdd->get_device();
|
||||
MTL::Device *dev = rdd->get_device();
|
||||
|
||||
MTLFXSpatialScalerDescriptor *desc = [MTLFXSpatialScalerDescriptor new];
|
||||
desc.inputWidth = (NSUInteger)p_params.input_size.width;
|
||||
desc.inputHeight = (NSUInteger)p_params.input_size.height;
|
||||
NS::SharedPtr<MTLFX::SpatialScalerDescriptor> desc = NS::TransferPtr(MTLFX::SpatialScalerDescriptor::alloc()->init());
|
||||
desc->setInputWidth((NS::UInteger)p_params.input_size.width);
|
||||
desc->setInputHeight((NS::UInteger)p_params.input_size.height);
|
||||
|
||||
desc.outputWidth = (NSUInteger)p_params.output_size.width;
|
||||
desc.outputHeight = (NSUInteger)p_params.output_size.height;
|
||||
desc->setOutputWidth((NS::UInteger)p_params.output_size.width);
|
||||
desc->setOutputHeight((NS::UInteger)p_params.output_size.height);
|
||||
|
||||
desc->setColorTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.input_format));
|
||||
desc->setOutputTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.output_format));
|
||||
desc->setColorProcessingMode(MTLFX::SpatialScalerColorProcessingModeLinear);
|
||||
|
||||
desc.colorTextureFormat = pf.getMTLPixelFormat(p_params.input_format);
|
||||
desc.outputTextureFormat = pf.getMTLPixelFormat(p_params.output_format);
|
||||
desc.colorProcessingMode = MTLFXSpatialScalerColorProcessingModeLinear;
|
||||
id<MTLFXSpatialScaler> scaler = [desc newSpatialScalerWithDevice:dev];
|
||||
MFXSpatialContext *context = memnew(MFXSpatialContext);
|
||||
context->scaler = scaler;
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
context->scaler = desc->newSpatialScaler(dev);
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -127,7 +120,11 @@ MFXSpatialContext *MFXSpatialEffect::create_context(CreateParams p_params) const
|
||||
|
||||
#pragma mark - Temporal Scaler
|
||||
|
||||
MFXTemporalContext::~MFXTemporalContext() {}
|
||||
MFXTemporalContext::~MFXTemporalContext() {
|
||||
if (scaler) {
|
||||
scaler->release();
|
||||
}
|
||||
}
|
||||
|
||||
MFXTemporalEffect::MFXTemporalEffect() {}
|
||||
MFXTemporalEffect::~MFXTemporalEffect() {}
|
||||
@@ -135,35 +132,29 @@ MFXTemporalEffect::~MFXTemporalEffect() {}
|
||||
MFXTemporalContext *MFXTemporalEffect::create_context(CreateParams p_params) const {
|
||||
DEV_ASSERT(RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_TEMPORAL));
|
||||
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
RenderingDeviceDriverMetal *rdd = (RenderingDeviceDriverMetal *)RD::get_singleton()->get_device_driver();
|
||||
PixelFormats &pf = rdd->get_pixel_formats();
|
||||
id<MTLDevice> dev = rdd->get_device();
|
||||
MTL::Device *dev = rdd->get_device();
|
||||
|
||||
MTLFXTemporalScalerDescriptor *desc = [MTLFXTemporalScalerDescriptor new];
|
||||
desc.inputWidth = (NSUInteger)p_params.input_size.width;
|
||||
desc.inputHeight = (NSUInteger)p_params.input_size.height;
|
||||
NS::SharedPtr<MTLFX::TemporalScalerDescriptor> desc = NS::TransferPtr(MTLFX::TemporalScalerDescriptor::alloc()->init());
|
||||
desc->setInputWidth((NS::UInteger)p_params.input_size.width);
|
||||
desc->setInputHeight((NS::UInteger)p_params.input_size.height);
|
||||
|
||||
desc.outputWidth = (NSUInteger)p_params.output_size.width;
|
||||
desc.outputHeight = (NSUInteger)p_params.output_size.height;
|
||||
desc->setOutputWidth((NS::UInteger)p_params.output_size.width);
|
||||
desc->setOutputHeight((NS::UInteger)p_params.output_size.height);
|
||||
|
||||
desc.colorTextureFormat = pf.getMTLPixelFormat(p_params.input_format);
|
||||
desc.depthTextureFormat = pf.getMTLPixelFormat(p_params.depth_format);
|
||||
desc.motionTextureFormat = pf.getMTLPixelFormat(p_params.motion_format);
|
||||
desc.autoExposureEnabled = NO;
|
||||
desc->setColorTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.input_format));
|
||||
desc->setDepthTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.depth_format));
|
||||
desc->setMotionTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.motion_format));
|
||||
desc->setAutoExposureEnabled(false);
|
||||
|
||||
desc.outputTextureFormat = pf.getMTLPixelFormat(p_params.output_format);
|
||||
desc->setOutputTextureFormat((MTL::PixelFormat)pf.getMTLPixelFormat(p_params.output_format));
|
||||
|
||||
id<MTLFXTemporalScaler> scaler = [desc newTemporalScalerWithDevice:dev];
|
||||
MFXTemporalContext *context = memnew(MFXTemporalContext);
|
||||
context->scaler = scaler;
|
||||
|
||||
scaler.motionVectorScaleX = p_params.motion_vector_scale.x;
|
||||
scaler.motionVectorScaleY = p_params.motion_vector_scale.y;
|
||||
scaler.depthReversed = true; // Godot uses reverse Z per https://github.com/godotengine/godot/pull/88328
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
context->scaler = desc->newTemporalScaler(dev);
|
||||
context->scaler->setMotionVectorScaleX(p_params.motion_vector_scale.x);
|
||||
context->scaler->setMotionVectorScaleY(p_params.motion_vector_scale.y);
|
||||
context->scaler->setDepthReversed(true); // Godot uses reverse Z per https://github.com/godotengine/godot/pull/88328
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -188,38 +179,33 @@ void MFXTemporalEffect::process(RendererRD::MFXTemporalContext *p_ctx, RendererR
|
||||
}
|
||||
|
||||
void MFXTemporalEffect::callback(RDD *p_driver, RDD::CommandBufferID p_command_buffer, CallbackArgs *p_userdata) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
|
||||
MDCommandBuffer *obj = (MDCommandBuffer *)(p_command_buffer.id);
|
||||
MDCommandBufferBase *obj = (MDCommandBufferBase *)(p_command_buffer.id);
|
||||
obj->end();
|
||||
|
||||
id<MTLTexture> src_texture = rid::get(p_userdata->src);
|
||||
id<MTLTexture> depth = rid::get(p_userdata->depth);
|
||||
id<MTLTexture> motion = rid::get(p_userdata->motion);
|
||||
id<MTLTexture> exposure = rid::get(p_userdata->exposure);
|
||||
MTL::Texture *src_texture = reinterpret_cast<MTL::Texture *>(p_userdata->src.id);
|
||||
MTL::Texture *depth = reinterpret_cast<MTL::Texture *>(p_userdata->depth.id);
|
||||
MTL::Texture *motion = reinterpret_cast<MTL::Texture *>(p_userdata->motion.id);
|
||||
MTL::Texture *exposure = reinterpret_cast<MTL::Texture *>(p_userdata->exposure.id);
|
||||
|
||||
id<MTLTexture> dst_texture = rid::get(p_userdata->dst);
|
||||
MTL::Texture *dst_texture = reinterpret_cast<MTL::Texture *>(p_userdata->dst.id);
|
||||
|
||||
__block id<MTLFXTemporalScaler> scaler = p_userdata->ctx.scaler;
|
||||
scaler.reset = p_userdata->reset;
|
||||
scaler.colorTexture = src_texture;
|
||||
scaler.depthTexture = depth;
|
||||
scaler.motionTexture = motion;
|
||||
scaler.exposureTexture = exposure;
|
||||
scaler.jitterOffsetX = p_userdata->jitter_offset.x;
|
||||
scaler.jitterOffsetY = p_userdata->jitter_offset.y;
|
||||
scaler.outputTexture = dst_texture;
|
||||
[scaler encodeToCommandBuffer:obj->get_command_buffer()];
|
||||
// TODO(sgc): add API to retain objects until the command buffer completes
|
||||
[obj->get_command_buffer() addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
|
||||
// This block retains a reference to the scaler until the command buffer.
|
||||
// completes.
|
||||
scaler = nil;
|
||||
}];
|
||||
MTLFX::TemporalScalerBase *scaler = p_userdata->scaler;
|
||||
scaler->setReset(p_userdata->reset);
|
||||
scaler->setColorTexture(src_texture);
|
||||
scaler->setDepthTexture(depth);
|
||||
scaler->setMotionTexture(motion);
|
||||
scaler->setExposureTexture(exposure);
|
||||
scaler->setJitterOffsetX(p_userdata->jitter_offset.x);
|
||||
scaler->setJitterOffsetY(p_userdata->jitter_offset.y);
|
||||
scaler->setOutputTexture(dst_texture);
|
||||
MTLFX::TemporalScaler *s = static_cast<MTLFX::TemporalScaler *>(scaler);
|
||||
MTL3::MDCommandBuffer *cmd = (MTL3::MDCommandBuffer *)(p_command_buffer.id);
|
||||
s->encodeToCommandBuffer(cmd->get_command_buffer());
|
||||
obj->retain_resource(scaler);
|
||||
|
||||
CallbackArgs::free(&p_userdata);
|
||||
|
||||
GODOT_CLANG_WARNING_POP
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -41,32 +41,28 @@
|
||||
#include "core/templates/paged_allocator.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
@protocol MTLFXSpatialScaler;
|
||||
@protocol MTLFXTemporalScaler;
|
||||
#endif
|
||||
namespace MTLFX {
|
||||
class SpatialScalerBase;
|
||||
class TemporalScalerBase;
|
||||
} //namespace MTLFX
|
||||
|
||||
namespace RendererRD {
|
||||
|
||||
struct MFXSpatialContext {
|
||||
#ifdef __OBJC__
|
||||
id<MTLFXSpatialScaler> scaler = nullptr;
|
||||
#else
|
||||
void *scaler = nullptr;
|
||||
#endif
|
||||
MTLFX::SpatialScalerBase *scaler = nullptr;
|
||||
MFXSpatialContext() = default;
|
||||
~MFXSpatialContext();
|
||||
};
|
||||
|
||||
class MFXSpatialEffect : public SpatialUpscaler {
|
||||
struct CallbackArgs {
|
||||
MFXSpatialEffect *owner;
|
||||
MFXSpatialEffect *owner = nullptr;
|
||||
MTLFX::SpatialScalerBase *scaler = nullptr;
|
||||
RDD::TextureID src;
|
||||
RDD::TextureID dst;
|
||||
MFXSpatialContext ctx;
|
||||
|
||||
CallbackArgs(MFXSpatialEffect *p_owner, RDD::TextureID p_src, RDD::TextureID p_dst, MFXSpatialContext p_ctx) :
|
||||
owner(p_owner), src(p_src), dst(p_dst), ctx(p_ctx) {}
|
||||
CallbackArgs(MFXSpatialEffect *p_owner, RDD::TextureID p_src, RDD::TextureID p_dst, const MFXSpatialContext &p_ctx) :
|
||||
owner(p_owner), scaler(p_ctx.scaler), src(p_src), dst(p_dst) {}
|
||||
|
||||
static void free(CallbackArgs **p_args) {
|
||||
(*p_args)->owner->args_allocator.free(*p_args);
|
||||
@@ -98,25 +94,21 @@ public:
|
||||
#ifdef METAL_MFXTEMPORAL_ENABLED
|
||||
|
||||
struct MFXTemporalContext {
|
||||
#ifdef __OBJC__
|
||||
id<MTLFXTemporalScaler> scaler = nullptr;
|
||||
#else
|
||||
void *scaler = nullptr;
|
||||
#endif
|
||||
MTLFX::TemporalScalerBase *scaler = nullptr;
|
||||
MFXTemporalContext() = default;
|
||||
~MFXTemporalContext();
|
||||
};
|
||||
|
||||
class MFXTemporalEffect {
|
||||
struct CallbackArgs {
|
||||
MFXTemporalEffect *owner;
|
||||
MFXTemporalEffect *owner = nullptr;
|
||||
MTLFX::TemporalScalerBase *scaler = nullptr;
|
||||
RDD::TextureID src;
|
||||
RDD::TextureID depth;
|
||||
RDD::TextureID motion;
|
||||
RDD::TextureID exposure;
|
||||
Vector2 jitter_offset;
|
||||
RDD::TextureID dst;
|
||||
MFXTemporalContext ctx;
|
||||
bool reset = false;
|
||||
|
||||
CallbackArgs(
|
||||
@@ -127,16 +119,16 @@ class MFXTemporalEffect {
|
||||
RDD::TextureID p_exposure,
|
||||
Vector2 p_jitter_offset,
|
||||
RDD::TextureID p_dst,
|
||||
MFXTemporalContext p_ctx,
|
||||
const MFXTemporalContext &p_ctx,
|
||||
bool p_reset) :
|
||||
owner(p_owner),
|
||||
scaler(p_ctx.scaler),
|
||||
src(p_src),
|
||||
depth(p_depth),
|
||||
motion(p_motion),
|
||||
exposure(p_exposure),
|
||||
jitter_offset(p_jitter_offset),
|
||||
dst(p_dst),
|
||||
ctx(p_ctx),
|
||||
reset(p_reset) {}
|
||||
|
||||
static void free(CallbackArgs **p_args) {
|
||||
|
||||
Reference in New Issue
Block a user