SDL: Support 16-bit packed texture formats with the Metal renderer

From 4af4c97e44cac762fd01cc2eb0d712dc49ddb3e7 Mon Sep 17 00:00:00 2001
From: Cameron Cawley <[EMAIL REDACTED]>
Date: Fri, 16 Jan 2026 23:15:50 +0000
Subject: [PATCH] Support 16-bit packed texture formats with the Metal renderer

---
 src/render/metal/SDL_render_metal.m | 46 ++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 36a4b5cc336dd..5c1a3dc2f79dc 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -682,7 +682,7 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
 {
     @autoreleasepool {
         SDL3METAL_RenderData *data = (__bridge SDL3METAL_RenderData *)renderer->internal;
-        MTLPixelFormat pixfmt;
+        MTLPixelFormat pixfmt = MTLPixelFormatInvalid;
         MTLTextureDescriptor *mtltexdesc;
         id<MTLTexture> mtltexture = nil, mtltextureUv = nil;
         SDL3METAL_TextureData *texturedata;
@@ -715,6 +715,26 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
         case SDL_PIXELFORMAT_ABGR2101010:
             pixfmt = MTLPixelFormatRGB10A2Unorm;
             break;
+        case SDL_PIXELFORMAT_RGB565:
+            if (@available(macOS 11.0, *)) {
+                pixfmt = MTLPixelFormatB5G6R5Unorm;
+            }
+            break;
+        case SDL_PIXELFORMAT_RGBA5551:
+            if (@available(macOS 11.0, *)) {
+                pixfmt = MTLPixelFormatA1BGR5Unorm;
+            }
+            break;
+        case SDL_PIXELFORMAT_ARGB1555:
+            if (@available(macOS 11.0, *)) {
+                pixfmt = MTLPixelFormatBGR5A1Unorm;
+            }
+            break;
+        case SDL_PIXELFORMAT_RGBA4444:
+            if (@available(macOS 11.0, *)) {
+                pixfmt = MTLPixelFormatABGR4Unorm;
+            }
+            break;
         case SDL_PIXELFORMAT_INDEX8:
         case SDL_PIXELFORMAT_IYUV:
         case SDL_PIXELFORMAT_YV12:
@@ -732,6 +752,10 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
             pixfmt = MTLPixelFormatRGBA32Float;
             break;
         default:
+            break;
+        }
+
+        if (pixfmt == MTLPixelFormatInvalid) {
             return SDL_SetError("Texture format %s not supported by Metal", SDL_GetPixelFormatName(texture->format));
         }
 
@@ -1949,6 +1973,18 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
         case MTLPixelFormatRGBA16Float:
             format = SDL_PIXELFORMAT_RGBA64_FLOAT;
             break;
+        case MTLPixelFormatB5G6R5Unorm:
+            format = SDL_PIXELFORMAT_RGB565;
+            break;
+        case MTLPixelFormatA1BGR5Unorm:
+            format = SDL_PIXELFORMAT_RGBA5551;
+            break;
+        case MTLPixelFormatBGR5A1Unorm:
+            format = SDL_PIXELFORMAT_ARGB1555;
+            break;
+        case MTLPixelFormatABGR4Unorm:
+            format = SDL_PIXELFORMAT_RGBA4444;
+            break;
         default:
             SDL_SetError("Unknown framebuffer pixel format");
             return NULL;
@@ -2365,6 +2401,14 @@ in case we want to use it later (recreating the renderer)
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010);
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT);
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA128_FLOAT);
+        if (@available(macOS 11.0, iOS 13.0, tvOS 13.0, *)) {
+            if ([mtldevice supportsFamily:MTLGPUFamilyApple1]) {
+                SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGB565);
+                SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA5551);
+                SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB1555);
+                SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA4444);
+            }
+        }
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
         SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);