Path: blob/master/drivers/metal/rendering_shader_container_metal.h
9973 views
/**************************************************************************/1/* rendering_shader_container_metal.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#import "sha256_digest.h"3334#import "servers/rendering/rendering_device_driver.h"35#import "servers/rendering/rendering_shader_container.h"3637constexpr uint32_t R32UI_ALIGNMENT_CONSTANT_ID = 65535;38/// Metal buffer index for the view mask when rendering multi-view.39const uint32_t VIEW_MASK_BUFFER_INDEX = 24;4041class RenderingShaderContainerFormatMetal;4243/// @brief A minimal structure that defines a device profile for Metal.44///45/// This structure is used by the `RenderingShaderContainerMetal` class to46/// determine options for compiling SPIR-V to Metal source. It currently only47/// contains the minimum properties required to transform shaders from SPIR-V to Metal48/// and potentially compile to a `.metallib`.49struct MetalDeviceProfile {50enum class Platform : uint32_t {51macOS = 0,52iOS = 1,53};5455/// @brief The GPU family.56enum class GPU : uint32_t {57Apple1,58Apple2,59Apple3,60Apple4,61Apple5,62Apple6,63Apple7,64Apple8,65Apple9,66};6768enum class ArgumentBuffersTier : uint32_t {69Tier1 = 0,70Tier2 = 1,71};7273struct Features {74uint32_t mslVersionMajor = 0;75uint32_t mslVersionMinor = 0;76ArgumentBuffersTier argument_buffers_tier = ArgumentBuffersTier::Tier1;77bool simdPermute = false;78};7980Platform platform = Platform::macOS;81GPU gpu = GPU::Apple4;82Features features;8384static const MetalDeviceProfile *get_profile(Platform p_platform, GPU p_gpu);8586MetalDeviceProfile() = default;8788private:89static Mutex profiles_lock; ///< Mutex to protect access to the profiles map.90static HashMap<uint32_t, MetalDeviceProfile> profiles;91};9293class RenderingShaderContainerMetal : public RenderingShaderContainer {94GDSOFTCLASS(RenderingShaderContainerMetal, RenderingShaderContainer);9596public:97struct HeaderData {98enum Flags : uint32_t {99NONE = 0,100NEEDS_VIEW_MASK_BUFFER = 1 << 0,101USES_ARGUMENT_BUFFERS = 1 << 1,102};103104/// The base profile that was used to generate this shader.105MetalDeviceProfile profile;106107/// The Metal language version specified when compiling SPIR-V to MSL.108/// Format is major * 10000 + minor * 100 + patch.109uint32_t msl_version = UINT32_MAX;110uint32_t flags = NONE;111112/// @brief Returns `true` if the shader is compiled with multi-view support.113bool needs_view_mask_buffer() const {114return flags & NEEDS_VIEW_MASK_BUFFER;115}116117void set_needs_view_mask_buffer(bool p_value) {118if (p_value) {119flags |= NEEDS_VIEW_MASK_BUFFER;120} else {121flags &= ~NEEDS_VIEW_MASK_BUFFER;122}123}124125/// @brief Returns `true` if the shader was compiled with argument buffer support.126bool uses_argument_buffers() const {127return flags & USES_ARGUMENT_BUFFERS;128}129130void set_uses_argument_buffers(bool p_value) {131if (p_value) {132flags |= USES_ARGUMENT_BUFFERS;133} else {134flags &= ~USES_ARGUMENT_BUFFERS;135}136}137};138139struct StageData {140uint32_t vertex_input_binding_mask = 0;141uint32_t is_position_invariant = 0; ///< <c>true</c> if the position output is invariant142uint32_t supports_fast_math = 0;143SHA256Digest hash; ///< SHA 256 hash of the shader code144uint32_t source_size = 0; ///< size of the source code in the returned bytes145uint32_t library_size = 0; ///< size of the compiled library in the returned bytes, 0 if it is not compiled146uint32_t push_constant_binding = UINT32_MAX; ///< Metal binding slot for the push constant data147};148149struct BindingInfoData {150uint32_t shader_stage = UINT32_MAX; ///< The shader stage this binding is used in, or UINT32_MAX if not used.151uint32_t data_type = 0; // MTLDataTypeNone152uint32_t index = 0;153uint32_t access = 0; // MTLBindingAccessReadOnly154uint32_t usage = 0; // MTLResourceUsage (none)155uint32_t texture_type = 2; // MTLTextureType2D156uint32_t image_format = 0;157uint32_t array_length = 0;158uint32_t is_multisampled = 0;159};160161struct UniformData {162/// Specifies the index into the `bindings` array for the shader stage.163///164/// For example, a vertex and fragment shader use slots 0 and 1 of the bindings and bindings_secondary arrays.165static constexpr uint32_t STAGE_INDEX[RenderingDeviceCommons::SHADER_STAGE_MAX] = {1660, // SHADER_STAGE_VERTEX1671, // SHADER_STAGE_FRAGMENT1680, // SHADER_STAGE_TESSELATION_CONTROL1691, // SHADER_STAGE_TESSELATION_EVALUATION1700, // SHADER_STAGE_COMPUTE171};172173/// Specifies the stages the uniform data is174/// used by the Metal shader.175uint32_t active_stages = 0;176/// The primary binding information for the uniform data.177///178/// A maximum of two stages is expected for any given pipeline, such as a vertex and fragment, so179/// the array size is fixed to 2.180BindingInfoData bindings[2];181/// The secondary binding information for the uniform data.182///183/// This is typically a sampler for an image-sampler uniform184BindingInfoData bindings_secondary[2];185186_FORCE_INLINE_ constexpr uint32_t get_index_for_stage(RenderingDeviceCommons::ShaderStage p_stage) const {187return STAGE_INDEX[p_stage];188}189190_FORCE_INLINE_ BindingInfoData &get_binding_for_stage(RenderingDeviceCommons::ShaderStage p_stage) {191BindingInfoData &info = bindings[get_index_for_stage(p_stage)];192DEV_ASSERT(info.shader_stage == UINT32_MAX || info.shader_stage == p_stage); // make sure this uniform isn't used in the other stage193info.shader_stage = p_stage;194return info;195}196197_FORCE_INLINE_ BindingInfoData &get_secondary_binding_for_stage(RenderingDeviceCommons::ShaderStage p_stage) {198BindingInfoData &info = bindings_secondary[get_index_for_stage(p_stage)];199DEV_ASSERT(info.shader_stage == UINT32_MAX || info.shader_stage == p_stage); // make sure this uniform isn't used in the other stage200info.shader_stage = p_stage;201return info;202}203};204205struct SpecializationData {206uint32_t used_stages = 0;207};208209HeaderData mtl_reflection_data; // compliment to reflection_data210Vector<StageData> mtl_shaders; // compliment to shaders211212private:213const MetalDeviceProfile *device_profile = nullptr;214bool export_mode = false;215216Vector<UniformData> mtl_reflection_binding_set_uniforms_data; // compliment to reflection_binding_set_uniforms_data217Vector<SpecializationData> mtl_reflection_specialization_data; // compliment to reflection_specialization_data218219Error compile_metal_source(const char *p_source, const StageData &p_stage_data, Vector<uint8_t> &r_binary_data);220221public:222static constexpr uint32_t FORMAT_VERSION = 1;223224void set_export_mode(bool p_export_mode) { export_mode = p_export_mode; }225void set_device_profile(const MetalDeviceProfile *p_device_profile) { device_profile = p_device_profile; }226227struct MetalShaderReflection {228Vector<Vector<UniformData>> uniform_sets;229Vector<SpecializationData> specialization_constants;230};231232MetalShaderReflection get_metal_shader_reflection() const;233234protected:235virtual uint32_t _from_bytes_reflection_extra_data(const uint8_t *p_bytes) override;236virtual uint32_t _from_bytes_reflection_binding_uniform_extra_data_start(const uint8_t *p_bytes) override;237virtual uint32_t _from_bytes_reflection_binding_uniform_extra_data(const uint8_t *p_bytes, uint32_t p_index) override;238virtual uint32_t _from_bytes_reflection_specialization_extra_data_start(const uint8_t *p_bytes) override;239virtual uint32_t _from_bytes_reflection_specialization_extra_data(const uint8_t *p_bytes, uint32_t p_index) override;240virtual uint32_t _from_bytes_shader_extra_data_start(const uint8_t *p_bytes) override;241virtual uint32_t _from_bytes_shader_extra_data(const uint8_t *p_bytes, uint32_t p_index) override;242243virtual uint32_t _to_bytes_reflection_extra_data(uint8_t *p_bytes) const override;244virtual uint32_t _to_bytes_reflection_binding_uniform_extra_data(uint8_t *p_bytes, uint32_t p_index) const override;245virtual uint32_t _to_bytes_reflection_specialization_extra_data(uint8_t *p_bytes, uint32_t p_index) const override;246virtual uint32_t _to_bytes_shader_extra_data(uint8_t *p_bytes, uint32_t p_index) const override;247248virtual uint32_t _format() const override;249virtual uint32_t _format_version() const override;250virtual bool _set_code_from_spirv(const Vector<RenderingDeviceCommons::ShaderStageSPIRVData> &p_spirv) override;251};252253class RenderingShaderContainerFormatMetal : public RenderingShaderContainerFormat {254bool export_mode = false;255256const MetalDeviceProfile *device_profile = nullptr;257258public:259virtual Ref<RenderingShaderContainer> create_container() const override;260virtual ShaderLanguageVersion get_shader_language_version() const override;261virtual ShaderSpirvVersion get_shader_spirv_version() const override;262RenderingShaderContainerFormatMetal(const MetalDeviceProfile *p_device_profile, bool p_export = false);263virtual ~RenderingShaderContainerFormatMetal() = default;264};265266267