123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /******************************************************************************
- Copyright (C) 2024 by Patrick Heyer <[email protected]>
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
- import CoreGraphics
- import CoreVideo
- import Foundation
- import Metal
- extension MTLPixelFormat {
- /// Property to check whether the pixel format is an 8-bit format
- var is8Bit: Bool {
- switch self {
- case .a8Unorm, .r8Unorm, .r8Snorm, .r8Uint, .r8Sint:
- return true
- case .r8Unorm_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a 16-bit format
- var is16Bit: Bool {
- switch self {
- case .r16Unorm, .r16Snorm, .r16Uint, .r16Sint:
- return true
- case .rg8Unorm, .rg8Snorm, .rg8Uint, .rg8Sint:
- return true
- case .rg16Float:
- return true
- case .rg8Unorm_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a packed 16-bit format
- var isPacked16Bit: Bool {
- switch self {
- case .b5g6r5Unorm, .a1bgr5Unorm, .abgr4Unorm, .bgr5A1Unorm:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a 32-bit format
- var is32Bit: Bool {
- switch self {
- case .r32Uint, .r32Sint:
- return true
- case .r32Float:
- return true
- case .rg16Unorm, .rg16Snorm, .rg16Uint, .rg16Sint:
- return true
- case .rg16Float:
- return true
- case .rgba8Unorm, .rgba8Snorm, .rgba8Uint, .rgba8Sint, .bgra8Unorm:
- return true
- case .rgba8Unorm_srgb, .bgra8Unorm_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a packed 32-bit format
- var isPacked32Bit: Bool {
- switch self {
- case .rgb10a2Unorm, .rgb10a2Uint, .bgr10a2Unorm:
- return true
- case .rg11b10Float:
- return true
- case .rgb9e5Float:
- return true
- case .bgr10_xr, .bgr10_xr_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a 64-bit format
- var is64Bit: Bool {
- switch self {
- case .rg32Uint, .rg32Sint:
- return true
- case .rg32Float:
- return true
- case .rgba16Unorm, .rgba16Snorm, .rgba16Uint, .rgba16Sint:
- return true
- case .rgba16Float:
- return true
- case .bgra10_xr, .bgra10_xr_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a 128-bit format
- var is128Bit: Bool {
- switch self {
- case .rgba32Uint, .rgba32Sint:
- return true
- case .rgba32Float:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format will trigger automatic sRGB gamma encoding and decoding
- var isSRGB: Bool {
- switch self {
- case .r8Unorm_srgb, .rg8Unorm_srgb, .bgra8Unorm_srgb, .rgba8Unorm_srgb:
- return true
- case .bgr10_xr_srgb, .bgra10_xr_srgb:
- return true
- case .astc_4x4_srgb, .astc_5x4_srgb, .astc_5x5_srgb, .astc_6x5_srgb, .astc_6x6_srgb, .astc_8x5_srgb,
- .astc_8x6_srgb, .astc_8x8_srgb, .astc_10x5_srgb, .astc_10x6_srgb, .astc_10x8_srgb, .astc_10x10_srgb,
- .astc_12x10_srgb, .astc_12x12_srgb:
- return true
- case .bc1_rgba_srgb, .bc2_rgba_srgb, .bc3_rgba_srgb, .bc7_rgbaUnorm_srgb:
- return true
- case .eac_rgba8_srgb, .etc2_rgb8, .etc2_rgb8a1_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is an extended dynamic range (EDR) format
- var isEDR: Bool {
- switch self {
- case .bgr10_xr, .bgra10_xr, .bgr10_xr_srgb, .bgra10_xr_srgb:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format uses a form of texture compression
- var isCompressed: Bool {
- switch self {
- // S3TC
- case .bc1_rgba, .bc1_rgba_srgb, .bc2_rgba, .bc2_rgba_srgb, .bc3_rgba, .bc3_rgba_srgb:
- return true
- // RGTC
- case .bc4_rUnorm, .bc4_rSnorm, .bc5_rgUnorm, .bc5_rgSnorm:
- return true
- // BPTC
- case .bc6H_rgbFloat, .bc6H_rgbuFloat, .bc7_rgbaUnorm, .bc7_rgbaUnorm_srgb:
- return true
- // EAC
- case .eac_r11Unorm, .eac_r11Snorm, .eac_rg11Unorm, .eac_rg11Snorm, .eac_rgba8, .eac_rgba8_srgb:
- return true
- // ETC
- case .etc2_rgb8, .etc2_rgb8_srgb, .etc2_rgb8a1, .etc2_rgb8a1_srgb:
- return true
- // ASTC
- case .astc_4x4_srgb, .astc_5x4_srgb, .astc_5x5_srgb, .astc_6x5_srgb, .astc_6x6_srgb, .astc_8x5_srgb,
- .astc_8x6_srgb, .astc_8x8_srgb, .astc_10x5_srgb, .astc_10x6_srgb, .astc_10x8_srgb, .astc_10x10_srgb,
- .astc_12x10_srgb, .astc_12x12_srgb, .astc_4x4_ldr, .astc_5x4_ldr, .astc_5x5_ldr, .astc_6x5_ldr,
- .astc_6x6_ldr, .astc_8x5_ldr, .astc_8x6_ldr, .astc_8x8_ldr, .astc_10x5_ldr, .astc_10x6_ldr, .astc_10x8_ldr,
- .astc_10x10_ldr, .astc_12x10_ldr, .astc_12x12_ldr:
- return true
- // ASTC HDR
- case .astc_4x4_hdr, .astc_5x4_hdr, .astc_5x5_hdr, .astc_6x5_hdr, .astc_6x6_hdr, .astc_8x5_hdr, .astc_8x6_hdr,
- .astc_8x8_hdr, .astc_10x5_hdr, .astc_10x6_hdr, .astc_10x8_hdr, .astc_10x10_hdr, .astc_12x10_hdr,
- .astc_12x12_hdr:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is a depth buffer format
- var isDepth: Bool {
- switch self {
- case .depth16Unorm, .depth32Float:
- return true
- default:
- return false
- }
- }
- /// Property to check whether the pixel format is depth stencil format
- var isStencil: Bool {
- switch self {
- case .stencil8, .x24_stencil8, .x32_stencil8, .depth24Unorm_stencil8, .depth32Float_stencil8:
- return true
- default:
- return false
- }
- }
- /// Returns number of color components used by the pixel format
- var componentCount: Int? {
- switch self {
- case .a8Unorm, .r8Unorm, .r8Snorm, .r8Uint, .r8Sint, .r8Unorm_srgb:
- return 1
- case .r16Unorm, .r16Snorm, .r16Uint, .r16Sint, .r16Float:
- return 1
- case .r32Uint, .r32Sint, .r32Float:
- return 1
- case .rg8Unorm, .rg8Snorm, .rg8Uint, .rg8Sint, .rg8Unorm_srgb:
- return 2
- case .rg16Unorm, .rg16Snorm, .rg16Uint, .rg16Sint:
- return 2
- case .rg32Uint, .rg32Sint, .rg32Float:
- return 2
- case .b5g6r5Unorm, .rg11b10Float, .rgb9e5Float, .gbgr422, .bgrg422:
- return 3
- case .a1bgr5Unorm, .abgr4Unorm, .bgr5A1Unorm:
- return 4
- case .rgba8Unorm, .rgba8Snorm, .rgba8Uint, .rgba8Sint, .rgba8Unorm_srgb, .bgra8Unorm, .bgra8Unorm_srgb:
- return 4
- case .rgb10a2Unorm, .rgb10a2Uint, .bgr10a2Unorm, .bgr10_xr, .bgr10_xr_srgb:
- return 4
- case .rgba16Unorm, .rgba16Snorm, .rgba16Uint, .rgba16Sint, .rgba16Float:
- return 4
- case .rgba32Uint, .rgba32Sint, .rgba32Float:
- return 4
- case .bc4_rUnorm, .bc4_rSnorm, .eac_r11Unorm, .eac_r11Snorm:
- return 1
- case .bc5_rgUnorm, .bc5_rgSnorm:
- return 2
- case .bc6H_rgbFloat, .bc6H_rgbuFloat, .eac_rg11Unorm, .eac_rg11Snorm, .etc2_rgb8, .etc2_rgb8_srgb:
- return 3
- case .bc1_rgba, .bc1_rgba_srgb, .bc2_rgba, .bc2_rgba_srgb, .bc3_rgba, .bc3_rgba_srgb, .etc2_rgb8a1,
- .etc2_rgb8a1_srgb, .eac_rgba8, .eac_rgba8_srgb, .bc7_rgbaUnorm, .bc7_rgbaUnorm_srgb:
- return 4
- default:
- return nil
- }
- }
- /// Conversion of pixel format to `libobs` color format
- var gsColorFormat: gs_color_format {
- switch self {
- case .a8Unorm:
- return GS_A8
- case .r8Unorm:
- return GS_R8
- case .rgba8Unorm:
- return GS_RGBA
- case .bgra8Unorm:
- return GS_BGRA
- case .rgb10a2Unorm:
- return GS_R10G10B10A2
- case .rgba16Unorm:
- return GS_RGBA16
- case .r16Unorm:
- return GS_R16
- case .rgba16Float:
- return GS_RGBA16F
- case .rgba32Float:
- return GS_RGBA32F
- case .rg16Float:
- return GS_RG16F
- case .rg32Float:
- return GS_RG32F
- case .r16Float:
- return GS_R16F
- case .r32Float:
- return GS_R32F
- case .bc1_rgba:
- return GS_DXT1
- case .bc2_rgba:
- return GS_DXT3
- case .bc3_rgba:
- return GS_DXT5
- default:
- return GS_UNKNOWN
- }
- }
- /// Returns the bits per pixel based on the pixel format
- var bitsPerPixel: Int? {
- if self.is8Bit {
- return 8
- } else if self.is16Bit || self.isPacked16Bit {
- return 16
- } else if self.is32Bit || self.isPacked32Bit {
- return 32
- } else if self.is64Bit {
- return 64
- } else if self.is128Bit {
- return 128
- } else {
- return nil
- }
- }
- /// Returns the bytes per pixel based on the pixel format
- var bytesPerPixel: Int? {
- if self.is8Bit {
- return 1
- } else if self.is16Bit || self.isPacked16Bit {
- return 2
- } else if self.is32Bit {
- return 4
- } else if self.isPacked32Bit {
- switch self {
- case .rgb10a2Unorm, .rgb10a2Uint, .bgr10a2Unorm, .rg11b10Float, .rgb9e5Float:
- return 4
- case .bgr10_xr, .bgr10_xr_srgb:
- return 8
- default:
- return nil
- }
- } else if self.is64Bit {
- return 8
- } else {
- return nil
- }
- }
- /// Returns the bytes used per color component of the pixel format
- var bitsPerComponent: Int? {
- if !self.isCompressed {
- if let bitsPerPixel = self.bitsPerPixel, let componentCount = self.componentCount {
- return bitsPerPixel / componentCount
- }
- }
- return nil
- }
- }
- extension MTLPixelFormat {
- /// Converts the pixel format into a compatible CoreGraphics color space
- var colorSpace: CGColorSpace? {
- switch self {
- case .a8Unorm, .r8Unorm, .r8Snorm, .r8Uint, .r8Sint, .r16Unorm, .r16Snorm, .r16Uint, .r16Sint,
- .r16Float, .r32Uint, .r32Sint, .r32Float:
- return CGColorSpace(name: CGColorSpace.linearGray)
- case .rg8Unorm, .rg8Snorm, .rg8Uint, .rg8Sint, .rgba8Unorm, .rgba8Snorm, .rgba8Uint, .rgba8Sint, .bgra8Unorm,
- .rgba16Unorm, .rgba16Snorm, .rgba16Uint, .rgba16Sint:
- return CGColorSpace(name: CGColorSpace.linearSRGB)
- case .rg8Unorm_srgb, .rgba8Unorm_srgb, .bgra8Unorm_srgb:
- return CGColorSpace(name: CGColorSpace.sRGB)
- case .rg16Float, .rg32Float, .rgba16Float, .rgba32Float, .bgr10_xr, .bgr10a2Unorm:
- return CGColorSpace(name: CGColorSpace.extendedLinearSRGB)
- case .bgr10_xr_srgb:
- return CGColorSpace(name: CGColorSpace.extendedSRGB)
- default:
- return nil
- }
- }
- }
- extension MTLPixelFormat {
- /// Initializes a ``MTLPixelFormat`` with a compatible CoreVideo video pixel format
- init?(osType: OSType) {
- guard let pixelFormat = osType.mtlFormat else {
- return nil
- }
- self = pixelFormat
- }
- /// Conversion of the pixel format into a compatible CoreVideo video pixel format
- var videoPixelFormat: OSType? {
- switch self {
- case .r8Unorm, .r8Unorm_srgb:
- return kCVPixelFormatType_OneComponent8
- case .r16Float:
- return kCVPixelFormatType_OneComponent16Half
- case .r32Float:
- return kCVPixelFormatType_OneComponent32Float
- case .rg8Unorm, .rg8Unorm_srgb:
- return kCVPixelFormatType_TwoComponent8
- case .rg16Float:
- return kCVPixelFormatType_TwoComponent16Half
- case .rg32Float:
- return kCVPixelFormatType_TwoComponent32Float
- case .bgra8Unorm, .bgra8Unorm_srgb:
- return kCVPixelFormatType_32BGRA
- case .rgba8Unorm, .rgba8Unorm_srgb:
- return kCVPixelFormatType_32RGBA
- case .rgba16Float:
- return kCVPixelFormatType_64RGBAHalf
- case .rgba32Float:
- return kCVPixelFormatType_128RGBAFloat
- default:
- return nil
- }
- }
- }
|