/**************************************************************************/1/* pixel_formats.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/**************************************************************************/33/* */34/* Portions of this code were derived from MoltenVK. */35/* */36/* Copyright (c) 2015-2023 The Brenwill Workshop Ltd. */37/* (http://www.brenwill.com) */38/* */39/* Licensed under the Apache License, Version 2.0 (the "License"); */40/* you may not use this file except in compliance with the License. */41/* You may obtain a copy of the License at */42/* */43/* http://www.apache.org/licenses/LICENSE-2.0 */44/* */45/* Unless required by applicable law or agreed to in writing, software */46/* distributed under the License is distributed on an "AS IS" BASIS, */47/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */48/* implied. See the License for the specific language governing */49/* permissions and limitations under the License. */50/**************************************************************************/5152#include "core/typedefs.h"5354GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations")5556#include "inflection_map.h"57#include "metal_device_properties.h"5859#include "servers/rendering/rendering_device_commons.h"6061#ifdef __OBJC__62#include <Metal/Metal.h>63#endif64#include <Metal/Metal.hpp>65#include <iterator>6667#pragma mark -68#pragma mark Metal format capabilities6970using RDC = RenderingDeviceCommons;7172typedef enum : uint16_t {7374kMTLFmtCapsNone = 0,75/*! The format can be used in a shader read operation. */76kMTLFmtCapsRead = (1 << 0),77/*! The format can be used in a shader filter operation during sampling. */78kMTLFmtCapsFilter = (1 << 1),79/*! The format can be used in a shader write operation. */80kMTLFmtCapsWrite = (1 << 2),81/*! The format can be used with atomic operations. */82kMTLFmtCapsAtomic = (1 << 3),83/*! The format can be used as a color attachment. */84kMTLFmtCapsColorAtt = (1 << 4),85/*! The format can be used as a depth-stencil attachment. */86kMTLFmtCapsDSAtt = (1 << 5),87/*! The format can be used with blend operations. */88kMTLFmtCapsBlend = (1 << 6),89/*! The format can be used as a destination for multisample antialias (MSAA) data. */90kMTLFmtCapsMSAA = (1 << 7),91/*! The format can be used as a resolve attachment. */92kMTLFmtCapsResolve = (1 << 8),93kMTLFmtCapsVertex = (1 << 9),9495kMTLFmtCapsRF = (kMTLFmtCapsRead | kMTLFmtCapsFilter),96kMTLFmtCapsRC = (kMTLFmtCapsRead | kMTLFmtCapsColorAtt),97kMTLFmtCapsRCB = (kMTLFmtCapsRC | kMTLFmtCapsBlend),98kMTLFmtCapsRCM = (kMTLFmtCapsRC | kMTLFmtCapsMSAA),99kMTLFmtCapsRCMB = (kMTLFmtCapsRCM | kMTLFmtCapsBlend),100kMTLFmtCapsRWC = (kMTLFmtCapsRC | kMTLFmtCapsWrite),101kMTLFmtCapsRWCB = (kMTLFmtCapsRWC | kMTLFmtCapsBlend),102kMTLFmtCapsRWCM = (kMTLFmtCapsRWC | kMTLFmtCapsMSAA),103kMTLFmtCapsRWCMB = (kMTLFmtCapsRWCM | kMTLFmtCapsBlend),104kMTLFmtCapsRFCMRB = (kMTLFmtCapsRCMB | kMTLFmtCapsFilter | kMTLFmtCapsResolve),105kMTLFmtCapsRFWCMB = (kMTLFmtCapsRWCMB | kMTLFmtCapsFilter),106kMTLFmtCapsAll = (kMTLFmtCapsRFWCMB | kMTLFmtCapsResolve),107108kMTLFmtCapsDRM = (kMTLFmtCapsDSAtt | kMTLFmtCapsRead | kMTLFmtCapsMSAA),109kMTLFmtCapsDRFM = (kMTLFmtCapsDRM | kMTLFmtCapsFilter),110kMTLFmtCapsDRMR = (kMTLFmtCapsDRM | kMTLFmtCapsResolve),111kMTLFmtCapsDRFMR = (kMTLFmtCapsDRFM | kMTLFmtCapsResolve),112113kMTLFmtCapsChromaSubsampling = kMTLFmtCapsRF,114kMTLFmtCapsMultiPlanar = kMTLFmtCapsChromaSubsampling,115} MTLFmtCaps;116117inline MTLFmtCaps operator|(MTLFmtCaps p_left, MTLFmtCaps p_right) {118return static_cast<MTLFmtCaps>(static_cast<uint32_t>(p_left) | p_right);119}120121inline MTLFmtCaps &operator|=(MTLFmtCaps &p_left, MTLFmtCaps p_right) {122return (p_left = p_left | p_right);123}124125#pragma mark -126#pragma mark Metal view classes127128enum class MTLViewClass : uint8_t {129None,130Color8,131Color16,132Color32,133Color64,134Color128,135PVRTC_RGB_2BPP,136PVRTC_RGB_4BPP,137PVRTC_RGBA_2BPP,138PVRTC_RGBA_4BPP,139EAC_R11,140EAC_RG11,141EAC_RGBA8,142ETC2_RGB8,143ETC2_RGB8A1,144ASTC_4x4,145ASTC_5x4,146ASTC_5x5,147ASTC_6x5,148ASTC_6x6,149ASTC_8x5,150ASTC_8x6,151ASTC_8x8,152ASTC_10x5,153ASTC_10x6,154ASTC_10x8,155ASTC_10x10,156ASTC_12x10,157ASTC_12x12,158BC1_RGBA,159BC2_RGBA,160BC3_RGBA,161BC4_R,162BC5_RG,163BC6H_RGB,164BC7_RGBA,165Depth24_Stencil8,166Depth32_Stencil8,167BGRA10_XR,168BGR10_XR169};170171#pragma mark -172#pragma mark Format descriptors173174/** Enumerates the data type of a format. */175enum class MTLFormatType {176None, /**< Format type is unknown. */177ColorHalf, /**< A 16-bit floating point color. */178ColorFloat, /**< A 32-bit floating point color. */179ColorInt8, /**< A signed 8-bit integer color. */180ColorUInt8, /**< An unsigned 8-bit integer color. */181ColorInt16, /**< A signed 16-bit integer color. */182ColorUInt16, /**< An unsigned 16-bit integer color. */183ColorInt32, /**< A signed 32-bit integer color. */184ColorUInt32, /**< An unsigned 32-bit integer color. */185DepthStencil, /**< A depth and stencil value. */186Compressed, /**< A block-compressed color. */187};188189struct Extent2D {190uint32_t width;191uint32_t height;192};193194struct ComponentMapping {195RDC::TextureSwizzle r = RDC::TEXTURE_SWIZZLE_IDENTITY;196RDC::TextureSwizzle g = RDC::TEXTURE_SWIZZLE_IDENTITY;197RDC::TextureSwizzle b = RDC::TEXTURE_SWIZZLE_IDENTITY;198RDC::TextureSwizzle a = RDC::TEXTURE_SWIZZLE_IDENTITY;199};200201/** Describes the properties of a DataFormat, including the corresponding Metal pixel and vertex format. */202struct DataFormatDesc {203RDC::DataFormat dataFormat;204MTL::PixelFormat mtlPixelFormat;205MTL::PixelFormat mtlPixelFormatSubstitute;206MTL::VertexFormat mtlVertexFormat;207MTL::VertexFormat mtlVertexFormatSubstitute;208uint8_t chromaSubsamplingPlaneCount;209uint8_t chromaSubsamplingComponentBits;210Extent2D blockTexelSize;211uint32_t bytesPerBlock;212MTLFormatType formatType;213ComponentMapping componentMapping;214const char *name;215bool hasReportedSubstitution;216217inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); }218219inline bool isSupported() const { return (mtlPixelFormat != MTL::PixelFormatInvalid || chromaSubsamplingPlaneCount > 1); }220inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlPixelFormatSubstitute != MTL::PixelFormatInvalid); }221222inline bool vertexIsSupported() const { return (mtlVertexFormat != MTL::VertexFormatInvalid); }223inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTL::VertexFormatInvalid); }224225bool needsSwizzle() const {226return (componentMapping.r != RDC::TEXTURE_SWIZZLE_IDENTITY ||227componentMapping.g != RDC::TEXTURE_SWIZZLE_IDENTITY ||228componentMapping.b != RDC::TEXTURE_SWIZZLE_IDENTITY ||229componentMapping.a != RDC::TEXTURE_SWIZZLE_IDENTITY);230}231};232233/** Describes the properties of a MTL::PixelFormat or MTL::VertexFormat. */234struct MTLFormatDesc {235union {236MTL::PixelFormat mtlPixelFormat;237MTL::VertexFormat mtlVertexFormat;238};239RDC::DataFormat dataFormat = RDC::DATA_FORMAT_MAX;240MTLFmtCaps mtlFmtCaps;241MTLViewClass mtlViewClass;242MTL::PixelFormat mtlPixelFormatLinear;243const char *name = nullptr;244245inline bool isSupported() const { return (mtlPixelFormat != MTL::PixelFormatInvalid) && (mtlFmtCaps != kMTLFmtCapsNone); }246};247248class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) PixelFormats {249using DataFormat = RDC::DataFormat;250251public:252/** Returns whether the DataFormat is supported by the GPU bound to this instance. */253bool isSupported(DataFormat p_format);254255/** Returns whether the DataFormat is supported by this implementation, or can be substituted by one that is. */256bool isSupportedOrSubstitutable(DataFormat p_format);257258/** Returns whether the specified Metal MTL::PixelFormat can be used as a depth format. */259_FORCE_INLINE_ bool isDepthFormat(MTL::PixelFormat p_format) {260switch (p_format) {261case MTL::PixelFormatDepth32Float:262case MTL::PixelFormatDepth16Unorm:263case MTL::PixelFormatDepth32Float_Stencil8:264#if TARGET_OS_OSX265case MTL::PixelFormatDepth24Unorm_Stencil8:266#endif267return true;268default:269return false;270}271}272273/** Returns whether the specified Metal MTL::PixelFormat can be used as a stencil format. */274_FORCE_INLINE_ bool isStencilFormat(MTL::PixelFormat p_format) {275switch (p_format) {276case MTL::PixelFormatStencil8:277#if TARGET_OS_OSX278case MTL::PixelFormatDepth24Unorm_Stencil8:279case MTL::PixelFormatX24_Stencil8:280#endif281case MTL::PixelFormatDepth32Float_Stencil8:282case MTL::PixelFormatX32_Stencil8:283return true;284default:285return false;286}287}288289/** Returns whether the specified Metal MTL::PixelFormat is a PVRTC format. */290bool isPVRTCFormat(MTL::PixelFormat p_format);291292/** Returns the format type corresponding to the specified Godot pixel format, */293MTLFormatType getFormatType(DataFormat p_format);294295/** Returns the format type corresponding to the specified Metal MTL::PixelFormat, */296MTLFormatType getFormatType(MTL::PixelFormat p_format);297298/**299* Returns the Metal MTL::PixelFormat corresponding to the specified Godot pixel300* or returns MTL::PixelFormatInvalid if no corresponding MTL::PixelFormat exists.301*/302MTL::PixelFormat getMTLPixelFormat(DataFormat p_format);303304/**305* Returns the DataFormat corresponding to the specified Metal MTL::PixelFormat,306* or returns DATA_FORMAT_MAX if no corresponding DataFormat exists.307*/308DataFormat getDataFormat(MTL::PixelFormat p_format);309310/**311* Returns the size, in bytes, of a texel block of the specified Godot pixel.312* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.313*/314uint32_t getBytesPerBlock(DataFormat p_format);315316/**317* Returns the size, in bytes, of a texel block of the specified Metal format.318* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.319*/320uint32_t getBytesPerBlock(MTL::PixelFormat p_format);321322/** Returns the number of planes of the specified chroma-subsampling (YCbCr) DataFormat */323uint8_t getChromaSubsamplingPlaneCount(DataFormat p_format);324325/** Returns the number of bits per channel of the specified chroma-subsampling (YCbCr) DataFormat */326uint8_t getChromaSubsamplingComponentBits(DataFormat p_format);327328/**329* Returns the size, in bytes, of a texel of the specified Godot format.330* The returned value may be fractional for certain compressed formats.331*/332float getBytesPerTexel(DataFormat p_format);333334/**335* Returns the size, in bytes, of a texel of the specified Metal format.336* The returned value may be fractional for certain compressed formats.337*/338float getBytesPerTexel(MTL::PixelFormat p_format);339340/**341* Returns the size, in bytes, of a row of texels of the specified Godot pixel format.342*343* For compressed formats, this takes into consideration the compression block size,344* and p_texels_per_row should specify the width in texels, not blocks. The result is rounded345* up if p_texels_per_row is not an integer multiple of the compression block width.346*/347size_t getBytesPerRow(DataFormat p_format, uint32_t p_texels_per_row);348349/**350* Returns the size, in bytes, of a row of texels of the specified Metal format.351*352* For compressed formats, this takes into consideration the compression block size,353* and texelsPerRow should specify the width in texels, not blocks. The result is rounded354* up if texelsPerRow is not an integer multiple of the compression block width.355*/356size_t getBytesPerRow(MTL::PixelFormat p_format, uint32_t p_texels_per_row);357358/**359* Returns the size, in bytes, of a texture layer of the specified Godot pixel format.360*361* For compressed formats, this takes into consideration the compression block size,362* and p_texel_rows_per_layer should specify the height in texels, not blocks. The result is363* rounded up if p_texel_rows_per_layer is not an integer multiple of the compression block height.364*/365size_t getBytesPerLayer(DataFormat p_format, size_t p_bytes_per_row, uint32_t p_texel_rows_per_layer);366367/**368* Returns the size, in bytes, of a texture layer of the specified Metal format.369* For compressed formats, this takes into consideration the compression block size,370* and p_texel_rows_per_layer should specify the height in texels, not blocks. The result is371* rounded up if p_texel_rows_per_layer is not an integer multiple of the compression block height.372*/373size_t getBytesPerLayer(MTL::PixelFormat p_format, size_t p_bytes_per_row, uint32_t p_texel_rows_per_layer);374375/** Returns whether or not the specified Godot format requires swizzling to use with Metal. */376bool needsSwizzle(DataFormat p_format);377378/** Returns the Metal format capabilities supported by the specified Godot format, without substitution. */379MTLFmtCaps getCapabilities(DataFormat p_format, bool p_extended = false);380381/** Returns the Metal format capabilities supported by the specified Metal format. */382MTLFmtCaps getCapabilities(MTL::PixelFormat p_format, bool p_extended = false);383384/**385* Returns the Metal MTL::VertexFormat corresponding to the specified386* DataFormat as used as a vertex attribute format.387*/388MTL::VertexFormat getMTLVertexFormat(DataFormat p_format);389390#pragma mark Construction391392explicit PixelFormats(MTL::Device *p_device, const MetalFeatures &p_feat);393~PixelFormats();394395protected:396DataFormatDesc &getDataFormatDesc(DataFormat p_format);397DataFormatDesc &getDataFormatDesc(MTL::PixelFormat p_format);398MTLFormatDesc &getMTLPixelFormatDesc(MTL::PixelFormat p_format);399MTLFmtCaps &getMTLPixelFormatCapsIf(MTL::PixelFormat mtlPixFmt, bool cond);400MTLFormatDesc &getMTLVertexFormatDesc(MTL::VertexFormat p_format);401402void initDataFormatCapabilities();403void initMTLPixelFormatCapabilities();404void initMTLVertexFormatCapabilities(const MetalFeatures &p_feat);405void modifyMTLFormatCapabilities(const MetalFeatures &p_feat);406void buildDFFormatMaps();407void addMTLPixelFormatDescImpl(MTL::PixelFormat p_pix_fmt, MTL::PixelFormat p_pix_fmt_linear,408MTLViewClass p_view_class, MTLFmtCaps p_fmt_caps, const char *p_name);409void addMTLVertexFormatDescImpl(MTL::VertexFormat p_vert_fmt, MTLFmtCaps p_vert_caps, const char *name);410411MTL::Device *device;412InflectionMap<DataFormat, DataFormatDesc, RDC::DATA_FORMAT_MAX> _data_format_descs;413InflectionMap<uint16_t, MTLFormatDesc, MTL::PixelFormatX32_Stencil8 + 2> _mtl_pixel_format_descs; // The actual last enum value is not available on iOS.414TightLocalVector<MTLFormatDesc> _mtl_vertex_format_descs;415};416417GODOT_CLANG_WARNING_POP418419420