/**************************************************************************/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#import "inflection_map.h"57#import "metal_device_properties.h"5859#include "servers/rendering/rendering_device.h"6061#import <Metal/Metal.h>6263#pragma mark -64#pragma mark Metal format capabilities6566typedef enum : uint16_t {6768kMTLFmtCapsNone = 0,69/*! The format can be used in a shader read operation. */70kMTLFmtCapsRead = (1 << 0),71/*! The format can be used in a shader filter operation during sampling. */72kMTLFmtCapsFilter = (1 << 1),73/*! The format can be used in a shader write operation. */74kMTLFmtCapsWrite = (1 << 2),75/*! The format can be used with atomic operations. */76kMTLFmtCapsAtomic = (1 << 3),77/*! The format can be used as a color attachment. */78kMTLFmtCapsColorAtt = (1 << 4),79/*! The format can be used as a depth-stencil attachment. */80kMTLFmtCapsDSAtt = (1 << 5),81/*! The format can be used with blend operations. */82kMTLFmtCapsBlend = (1 << 6),83/*! The format can be used as a destination for multisample antialias (MSAA) data. */84kMTLFmtCapsMSAA = (1 << 7),85/*! The format can be used as a resolve attachment. */86kMTLFmtCapsResolve = (1 << 8),87kMTLFmtCapsVertex = (1 << 9),8889kMTLFmtCapsRF = (kMTLFmtCapsRead | kMTLFmtCapsFilter),90kMTLFmtCapsRC = (kMTLFmtCapsRead | kMTLFmtCapsColorAtt),91kMTLFmtCapsRCB = (kMTLFmtCapsRC | kMTLFmtCapsBlend),92kMTLFmtCapsRCM = (kMTLFmtCapsRC | kMTLFmtCapsMSAA),93kMTLFmtCapsRCMB = (kMTLFmtCapsRCM | kMTLFmtCapsBlend),94kMTLFmtCapsRWC = (kMTLFmtCapsRC | kMTLFmtCapsWrite),95kMTLFmtCapsRWCB = (kMTLFmtCapsRWC | kMTLFmtCapsBlend),96kMTLFmtCapsRWCM = (kMTLFmtCapsRWC | kMTLFmtCapsMSAA),97kMTLFmtCapsRWCMB = (kMTLFmtCapsRWCM | kMTLFmtCapsBlend),98kMTLFmtCapsRFCMRB = (kMTLFmtCapsRCMB | kMTLFmtCapsFilter | kMTLFmtCapsResolve),99kMTLFmtCapsRFWCMB = (kMTLFmtCapsRWCMB | kMTLFmtCapsFilter),100kMTLFmtCapsAll = (kMTLFmtCapsRFWCMB | kMTLFmtCapsResolve),101102kMTLFmtCapsDRM = (kMTLFmtCapsDSAtt | kMTLFmtCapsRead | kMTLFmtCapsMSAA),103kMTLFmtCapsDRFM = (kMTLFmtCapsDRM | kMTLFmtCapsFilter),104kMTLFmtCapsDRMR = (kMTLFmtCapsDRM | kMTLFmtCapsResolve),105kMTLFmtCapsDRFMR = (kMTLFmtCapsDRFM | kMTLFmtCapsResolve),106107kMTLFmtCapsChromaSubsampling = kMTLFmtCapsRF,108kMTLFmtCapsMultiPlanar = kMTLFmtCapsChromaSubsampling,109} MTLFmtCaps;110111inline MTLFmtCaps operator|(MTLFmtCaps p_left, MTLFmtCaps p_right) {112return static_cast<MTLFmtCaps>(static_cast<uint32_t>(p_left) | p_right);113}114115inline MTLFmtCaps &operator|=(MTLFmtCaps &p_left, MTLFmtCaps p_right) {116return (p_left = p_left | p_right);117}118119#pragma mark -120#pragma mark Metal view classes121122enum class MTLViewClass : uint8_t {123None,124Color8,125Color16,126Color32,127Color64,128Color128,129PVRTC_RGB_2BPP,130PVRTC_RGB_4BPP,131PVRTC_RGBA_2BPP,132PVRTC_RGBA_4BPP,133EAC_R11,134EAC_RG11,135EAC_RGBA8,136ETC2_RGB8,137ETC2_RGB8A1,138ASTC_4x4,139ASTC_5x4,140ASTC_5x5,141ASTC_6x5,142ASTC_6x6,143ASTC_8x5,144ASTC_8x6,145ASTC_8x8,146ASTC_10x5,147ASTC_10x6,148ASTC_10x8,149ASTC_10x10,150ASTC_12x10,151ASTC_12x12,152BC1_RGBA,153BC2_RGBA,154BC3_RGBA,155BC4_R,156BC5_RG,157BC6H_RGB,158BC7_RGBA,159Depth24_Stencil8,160Depth32_Stencil8,161BGRA10_XR,162BGR10_XR163};164165#pragma mark -166#pragma mark Format descriptors167168/** Enumerates the data type of a format. */169enum class MTLFormatType {170None, /**< Format type is unknown. */171ColorHalf, /**< A 16-bit floating point color. */172ColorFloat, /**< A 32-bit floating point color. */173ColorInt8, /**< A signed 8-bit integer color. */174ColorUInt8, /**< An unsigned 8-bit integer color. */175ColorInt16, /**< A signed 16-bit integer color. */176ColorUInt16, /**< An unsigned 16-bit integer color. */177ColorInt32, /**< A signed 32-bit integer color. */178ColorUInt32, /**< An unsigned 32-bit integer color. */179DepthStencil, /**< A depth and stencil value. */180Compressed, /**< A block-compressed color. */181};182183struct Extent2D {184uint32_t width;185uint32_t height;186};187188struct ComponentMapping {189RD::TextureSwizzle r = RD::TEXTURE_SWIZZLE_IDENTITY;190RD::TextureSwizzle g = RD::TEXTURE_SWIZZLE_IDENTITY;191RD::TextureSwizzle b = RD::TEXTURE_SWIZZLE_IDENTITY;192RD::TextureSwizzle a = RD::TEXTURE_SWIZZLE_IDENTITY;193};194195/** Describes the properties of a DataFormat, including the corresponding Metal pixel and vertex format. */196struct DataFormatDesc {197RD::DataFormat dataFormat;198MTLPixelFormat mtlPixelFormat;199MTLPixelFormat mtlPixelFormatSubstitute;200MTLVertexFormat mtlVertexFormat;201MTLVertexFormat mtlVertexFormatSubstitute;202uint8_t chromaSubsamplingPlaneCount;203uint8_t chromaSubsamplingComponentBits;204Extent2D blockTexelSize;205uint32_t bytesPerBlock;206MTLFormatType formatType;207ComponentMapping componentMapping;208const char *name;209bool hasReportedSubstitution;210211inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); }212213inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid || chromaSubsamplingPlaneCount > 1); }214inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlPixelFormatSubstitute != MTLPixelFormatInvalid); }215216inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); }217inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); }218219bool needsSwizzle() const {220return (componentMapping.r != RD::TEXTURE_SWIZZLE_IDENTITY ||221componentMapping.g != RD::TEXTURE_SWIZZLE_IDENTITY ||222componentMapping.b != RD::TEXTURE_SWIZZLE_IDENTITY ||223componentMapping.a != RD::TEXTURE_SWIZZLE_IDENTITY);224}225};226227/** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */228struct MTLFormatDesc {229union {230MTLPixelFormat mtlPixelFormat;231MTLVertexFormat mtlVertexFormat;232};233RD::DataFormat dataFormat = RD::DATA_FORMAT_MAX;234MTLFmtCaps mtlFmtCaps;235MTLViewClass mtlViewClass;236MTLPixelFormat mtlPixelFormatLinear;237const char *name = nullptr;238239inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid) && (mtlFmtCaps != kMTLFmtCapsNone); }240};241242class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) PixelFormats {243using DataFormat = RD::DataFormat;244245public:246/** Returns whether the DataFormat is supported by the GPU bound to this instance. */247bool isSupported(DataFormat p_format);248249/** Returns whether the DataFormat is supported by this implementation, or can be substituted by one that is. */250bool isSupportedOrSubstitutable(DataFormat p_format);251252/** Returns whether the specified Metal MTLPixelFormat can be used as a depth format. */253_FORCE_INLINE_ bool isDepthFormat(MTLPixelFormat p_format) {254switch (p_format) {255case MTLPixelFormatDepth32Float:256case MTLPixelFormatDepth16Unorm:257case MTLPixelFormatDepth32Float_Stencil8:258#if TARGET_OS_OSX259case MTLPixelFormatDepth24Unorm_Stencil8:260#endif261return true;262default:263return false;264}265}266267/** Returns whether the specified Metal MTLPixelFormat can be used as a stencil format. */268_FORCE_INLINE_ bool isStencilFormat(MTLPixelFormat p_format) {269switch (p_format) {270case MTLPixelFormatStencil8:271#if TARGET_OS_OSX272case MTLPixelFormatDepth24Unorm_Stencil8:273case MTLPixelFormatX24_Stencil8:274#endif275case MTLPixelFormatDepth32Float_Stencil8:276case MTLPixelFormatX32_Stencil8:277return true;278default:279return false;280}281}282283/** Returns whether the specified Metal MTLPixelFormat is a PVRTC format. */284bool isPVRTCFormat(MTLPixelFormat p_format);285286/** Returns the format type corresponding to the specified Godot pixel format, */287MTLFormatType getFormatType(DataFormat p_format);288289/** Returns the format type corresponding to the specified Metal MTLPixelFormat, */290MTLFormatType getFormatType(MTLPixelFormat p_format);291292/**293* Returns the Metal MTLPixelFormat corresponding to the specified Godot pixel294* or returns MTLPixelFormatInvalid if no corresponding MTLPixelFormat exists.295*/296MTLPixelFormat getMTLPixelFormat(DataFormat p_format);297298/**299* Returns the DataFormat corresponding to the specified Metal MTLPixelFormat,300* or returns DATA_FORMAT_MAX if no corresponding DataFormat exists.301*/302DataFormat getDataFormat(MTLPixelFormat p_format);303304/**305* Returns the size, in bytes, of a texel block of the specified Godot pixel.306* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.307*/308uint32_t getBytesPerBlock(DataFormat p_format);309310/**311* Returns the size, in bytes, of a texel block of the specified Metal format.312* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.313*/314uint32_t getBytesPerBlock(MTLPixelFormat p_format);315316/** Returns the number of planes of the specified chroma-subsampling (YCbCr) DataFormat */317uint8_t getChromaSubsamplingPlaneCount(DataFormat p_format);318319/** Returns the number of bits per channel of the specified chroma-subsampling (YCbCr) DataFormat */320uint8_t getChromaSubsamplingComponentBits(DataFormat p_format);321322/**323* Returns the size, in bytes, of a texel of the specified Godot format.324* The returned value may be fractional for certain compressed formats.325*/326float getBytesPerTexel(DataFormat p_format);327328/**329* Returns the size, in bytes, of a texel of the specified Metal format.330* The returned value may be fractional for certain compressed formats.331*/332float getBytesPerTexel(MTLPixelFormat p_format);333334/**335* Returns the size, in bytes, of a row of texels of the specified Godot pixel format.336*337* For compressed formats, this takes into consideration the compression block size,338* and p_texels_per_row should specify the width in texels, not blocks. The result is rounded339* up if p_texels_per_row is not an integer multiple of the compression block width.340*/341size_t getBytesPerRow(DataFormat p_format, uint32_t p_texels_per_row);342343/**344* Returns the size, in bytes, of a row of texels of the specified Metal format.345*346* For compressed formats, this takes into consideration the compression block size,347* and texelsPerRow should specify the width in texels, not blocks. The result is rounded348* up if texelsPerRow is not an integer multiple of the compression block width.349*/350size_t getBytesPerRow(MTLPixelFormat p_format, uint32_t p_texels_per_row);351352/**353* Returns the size, in bytes, of a texture layer of the specified Godot pixel format.354*355* For compressed formats, this takes into consideration the compression block size,356* and p_texel_rows_per_layer should specify the height in texels, not blocks. The result is357* rounded up if p_texel_rows_per_layer is not an integer multiple of the compression block height.358*/359size_t getBytesPerLayer(DataFormat p_format, size_t p_bytes_per_row, uint32_t p_texel_rows_per_layer);360361/**362* Returns the size, in bytes, of a texture layer of the specified Metal format.363* For compressed formats, this takes into consideration the compression block size,364* and p_texel_rows_per_layer should specify the height in texels, not blocks. The result is365* rounded up if p_texel_rows_per_layer is not an integer multiple of the compression block height.366*/367size_t getBytesPerLayer(MTLPixelFormat p_format, size_t p_bytes_per_row, uint32_t p_texel_rows_per_layer);368369/** Returns whether or not the specified Godot format requires swizzling to use with Metal. */370bool needsSwizzle(DataFormat p_format);371372/** Returns the Metal format capabilities supported by the specified Godot format, without substitution. */373MTLFmtCaps getCapabilities(DataFormat p_format, bool p_extended = false);374375/** Returns the Metal format capabilities supported by the specified Metal format. */376MTLFmtCaps getCapabilities(MTLPixelFormat p_format, bool p_extended = false);377378/**379* Returns the Metal MTLVertexFormat corresponding to the specified380* DataFormat as used as a vertex attribute format.381*/382MTLVertexFormat getMTLVertexFormat(DataFormat p_format);383384#pragma mark Construction385386explicit PixelFormats(id<MTLDevice> p_device, const MetalFeatures &p_feat);387388protected:389DataFormatDesc &getDataFormatDesc(DataFormat p_format);390DataFormatDesc &getDataFormatDesc(MTLPixelFormat p_format);391MTLFormatDesc &getMTLPixelFormatDesc(MTLPixelFormat p_format);392MTLFmtCaps &getMTLPixelFormatCapsIf(MTLPixelFormat mtlPixFmt, bool cond);393MTLFormatDesc &getMTLVertexFormatDesc(MTLVertexFormat p_format);394395void initDataFormatCapabilities();396void initMTLPixelFormatCapabilities();397void initMTLVertexFormatCapabilities(const MetalFeatures &p_feat);398void modifyMTLFormatCapabilities(const MetalFeatures &p_feat);399void buildDFFormatMaps();400void addMTLPixelFormatDescImpl(MTLPixelFormat p_pix_fmt, MTLPixelFormat p_pix_fmt_linear,401MTLViewClass p_view_class, MTLFmtCaps p_fmt_caps, const char *p_name);402void addMTLVertexFormatDescImpl(MTLVertexFormat p_vert_fmt, MTLFmtCaps p_vert_caps, const char *name);403404id<MTLDevice> device;405InflectionMap<DataFormat, DataFormatDesc, RD::DATA_FORMAT_MAX> _data_format_descs;406InflectionMap<uint16_t, MTLFormatDesc, MTLPixelFormatX32_Stencil8 + 2> _mtl_pixel_format_descs; // The actual last enum value is not available on iOS.407TightLocalVector<MTLFormatDesc> _mtl_vertex_format_descs;408};409410GODOT_CLANG_WARNING_POP411412413