mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Merge pull request #110264 from stuartcarnie/109846/metal_version
Metal: Ensure baked Metal binaries can be loaded on the minimum target OS
This commit is contained in:
commit
0e8df80231
14 changed files with 250 additions and 44 deletions
|
@ -143,11 +143,15 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MetalDeviceProperties {
|
||||||
private:
|
private:
|
||||||
void init_features(id<MTLDevice> p_device);
|
void init_features(id<MTLDevice> p_device);
|
||||||
void init_limits(id<MTLDevice> p_device);
|
void init_limits(id<MTLDevice> p_device);
|
||||||
|
void init_os_props();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MetalFeatures features;
|
MetalFeatures features;
|
||||||
MetalLimits limits;
|
MetalLimits limits;
|
||||||
|
|
||||||
|
// maj * 10000 + min * 100 + patch
|
||||||
|
uint32_t os_version;
|
||||||
|
|
||||||
SampleCount find_nearest_supported_sample_count(RenderingDevice::TextureSamples p_samples) const;
|
SampleCount find_nearest_supported_sample_count(RenderingDevice::TextureSamples p_samples) const;
|
||||||
|
|
||||||
MetalDeviceProperties(id<MTLDevice> p_device);
|
MetalDeviceProperties(id<MTLDevice> p_device);
|
||||||
|
|
|
@ -311,9 +311,15 @@ void MetalDeviceProperties::init_limits(id<MTLDevice> p_device) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetalDeviceProperties::init_os_props() {
|
||||||
|
NSOperatingSystemVersion ver = NSProcessInfo.processInfo.operatingSystemVersion;
|
||||||
|
os_version = (uint32_t)ver.majorVersion * 10000 + (uint32_t)ver.minorVersion * 100 + (uint32_t)ver.patchVersion;
|
||||||
|
}
|
||||||
|
|
||||||
MetalDeviceProperties::MetalDeviceProperties(id<MTLDevice> p_device) {
|
MetalDeviceProperties::MetalDeviceProperties(id<MTLDevice> p_device) {
|
||||||
init_features(p_device);
|
init_features(p_device);
|
||||||
init_limits(p_device);
|
init_limits(p_device);
|
||||||
|
init_os_props();
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalDeviceProperties::~MetalDeviceProperties() {
|
MetalDeviceProperties::~MetalDeviceProperties() {
|
||||||
|
|
|
@ -103,6 +103,11 @@ extern os_log_t LOG_DRIVER;
|
||||||
// Used for dynamic tracing.
|
// Used for dynamic tracing.
|
||||||
extern os_log_t LOG_INTERVALS;
|
extern os_log_t LOG_INTERVALS;
|
||||||
|
|
||||||
_FORCE_INLINE_ static uint32_t make_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) {
|
_FORCE_INLINE_ static uint32_t make_msl_version(uint32_t p_major, uint32_t p_minor = 0, uint32_t p_patch = 0) {
|
||||||
return (major * 10000) + (minor * 100) + patch;
|
return (p_major * 10000) + (p_minor * 100) + p_patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ static void parse_msl_version(uint32_t p_version, uint32_t &r_major, uint32_t &r_minor) {
|
||||||
|
r_major = p_version / 10000;
|
||||||
|
r_minor = (p_version % 10000) / 100;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1135,12 +1135,17 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_container(const Ref
|
||||||
// We need to regenerate the shader if the cache is moved to an incompatible device.
|
// We need to regenerate the shader if the cache is moved to an incompatible device.
|
||||||
ERR_FAIL_COND_V_MSG(device_properties->features.argument_buffers_tier < MTLArgumentBuffersTier2 && mtl_reflection_data.uses_argument_buffers(),
|
ERR_FAIL_COND_V_MSG(device_properties->features.argument_buffers_tier < MTLArgumentBuffersTier2 && mtl_reflection_data.uses_argument_buffers(),
|
||||||
RDD::ShaderID(),
|
RDD::ShaderID(),
|
||||||
"Shader was generated with argument buffers, but device has limited support");
|
"Shader was compiled with argument buffers enabled, but this device does not support them");
|
||||||
|
|
||||||
uint32_t msl_version = make_msl_version(device_properties->features.mslVersionMajor, device_properties->features.mslVersionMinor);
|
uint32_t msl_version = make_msl_version(device_properties->features.mslVersionMajor, device_properties->features.mslVersionMinor);
|
||||||
ERR_FAIL_COND_V_MSG(msl_version < mtl_reflection_data.msl_version,
|
ERR_FAIL_COND_V_MSG(msl_version < mtl_reflection_data.msl_version,
|
||||||
RDD::ShaderID(),
|
RDD::ShaderID(),
|
||||||
"Shader was compiled with a newer version of Metal than is available on the device.");
|
"Shader was compiled for a newer version of Metal");
|
||||||
|
|
||||||
|
MTLGPUFamily compiled_gpu_family = static_cast<MTLGPUFamily>(mtl_reflection_data.profile.gpu);
|
||||||
|
ERR_FAIL_COND_V_MSG(device_properties->features.highestFamily < compiled_gpu_family,
|
||||||
|
RDD::ShaderID(),
|
||||||
|
"Shader was generated for a newer Apple GPU");
|
||||||
|
|
||||||
MTLCompileOptions *options = [MTLCompileOptions new];
|
MTLCompileOptions *options = [MTLCompileOptions new];
|
||||||
uint32_t major = mtl_reflection_data.msl_version / 10000;
|
uint32_t major = mtl_reflection_data.msl_version / 10000;
|
||||||
|
@ -1181,6 +1186,9 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_container(const Ref
|
||||||
|
|
||||||
MDLibrary *library = nil;
|
MDLibrary *library = nil;
|
||||||
if (shader_data.library_size > 0) {
|
if (shader_data.library_size > 0) {
|
||||||
|
ERR_FAIL_COND_V_MSG(mtl_reflection_data.os_min_version > device_properties->os_version,
|
||||||
|
RDD::ShaderID(),
|
||||||
|
"Metal shader binary was generated for a newer target OS");
|
||||||
dispatch_data_t binary = dispatch_data_create(decompressed_code.ptr() + shader_data.source_size, shader_data.library_size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
dispatch_data_t binary = dispatch_data_create(decompressed_code.ptr() + shader_data.source_size, shader_data.library_size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
||||||
library = [MDLibrary newLibraryWithCacheEntry:cd
|
library = [MDLibrary newLibraryWithCacheEntry:cd
|
||||||
device:device
|
device:device
|
||||||
|
|
|
@ -41,6 +41,25 @@ const uint32_t VIEW_MASK_BUFFER_INDEX = 24;
|
||||||
|
|
||||||
class RenderingShaderContainerFormatMetal;
|
class RenderingShaderContainerFormatMetal;
|
||||||
|
|
||||||
|
class MinOsVersion {
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
public:
|
||||||
|
String to_compiler_os_version() const;
|
||||||
|
bool is_null() const { return version == UINT32_MAX; }
|
||||||
|
bool is_valid() const { return version != UINT32_MAX; }
|
||||||
|
|
||||||
|
MinOsVersion(const String &p_version);
|
||||||
|
explicit MinOsVersion(uint32_t p_version) :
|
||||||
|
version(p_version) {}
|
||||||
|
MinOsVersion() :
|
||||||
|
version(UINT32_MAX) {}
|
||||||
|
|
||||||
|
bool operator>(uint32_t p_other) {
|
||||||
|
return version > p_other;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief A minimal structure that defines a device profile for Metal.
|
/// @brief A minimal structure that defines a device profile for Metal.
|
||||||
///
|
///
|
||||||
/// This structure is used by the `RenderingShaderContainerMetal` class to
|
/// This structure is used by the `RenderingShaderContainerMetal` class to
|
||||||
|
@ -53,17 +72,20 @@ struct MetalDeviceProfile {
|
||||||
iOS = 1,
|
iOS = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief The GPU family.
|
/*! @brief The GPU family.
|
||||||
|
*
|
||||||
|
* NOTE: These values match Apple's MTLGPUFamily
|
||||||
|
*/
|
||||||
enum class GPU : uint32_t {
|
enum class GPU : uint32_t {
|
||||||
Apple1,
|
Apple1 = 1001,
|
||||||
Apple2,
|
Apple2 = 1002,
|
||||||
Apple3,
|
Apple3 = 1003,
|
||||||
Apple4,
|
Apple4 = 1004,
|
||||||
Apple5,
|
Apple5 = 1005,
|
||||||
Apple6,
|
Apple6 = 1006,
|
||||||
Apple7,
|
Apple7 = 1007,
|
||||||
Apple8,
|
Apple8 = 1008,
|
||||||
Apple9,
|
Apple9 = 1009,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ArgumentBuffersTier : uint32_t {
|
enum class ArgumentBuffersTier : uint32_t {
|
||||||
|
@ -108,6 +130,13 @@ public:
|
||||||
/// The Metal language version specified when compiling SPIR-V to MSL.
|
/// The Metal language version specified when compiling SPIR-V to MSL.
|
||||||
/// Format is major * 10000 + minor * 100 + patch.
|
/// Format is major * 10000 + minor * 100 + patch.
|
||||||
uint32_t msl_version = UINT32_MAX;
|
uint32_t msl_version = UINT32_MAX;
|
||||||
|
/*! @brief The minimum supported OS version for shaders baked to a `.metallib`.
|
||||||
|
*
|
||||||
|
* NOTE: This property is only valid when shaders are baked to a .metalllib
|
||||||
|
*
|
||||||
|
* Format is major * 10000 + minor * 100 + patch.
|
||||||
|
*/
|
||||||
|
MinOsVersion os_min_version;
|
||||||
uint32_t flags = NONE;
|
uint32_t flags = NONE;
|
||||||
|
|
||||||
/// @brief Returns `true` if the shader is compiled with multi-view support.
|
/// @brief Returns `true` if the shader is compiled with multi-view support.
|
||||||
|
@ -210,9 +239,23 @@ public:
|
||||||
HeaderData mtl_reflection_data; // compliment to reflection_data
|
HeaderData mtl_reflection_data; // compliment to reflection_data
|
||||||
Vector<StageData> mtl_shaders; // compliment to shaders
|
Vector<StageData> mtl_shaders; // compliment to shaders
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ToolchainProperties {
|
||||||
|
MinOsVersion os_version_min_required;
|
||||||
|
uint32_t metal_version = UINT32_MAX;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool is_null() const { return os_version_min_required.is_null() || metal_version == UINT32_MAX; }
|
||||||
|
_FORCE_INLINE_ bool is_valid() const { return !is_null(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
ToolchainProperties compiler_props;
|
||||||
|
|
||||||
|
void _initialize_toolchain_properties();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const MetalDeviceProfile *device_profile = nullptr;
|
const MetalDeviceProfile *device_profile = nullptr;
|
||||||
bool export_mode = false;
|
bool export_mode = false;
|
||||||
|
MinOsVersion min_os_version;
|
||||||
|
|
||||||
Vector<UniformData> mtl_reflection_binding_set_uniforms_data; // compliment to reflection_binding_set_uniforms_data
|
Vector<UniformData> mtl_reflection_binding_set_uniforms_data; // compliment to reflection_binding_set_uniforms_data
|
||||||
Vector<SpecializationData> mtl_reflection_specialization_data; // compliment to reflection_specialization_data
|
Vector<SpecializationData> mtl_reflection_specialization_data; // compliment to reflection_specialization_data
|
||||||
|
@ -224,6 +267,7 @@ public:
|
||||||
|
|
||||||
void set_export_mode(bool p_export_mode) { export_mode = p_export_mode; }
|
void set_export_mode(bool p_export_mode) { export_mode = p_export_mode; }
|
||||||
void set_device_profile(const MetalDeviceProfile *p_device_profile) { device_profile = p_device_profile; }
|
void set_device_profile(const MetalDeviceProfile *p_device_profile) { device_profile = p_device_profile; }
|
||||||
|
void set_min_os_version(const MinOsVersion p_min_os_version) { min_os_version = p_min_os_version; }
|
||||||
|
|
||||||
struct MetalShaderReflection {
|
struct MetalShaderReflection {
|
||||||
Vector<Vector<UniformData>> uniform_sets;
|
Vector<Vector<UniformData>> uniform_sets;
|
||||||
|
@ -253,6 +297,7 @@ protected:
|
||||||
|
|
||||||
class RenderingShaderContainerFormatMetal : public RenderingShaderContainerFormat {
|
class RenderingShaderContainerFormatMetal : public RenderingShaderContainerFormat {
|
||||||
bool export_mode = false;
|
bool export_mode = false;
|
||||||
|
MinOsVersion min_os_version;
|
||||||
|
|
||||||
const MetalDeviceProfile *device_profile = nullptr;
|
const MetalDeviceProfile *device_profile = nullptr;
|
||||||
|
|
||||||
|
@ -260,6 +305,6 @@ public:
|
||||||
virtual Ref<RenderingShaderContainer> create_container() const override;
|
virtual Ref<RenderingShaderContainer> create_container() const override;
|
||||||
virtual ShaderLanguageVersion get_shader_language_version() const override;
|
virtual ShaderLanguageVersion get_shader_language_version() const override;
|
||||||
virtual ShaderSpirvVersion get_shader_spirv_version() const override;
|
virtual ShaderSpirvVersion get_shader_spirv_version() const override;
|
||||||
RenderingShaderContainerFormatMetal(const MetalDeviceProfile *p_device_profile, bool p_export = false);
|
RenderingShaderContainerFormatMetal(const MetalDeviceProfile *p_device_profile, bool p_export = false, const MinOsVersion p_min_os_version = MinOsVersion());
|
||||||
virtual ~RenderingShaderContainerFormatMetal() = default;
|
virtual ~RenderingShaderContainerFormatMetal() = default;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,11 +28,12 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#include "rendering_shader_container_metal.h"
|
#import "rendering_shader_container_metal.h"
|
||||||
|
|
||||||
#include "servers/rendering/rendering_device.h"
|
#import "metal_utils.h"
|
||||||
|
|
||||||
#import "core/io/marshalls.h"
|
#import "core/io/marshalls.h"
|
||||||
|
#import "servers/rendering/rendering_device.h"
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
#import <spirv.hpp>
|
#import <spirv.hpp>
|
||||||
|
@ -85,6 +86,71 @@ const MetalDeviceProfile *MetalDeviceProfile::get_profile(MetalDeviceProfile::Pl
|
||||||
return &profiles.insert(key, res)->value;
|
return &profiles.insert(key, res)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingShaderContainerMetal::_initialize_toolchain_properties() {
|
||||||
|
if (compiler_props.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sdk;
|
||||||
|
switch (device_profile->platform) {
|
||||||
|
case MetalDeviceProfile::Platform::macOS:
|
||||||
|
sdk = "macosx";
|
||||||
|
break;
|
||||||
|
case MetalDeviceProfile::Platform::iOS:
|
||||||
|
sdk = "iphoneos";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<String> parts{ "echo", R"("")", "|", "/usr/bin/xcrun", "-sdk", sdk, "metal", "-E", "-dM", "-x", "metal", "-", "|", "grep", "-E", R"(\"__METAL_VERSION__|__ENVIRONMENT_OS\")" };
|
||||||
|
|
||||||
|
// Compile metal shaders for the minimum supported target instead of the host machine
|
||||||
|
if (min_os_version.is_valid()) {
|
||||||
|
switch (device_profile->platform) {
|
||||||
|
case MetalDeviceProfile::Platform::macOS: {
|
||||||
|
parts.push_back("-mmacosx-version-min=" + min_os_version.to_compiler_os_version());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MetalDeviceProfile::Platform::iOS: {
|
||||||
|
parts.push_back("-mios-version-min=" + min_os_version.to_compiler_os_version());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = " ";
|
||||||
|
List<String> args = { "-c", String(" ").join(parts) };
|
||||||
|
|
||||||
|
String r_pipe;
|
||||||
|
int exit_code;
|
||||||
|
Error err = OS::get_singleton()->execute("sh", args, &r_pipe, &exit_code, true);
|
||||||
|
ERR_FAIL_COND_MSG(err != OK, "Failed to determine Metal toolchain properties");
|
||||||
|
|
||||||
|
// Parse the lines, which are in the form:
|
||||||
|
//
|
||||||
|
// #define VARNAME VALUE
|
||||||
|
Vector<String> lines = r_pipe.split("\n", false);
|
||||||
|
for (String &line : lines) {
|
||||||
|
Vector<String> name_val = line.trim_prefix("#define ").split(" ");
|
||||||
|
if (name_val.size() != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name_val[0] == "__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__") {
|
||||||
|
compiler_props.os_version_min_required = MinOsVersion((uint32_t)name_val[1].to_int());
|
||||||
|
} else if (name_val[0] == "__METAL_VERSION__") {
|
||||||
|
uint32_t ver = (uint32_t)name_val[1].to_int();
|
||||||
|
uint32_t maj = ver / 100;
|
||||||
|
uint32_t min = (ver % 100) / 10;
|
||||||
|
compiler_props.metal_version = make_msl_version(maj, min);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_props.is_valid()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Error RenderingShaderContainerMetal::compile_metal_source(const char *p_source, const StageData &p_stage_data, Vector<uint8_t> &r_binary_data) {
|
Error RenderingShaderContainerMetal::compile_metal_source(const char *p_source, const StageData &p_stage_data, Vector<uint8_t> &r_binary_data) {
|
||||||
String name(shader_name.ptr());
|
String name(shader_name.ptr());
|
||||||
if (name.contains_char(':')) {
|
if (name.contains_char(':')) {
|
||||||
|
@ -115,9 +181,26 @@ Error RenderingShaderContainerMetal::compile_metal_source(const char *p_source,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the metallib binary.
|
// Build the .metallib binary.
|
||||||
{
|
{
|
||||||
List<String> args{ "-sdk", sdk, "metal", "-O3" };
|
List<String> args{ "-sdk", sdk, "metal", "-O3" };
|
||||||
|
|
||||||
|
// Compile metal shaders for the minimum supported target instead of the host machine.
|
||||||
|
if (min_os_version.is_valid()) {
|
||||||
|
switch (device_profile->platform) {
|
||||||
|
case MetalDeviceProfile::Platform::macOS: {
|
||||||
|
args.push_back("-mmacosx-version-min=" + min_os_version.to_compiler_os_version());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MetalDeviceProfile::Platform::iOS: {
|
||||||
|
args.push_back("-mios-version-min=" + min_os_version.to_compiler_os_version());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARN_PRINT_ONCE(vformat("Minimum target OS version is not set, so baking shaders for Metal will target the default version of your toolchain: %s", compiler_props.os_version_min_required.to_compiler_os_version()));
|
||||||
|
}
|
||||||
|
|
||||||
if (p_stage_data.is_position_invariant) {
|
if (p_stage_data.is_position_invariant) {
|
||||||
args.push_back("-fpreserve-invariance");
|
args.push_back("-fpreserve-invariance");
|
||||||
}
|
}
|
||||||
|
@ -175,6 +258,10 @@ bool RenderingShaderContainerMetal::_set_code_from_spirv(const Vector<RenderingD
|
||||||
using spirv_cross::CompilerMSL;
|
using spirv_cross::CompilerMSL;
|
||||||
using spirv_cross::Resource;
|
using spirv_cross::Resource;
|
||||||
|
|
||||||
|
if (export_mode) {
|
||||||
|
_initialize_toolchain_properties();
|
||||||
|
}
|
||||||
|
|
||||||
// initialize Metal-specific reflection data
|
// initialize Metal-specific reflection data
|
||||||
shaders.resize(p_spirv.size());
|
shaders.resize(p_spirv.size());
|
||||||
mtl_shaders.resize(p_spirv.size());
|
mtl_shaders.resize(p_spirv.size());
|
||||||
|
@ -182,6 +269,7 @@ bool RenderingShaderContainerMetal::_set_code_from_spirv(const Vector<RenderingD
|
||||||
mtl_reflection_specialization_data.resize(reflection_specialization_data.size());
|
mtl_reflection_specialization_data.resize(reflection_specialization_data.size());
|
||||||
|
|
||||||
mtl_reflection_data.set_needs_view_mask_buffer(reflection_data.has_multiview);
|
mtl_reflection_data.set_needs_view_mask_buffer(reflection_data.has_multiview);
|
||||||
|
mtl_reflection_data.profile = *device_profile;
|
||||||
|
|
||||||
// set_indexes will contain the starting offsets of each descriptor set in the binding set uniforms data
|
// set_indexes will contain the starting offsets of each descriptor set in the binding set uniforms data
|
||||||
// including the last one, which is the size of reflection_binding_set_uniforms_count.
|
// including the last one, which is the size of reflection_binding_set_uniforms_count.
|
||||||
|
@ -199,10 +287,25 @@ bool RenderingShaderContainerMetal::_set_code_from_spirv(const Vector<RenderingD
|
||||||
set_indexes[set_indexes_size - 1] = offset;
|
set_indexes[set_indexes_size - 1] = offset;
|
||||||
}
|
}
|
||||||
CompilerMSL::Options msl_options{};
|
CompilerMSL::Options msl_options{};
|
||||||
// MAJOR * 10000 + MINOR * 100
|
|
||||||
uint32_t msl_version = CompilerMSL::Options::make_msl_version(device_profile->features.mslVersionMajor, device_profile->features.mslVersionMinor);
|
// Determine Metal language version.
|
||||||
msl_options.set_msl_version(device_profile->features.mslVersionMajor, device_profile->features.mslVersionMinor);
|
uint32_t msl_version = 0;
|
||||||
mtl_reflection_data.msl_version = msl_options.msl_version;
|
{
|
||||||
|
if (export_mode && compiler_props.is_valid()) {
|
||||||
|
// Use the properties determined by the toolchain and minimum OS version.
|
||||||
|
msl_version = compiler_props.metal_version;
|
||||||
|
mtl_reflection_data.os_min_version = compiler_props.os_version_min_required;
|
||||||
|
} else {
|
||||||
|
msl_version = make_msl_version(device_profile->features.mslVersionMajor, device_profile->features.mslVersionMinor);
|
||||||
|
mtl_reflection_data.os_min_version = MinOsVersion();
|
||||||
|
}
|
||||||
|
uint32_t msl_ver_maj = 0;
|
||||||
|
uint32_t msl_ver_min = 0;
|
||||||
|
parse_msl_version(msl_version, msl_ver_maj, msl_ver_min);
|
||||||
|
msl_options.set_msl_version(msl_ver_maj, msl_ver_min);
|
||||||
|
mtl_reflection_data.msl_version = msl_version;
|
||||||
|
}
|
||||||
|
|
||||||
msl_options.platform = device_profile->platform == MetalDeviceProfile::Platform::macOS ? CompilerMSL::Options::macOS : CompilerMSL::Options::iOS;
|
msl_options.platform = device_profile->platform == MetalDeviceProfile::Platform::macOS ? CompilerMSL::Options::macOS : CompilerMSL::Options::iOS;
|
||||||
|
|
||||||
if (device_profile->platform == MetalDeviceProfile::Platform::iOS) {
|
if (device_profile->platform == MetalDeviceProfile::Platform::iOS) {
|
||||||
|
@ -238,7 +341,7 @@ bool RenderingShaderContainerMetal::_set_code_from_spirv(const Vector<RenderingD
|
||||||
msl_options.multiview_layered_rendering = true;
|
msl_options.multiview_layered_rendering = true;
|
||||||
msl_options.view_mask_buffer_index = VIEW_MASK_BUFFER_INDEX;
|
msl_options.view_mask_buffer_index = VIEW_MASK_BUFFER_INDEX;
|
||||||
}
|
}
|
||||||
if (msl_version >= CompilerMSL::Options::make_msl_version(3, 2)) {
|
if (msl_version >= make_msl_version(3, 2)) {
|
||||||
// All 3.2+ versions support device coherence, so we can disable texture fences.
|
// All 3.2+ versions support device coherence, so we can disable texture fences.
|
||||||
msl_options.readwrite_texture_fences = false;
|
msl_options.readwrite_texture_fences = false;
|
||||||
}
|
}
|
||||||
|
@ -571,13 +674,19 @@ bool RenderingShaderContainerMetal::_set_code_from_spirv(const Vector<RenderingD
|
||||||
memcpy(binary_data.ptrw(), source.c_str(), stage_data.source_size);
|
memcpy(binary_data.ptrw(), source.c_str(), stage_data.source_size);
|
||||||
|
|
||||||
if (export_mode) {
|
if (export_mode) {
|
||||||
// Try to compile the Metal source code
|
if (compiler_props.is_valid()) {
|
||||||
::Vector<uint8_t> library_data;
|
// Try to compile the Metal source code.
|
||||||
Error compile_err = compile_metal_source(source.c_str(), stage_data, library_data);
|
::Vector<uint8_t> library_data;
|
||||||
if (compile_err == OK) {
|
Error compile_err = compile_metal_source(source.c_str(), stage_data, library_data);
|
||||||
stage_data.library_size = library_data.size();
|
if (compile_err == OK) {
|
||||||
binary_data.resize(stage_data.source_size + stage_data.library_size);
|
// If we successfully compiled to a `.metallib`, there are greater restrictions on target platforms,
|
||||||
memcpy(binary_data.ptrw() + stage_data.source_size, library_data.ptr(), stage_data.library_size);
|
// so we must update the properties.
|
||||||
|
stage_data.library_size = library_data.size();
|
||||||
|
binary_data.resize(stage_data.source_size + stage_data.library_size);
|
||||||
|
memcpy(binary_data.ptrw() + stage_data.source_size, library_data.ptr(), stage_data.library_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARN_PRINT_ONCE("Metal shader baking limited to SPIR-V: Unable to determine toolchain properties to compile .metallib");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,6 +802,7 @@ Ref<RenderingShaderContainer> RenderingShaderContainerFormatMetal::create_contai
|
||||||
result.instantiate();
|
result.instantiate();
|
||||||
result->set_export_mode(export_mode);
|
result->set_export_mode(export_mode);
|
||||||
result->set_device_profile(device_profile);
|
result->set_device_profile(device_profile);
|
||||||
|
result->set_min_os_version(min_os_version);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,6 +814,30 @@ RenderingDeviceCommons::ShaderSpirvVersion RenderingShaderContainerFormatMetal::
|
||||||
return SHADER_SPIRV_VERSION_1_6;
|
return SHADER_SPIRV_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderingShaderContainerFormatMetal::RenderingShaderContainerFormatMetal(const MetalDeviceProfile *p_device_profile, bool p_export) :
|
RenderingShaderContainerFormatMetal::RenderingShaderContainerFormatMetal(const MetalDeviceProfile *p_device_profile, bool p_export, const MinOsVersion p_min_os_version) :
|
||||||
export_mode(p_export), device_profile(p_device_profile) {
|
export_mode(p_export), min_os_version(p_min_os_version), device_profile(p_device_profile) {
|
||||||
|
}
|
||||||
|
|
||||||
|
String MinOsVersion::to_compiler_os_version() const {
|
||||||
|
if (version == UINT32_MAX) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t major = version / 10000;
|
||||||
|
uint32_t minor = (version % 10000) / 100;
|
||||||
|
return vformat("%d.%d", major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
MinOsVersion::MinOsVersion(const String &p_version) {
|
||||||
|
int pos = p_version.find_char('.');
|
||||||
|
if (pos > 0) {
|
||||||
|
version = (uint32_t)(p_version.substr(0, pos).to_int() * 10000 +
|
||||||
|
p_version.substr(pos + 1).to_int() * 100);
|
||||||
|
} else {
|
||||||
|
version = (uint32_t)(p_version.to_int() * 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version == 0) {
|
||||||
|
version = UINT32_MAX;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ bool ShaderBakerExportPlugin::_is_active(const Vector<String> &p_features) const
|
||||||
return RendererSceneRenderRD::get_singleton() != nullptr && RendererRD::MaterialStorage::get_singleton() != nullptr && p_features.has("shader_baker");
|
return RendererSceneRenderRD::get_singleton() != nullptr && RendererRD::MaterialStorage::get_singleton() != nullptr && p_features.has("shader_baker");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderBakerExportPlugin::_initialize_container_format(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) {
|
bool ShaderBakerExportPlugin::_initialize_container_format(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features, const Ref<EditorExportPreset> &p_preset) {
|
||||||
Variant driver_variant = GLOBAL_GET("rendering/rendering_device/driver." + p_platform->get_os_name().to_lower());
|
Variant driver_variant = GLOBAL_GET("rendering/rendering_device/driver." + p_platform->get_os_name().to_lower());
|
||||||
if (!driver_variant.is_string()) {
|
if (!driver_variant.is_string()) {
|
||||||
driver_variant = GLOBAL_GET("rendering/rendering_device/driver");
|
driver_variant = GLOBAL_GET("rendering/rendering_device/driver");
|
||||||
|
@ -67,7 +67,7 @@ bool ShaderBakerExportPlugin::_initialize_container_format(const Ref<EditorExpor
|
||||||
|
|
||||||
for (Ref<ShaderBakerExportPluginPlatform> platform : platforms) {
|
for (Ref<ShaderBakerExportPluginPlatform> platform : platforms) {
|
||||||
if (platform->matches_driver(shader_container_driver)) {
|
if (platform->matches_driver(shader_container_driver)) {
|
||||||
shader_container_format = platform->create_shader_container_format(p_platform);
|
shader_container_format = platform->create_shader_container_format(p_platform, get_export_preset());
|
||||||
ERR_FAIL_NULL_V_MSG(shader_container_format, false, "Unable to create shader container format for the export platform.");
|
ERR_FAIL_NULL_V_MSG(shader_container_format, false, "Unable to create shader container format for the export platform.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ bool ShaderBakerExportPlugin::_begin_customize_resources(const Ref<EditorExportP
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_initialize_container_format(p_platform, p_features)) {
|
if (!_initialize_container_format(p_platform, p_features, get_export_preset())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ShaderBakerExportPluginPlatform : public RefCounted {
|
||||||
GDCLASS(ShaderBakerExportPluginPlatform, RefCounted);
|
GDCLASS(ShaderBakerExportPluginPlatform, RefCounted);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) = 0;
|
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) = 0;
|
||||||
virtual bool matches_driver(const String &p_driver) = 0;
|
virtual bool matches_driver(const String &p_driver) = 0;
|
||||||
virtual ~ShaderBakerExportPluginPlatform() {}
|
virtual ~ShaderBakerExportPluginPlatform() {}
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,7 @@ protected:
|
||||||
|
|
||||||
virtual String get_name() const override;
|
virtual String get_name() const override;
|
||||||
virtual bool _is_active(const Vector<String> &p_features) const;
|
virtual bool _is_active(const Vector<String> &p_features) const;
|
||||||
virtual bool _initialize_container_format(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features);
|
virtual bool _initialize_container_format(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features, const Ref<EditorExportPreset> &p_preset);
|
||||||
virtual void _cleanup_container_format();
|
virtual void _cleanup_container_format();
|
||||||
virtual bool _initialize_cache_directory();
|
virtual bool _initialize_cache_directory();
|
||||||
virtual bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) override;
|
virtual bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) override;
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformD3D12::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) {
|
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformD3D12::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) {
|
||||||
if (lib_d3d12 == nullptr) {
|
if (lib_d3d12 == nullptr) {
|
||||||
lib_d3d12 = LoadLibraryW(L"D3D12.dll");
|
lib_d3d12 = LoadLibraryW(L"D3D12.dll");
|
||||||
ERR_FAIL_NULL_V_MSG(lib_d3d12, nullptr, "Unable to load D3D12.dll.");
|
ERR_FAIL_NULL_V_MSG(lib_d3d12, nullptr, "Unable to load D3D12.dll.");
|
||||||
|
|
|
@ -39,7 +39,7 @@ private:
|
||||||
void *lib_d3d12 = nullptr;
|
void *lib_d3d12 = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) override;
|
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) override;
|
||||||
virtual bool matches_driver(const String &p_driver) override;
|
virtual bool matches_driver(const String &p_driver) override;
|
||||||
virtual ~ShaderBakerExportPluginPlatformD3D12() override;
|
virtual ~ShaderBakerExportPluginPlatformD3D12() override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,18 +32,22 @@
|
||||||
|
|
||||||
#include "drivers/metal/rendering_shader_container_metal.h"
|
#include "drivers/metal/rendering_shader_container_metal.h"
|
||||||
|
|
||||||
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformMetal::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) {
|
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformMetal::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) {
|
||||||
const String &os_name = p_platform->get_os_name();
|
const String &os_name = p_platform->get_os_name();
|
||||||
const MetalDeviceProfile *profile;
|
const MetalDeviceProfile *profile;
|
||||||
|
String min_os_version;
|
||||||
|
|
||||||
if (os_name == U"macOS") {
|
if (os_name == U"macOS") {
|
||||||
profile = MetalDeviceProfile::get_profile(MetalDeviceProfile::Platform::macOS, MetalDeviceProfile::GPU::Apple7);
|
profile = MetalDeviceProfile::get_profile(MetalDeviceProfile::Platform::macOS, MetalDeviceProfile::GPU::Apple7);
|
||||||
|
// Godot metal doesn't support x86_64 mac so no need to worry about that version
|
||||||
|
min_os_version = p_preset->get("application/min_macos_version_arm64");
|
||||||
} else if (os_name == U"iOS") {
|
} else if (os_name == U"iOS") {
|
||||||
profile = MetalDeviceProfile::get_profile(MetalDeviceProfile::Platform::iOS, MetalDeviceProfile::GPU::Apple7);
|
profile = MetalDeviceProfile::get_profile(MetalDeviceProfile::Platform::iOS, MetalDeviceProfile::GPU::Apple7);
|
||||||
|
min_os_version = p_preset->get("application/min_ios_version");
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_V_MSG(nullptr, vformat("Unsupported platform: %s", os_name));
|
ERR_FAIL_V_MSG(nullptr, vformat("Unsupported platform: %s", os_name));
|
||||||
}
|
}
|
||||||
return memnew(RenderingShaderContainerFormatMetal(profile, true));
|
return memnew(RenderingShaderContainerFormatMetal(profile, true, min_os_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderBakerExportPluginPlatformMetal::matches_driver(const String &p_driver) {
|
bool ShaderBakerExportPluginPlatformMetal::matches_driver(const String &p_driver) {
|
||||||
|
|
|
@ -34,6 +34,6 @@
|
||||||
|
|
||||||
class ShaderBakerExportPluginPlatformMetal : public ShaderBakerExportPluginPlatform {
|
class ShaderBakerExportPluginPlatformMetal : public ShaderBakerExportPluginPlatform {
|
||||||
public:
|
public:
|
||||||
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) override;
|
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) override;
|
||||||
virtual bool matches_driver(const String &p_driver) override;
|
virtual bool matches_driver(const String &p_driver) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
#include "drivers/vulkan/rendering_shader_container_vulkan.h"
|
#include "drivers/vulkan/rendering_shader_container_vulkan.h"
|
||||||
|
|
||||||
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformVulkan::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) {
|
RenderingShaderContainerFormat *ShaderBakerExportPluginPlatformVulkan::create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) {
|
||||||
return memnew(RenderingShaderContainerFormatVulkan);
|
return memnew(RenderingShaderContainerFormatVulkan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,6 @@ class ShaderBakerExportPluginPlatformVulkan : public ShaderBakerExportPluginPlat
|
||||||
GDCLASS(ShaderBakerExportPluginPlatformVulkan, ShaderBakerExportPluginPlatform);
|
GDCLASS(ShaderBakerExportPluginPlatformVulkan, ShaderBakerExportPluginPlatform);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform) override;
|
virtual RenderingShaderContainerFormat *create_shader_container_format(const Ref<EditorExportPlatform> &p_platform, const Ref<EditorExportPreset> &p_preset) override;
|
||||||
virtual bool matches_driver(const String &p_driver) override;
|
virtual bool matches_driver(const String &p_driver) override;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue