// Copyright 2022 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "VideoBackends/Metal/MTLVertexFormat.h" #include "VideoCommon/VertexShaderGen.h" static MTLVertexFormat ConvertFormat(ComponentFormat format, int count, bool int_format) { // clang-format off if (int_format) { switch (format) { case ComponentFormat::UByte: switch (count) { case 1: return MTLVertexFormatUChar; case 2: return MTLVertexFormatUChar2; case 3: return MTLVertexFormatUChar3; case 4: return MTLVertexFormatUChar4; default: return MTLVertexFormatInvalid; } case ComponentFormat::Byte: switch (count) { case 1: return MTLVertexFormatChar; case 2: return MTLVertexFormatChar2; case 3: return MTLVertexFormatChar3; case 4: return MTLVertexFormatChar4; default: return MTLVertexFormatInvalid; } case ComponentFormat::UShort: switch (count) { case 1: return MTLVertexFormatUShort; case 2: return MTLVertexFormatUShort2; case 3: return MTLVertexFormatUShort3; case 4: return MTLVertexFormatUShort4; default: return MTLVertexFormatInvalid; } case ComponentFormat::Short: switch (count) { case 1: return MTLVertexFormatShort; case 2: return MTLVertexFormatShort2; case 3: return MTLVertexFormatShort3; case 4: return MTLVertexFormatShort4; default: return MTLVertexFormatInvalid; } case ComponentFormat::Float: switch (count) { case 1: return MTLVertexFormatFloat; case 2: return MTLVertexFormatFloat2; case 3: return MTLVertexFormatFloat3; case 4: return MTLVertexFormatFloat4; default: return MTLVertexFormatInvalid; } } } else { switch (format) { case ComponentFormat::UByte: switch (count) { case 1: return MTLVertexFormatUCharNormalized; case 2: return MTLVertexFormatUChar2Normalized; case 3: return MTLVertexFormatUChar3Normalized; case 4: return MTLVertexFormatUChar4Normalized; default: return MTLVertexFormatInvalid; } case ComponentFormat::Byte: switch (count) { case 1: return MTLVertexFormatCharNormalized; case 2: return MTLVertexFormatChar2Normalized; case 3: return MTLVertexFormatChar3Normalized; case 4: return MTLVertexFormatChar4Normalized; default: return MTLVertexFormatInvalid; } case ComponentFormat::UShort: switch (count) { case 1: return MTLVertexFormatUShortNormalized; case 2: return MTLVertexFormatUShort2Normalized; case 3: return MTLVertexFormatUShort3Normalized; case 4: return MTLVertexFormatUShort4Normalized; default: return MTLVertexFormatInvalid; } case ComponentFormat::Short: switch (count) { case 1: return MTLVertexFormatShortNormalized; case 2: return MTLVertexFormatShort2Normalized; case 3: return MTLVertexFormatShort3Normalized; case 4: return MTLVertexFormatShort4Normalized; default: return MTLVertexFormatInvalid; } case ComponentFormat::Float: switch (count) { case 1: return MTLVertexFormatFloat; case 2: return MTLVertexFormatFloat2; case 3: return MTLVertexFormatFloat3; case 4: return MTLVertexFormatFloat4; default: return MTLVertexFormatInvalid; } } } // clang-format on } static void SetAttribute(MTLVertexDescriptor* desc, u32 attribute, const AttributeFormat& format) { if (!format.enable) return; MTLVertexAttributeDescriptor* attr_desc = [[desc attributes] objectAtIndexedSubscript:attribute]; [attr_desc setFormat:ConvertFormat(format.type, format.components, format.integer)]; [attr_desc setOffset:format.offset]; [attr_desc setBufferIndex:0]; } template static void SetAttributes(MTLVertexDescriptor* desc, u32 attribute, const AttributeFormat (&format)[N]) { for (size_t i = 0; i < N; ++i) SetAttribute(desc, attribute + i, format[i]); } Metal::VertexFormat::VertexFormat(const PortableVertexDeclaration& vtx_decl) : NativeVertexFormat(vtx_decl), m_desc(MRCTransfer([MTLVertexDescriptor new])) { [[[m_desc layouts] objectAtIndexedSubscript:0] setStride:vtx_decl.stride]; SetAttribute(m_desc, SHADER_POSITION_ATTRIB, vtx_decl.position); SetAttributes(m_desc, SHADER_NORMAL_ATTRIB, vtx_decl.normals); SetAttributes(m_desc, SHADER_COLOR0_ATTRIB, vtx_decl.colors); SetAttributes(m_desc, SHADER_TEXTURE0_ATTRIB, vtx_decl.texcoords); SetAttribute(m_desc, SHADER_POSMTX_ATTRIB, vtx_decl.posmtx); }