Skip to content

Commit

Permalink
Add Metal support for macOS (arm64) and iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartcarnie authored and akien-mga committed Aug 20, 2024
1 parent 826de79 commit 2d01655
Show file tree
Hide file tree
Showing 72 changed files with 67,923 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .github/actions/godot-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ inputs:
tests:
description: Unit tests.
default: false
required: false
platform:
description: Target platform.
required: false
sconsflags:
description: Additional SCons flags.
default: ""
required: false
scons-cache:
description: The SCons cache path.
default: "${{ github.workspace }}/.scons-cache/"
Expand Down
5 changes: 5 additions & 0 deletions COPYRIGHT.txt
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,11 @@ Comment: RVO2
Copyright: 2016, University of North Carolina at Chapel Hill
License: Apache-2.0

Files: ./thirdparty/spirv-cross/
Comment: SPIRV-Cross
Copyright: 2015-2021, Arm Limited
License: Apache-2.0 or Expat

Files: ./thirdparty/spirv-reflect/
Comment: SPIRV-Reflect
Copyright: 2017-2022, Google Inc.
Expand Down
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver", False))
opts.Add(BoolVariable("metal", "Enable the Metal rendering driver (Apple arm64 only)", False))
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ void OS::_bind_methods() {
BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
BIND_ENUM_CONSTANT(RENDERING_DRIVER_D3D12);
BIND_ENUM_CONSTANT(RENDERING_DRIVER_METAL);

BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP);
BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM);
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class OS : public Object {
RENDERING_DRIVER_VULKAN,
RENDERING_DRIVER_OPENGL3,
RENDERING_DRIVER_D3D12,
RENDERING_DRIVER_METAL,
};

PackedByteArray get_entropy(int p_bytes);
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,9 @@
<constant name="RENDERING_DRIVER_D3D12" value="2" enum="RenderingDriver">
The Direct3D 12 rendering driver.
</constant>
<constant name="RENDERING_DRIVER_METAL" value="3" enum="RenderingDriver">
The Metal rendering driver.
</constant>
<constant name="SYSTEM_DIR_DESKTOP" value="0" enum="SystemDir">
Refers to the Desktop directory path.
</constant>
Expand Down
2 changes: 2 additions & 0 deletions drivers/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ if env["opengl3"]:
SConscript("gl_context/SCsub")
SConscript("gles3/SCsub")
SConscript("egl/SCsub")
if env["metal"]:
SConscript("metal/SCsub")

# Core dependencies
SConscript("png/SCsub")
Expand Down
39 changes: 39 additions & 0 deletions drivers/metal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Metal Rendering Device

This document aims to describe the Metal rendering device implementation in Godot.

## Future work / ideas

* Use placement heaps
* Explicit hazard tracking
* [MetalFX] upscaling support?

## Acknowledgments

The Metal rendering owes a lot to the work of the [MoltenVK] project, which is a Vulkan implementation on top of Metal.
In accordance with the Apache 2.0 license, the following copyright notices have been included where applicable:

```
/**************************************************************************/
/* */
/* Portions of this code were derived from MoltenVK. */
/* */
/* Copyright (c) 2015-2023 The Brenwill Workshop Ltd. */
/* (http://www.brenwill.com) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
/* implied. See the License for the specific language governing */
/* permissions and limitations under the License. */
/**************************************************************************/
```

[MoltenVK]: https://github.com/KhronosGroup/MoltenVK
[MetalFX]: https://developer.apple.com/documentation/metalfx?language=objc
49 changes: 49 additions & 0 deletions drivers/metal/SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python

Import("env")

env_metal = env.Clone()

# Thirdparty source files

thirdparty_obj = []

thirdparty_dir = "#thirdparty/spirv-cross/"
thirdparty_sources = [
"spirv_cfg.cpp",
"spirv_cross_util.cpp",
"spirv_cross.cpp",
"spirv_parser.cpp",
"spirv_msl.cpp",
"spirv_reflect.cpp",
"spirv_glsl.cpp",
"spirv_cross_parsed_ir.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]

env_metal.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include"])

# Must enable exceptions for SPIRV-Cross; otherwise, it will abort the process on errors.
if "-fno-exceptions" in env_metal["CXXFLAGS"]:
env_metal["CXXFLAGS"].remove("-fno-exceptions")
env_metal.Append(CXXFLAGS=["-fexceptions"])

env_thirdparty = env_metal.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env_metal.drivers_sources += thirdparty_obj

# Enable C++20 for the Objective-C++ Metal code, which uses C++20 concepts.
if "-std=gnu++17" in env_metal["CXXFLAGS"]:
env_metal["CXXFLAGS"].remove("-std=gnu++17")
env_metal.Append(CXXFLAGS=["-std=c++20"])

# Driver source files

driver_obj = []

env_metal.add_source_files(driver_obj, "*.mm")
env.drivers_sources += driver_obj

# Needed to force rebuilding the driver files when the thirdparty library is updated.
env.Depends(driver_obj, thirdparty_obj)
141 changes: 141 additions & 0 deletions drivers/metal/metal_device_properties.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**************************************************************************/
/* metal_device_properties.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. */
/**************************************************************************/

/**************************************************************************/
/* */
/* Portions of this code were derived from MoltenVK. */
/* */
/* Copyright (c) 2015-2023 The Brenwill Workshop Ltd. */
/* (http://www.brenwill.com) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
/* implied. See the License for the specific language governing */
/* permissions and limitations under the License. */
/**************************************************************************/

#ifndef METAL_DEVICE_PROPERTIES_H
#define METAL_DEVICE_PROPERTIES_H

#import "servers/rendering/rendering_device.h"

#import <Foundation/Foundation.h>
#import <Metal/Metal.h>

/** The buffer index to use for vertex content. */
const static uint32_t VERT_CONTENT_BUFFER_INDEX = 0;
const static uint32_t MAX_COLOR_ATTACHMENT_COUNT = 8;

typedef NS_OPTIONS(NSUInteger, SampleCount) {
SampleCount1 = (1UL << 0),
SampleCount2 = (1UL << 1),
SampleCount4 = (1UL << 2),
SampleCount8 = (1UL << 3),
SampleCount16 = (1UL << 4),
SampleCount32 = (1UL << 5),
SampleCount64 = (1UL << 6),
};

struct API_AVAILABLE(macos(11.0), ios(14.0)) MetalFeatures {
uint32_t mslVersion;
MTLGPUFamily highestFamily;
MTLLanguageVersion mslVersionEnum;
SampleCount supportedSampleCounts;
long hostMemoryPageSize;
bool layeredRendering;
bool multisampleLayeredRendering;
bool quadPermute; /**< If true, quadgroup permutation functions (vote, ballot, shuffle) are supported in shaders. */
bool simdPermute; /**< If true, SIMD-group permutation functions (vote, ballot, shuffle) are supported in shaders. */
bool simdReduction; /**< If true, SIMD-group reduction functions (arithmetic) are supported in shaders. */
bool tessellationShader; /**< If true, tessellation shaders are supported. */
bool imageCubeArray; /**< If true, image cube arrays are supported. */
};

struct MetalLimits {
uint64_t maxImageArrayLayers;
uint64_t maxFramebufferHeight;
uint64_t maxFramebufferWidth;
uint64_t maxImageDimension1D;
uint64_t maxImageDimension2D;
uint64_t maxImageDimension3D;
uint64_t maxImageDimensionCube;
uint64_t maxViewportDimensionX;
uint64_t maxViewportDimensionY;
MTLSize maxThreadsPerThreadGroup;
MTLSize maxComputeWorkGroupCount;
uint64_t maxBoundDescriptorSets;
uint64_t maxColorAttachments;
uint64_t maxTexturesPerArgumentBuffer;
uint64_t maxSamplersPerArgumentBuffer;
uint64_t maxBuffersPerArgumentBuffer;
uint64_t maxBufferLength;
uint64_t minUniformBufferOffsetAlignment;
uint64_t maxVertexDescriptorLayoutStride;
uint16_t maxViewports;
uint32_t maxPerStageBufferCount; /**< The total number of per-stage Metal buffers available for shader uniform content and attributes. */
uint32_t maxPerStageTextureCount; /**< The total number of per-stage Metal textures available for shader uniform content. */
uint32_t maxPerStageSamplerCount; /**< The total number of per-stage Metal samplers available for shader uniform content. */
uint32_t maxVertexInputAttributes;
uint32_t maxVertexInputBindings;
uint32_t maxVertexInputBindingStride;
uint32_t maxDrawIndexedIndexValue;

uint32_t minSubgroupSize; /**< The minimum number of threads in a SIMD-group. */
uint32_t maxSubgroupSize; /**< The maximum number of threads in a SIMD-group. */
BitField<RDD::ShaderStage> subgroupSupportedShaderStages;
BitField<RD::SubgroupOperations> subgroupSupportedOperations; /**< The subgroup operations supported by the device. */
};

class API_AVAILABLE(macos(11.0), ios(14.0)) MetalDeviceProperties {
private:
void init_features(id<MTLDevice> p_device);
void init_limits(id<MTLDevice> p_device);

public:
MetalFeatures features;
MetalLimits limits;

SampleCount find_nearest_supported_sample_count(RenderingDevice::TextureSamples p_samples) const;

MetalDeviceProperties(id<MTLDevice> p_device);
~MetalDeviceProperties();

private:
static const SampleCount sample_count[RenderingDevice::TextureSamples::TEXTURE_SAMPLES_MAX];
};

#endif // METAL_DEVICE_PROPERTIES_H
Loading

0 comments on commit 2d01655

Please sign in to comment.