From 65360c9dae79c35bc98fe10c75be139ba417238c Mon Sep 17 00:00:00 2001
From: Beyley Cardellio <[EMAIL REDACTED]>
Date: Sun, 20 Sep 2026 12:01:41 -0700
Subject: [PATCH] xr: Return all valid swapchain formats in runtime's
preference (#16352)
---
src/gpu/d3d12/SDL_gpu_d3d12.c | 78 ++++++++--------------------
src/gpu/vulkan/SDL_gpu_vulkan.c | 91 ++++++++-------------------------
test/testgpu_spinning_cube_xr.c | 22 ++++++--
3 files changed, 60 insertions(+), 131 deletions(-)
diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c
index dbccc50ed5e7e..07f948ef2cb40 100644
--- a/src/gpu/d3d12/SDL_gpu_d3d12.c
+++ b/src/gpu/d3d12/SDL_gpu_d3d12.c
@@ -601,27 +601,10 @@ static DXGI_FORMAT SDLToD3D12_TypelessFormat[] = {
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TypelessFormat, SDL_arraysize(SDLToD3D12_TypelessFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
#ifdef HAVE_GPU_OPENXR
-// For XR sRGB format selection - maps DXGI sRGB formats to SDL formats
-typedef struct TextureFormatPair
-{
- DXGI_FORMAT dxgi;
- SDL_GPUTextureFormat sdl;
-} TextureFormatPair;
-
-static TextureFormatPair SDLToD3D12_TextureFormat_SrgbOnly[] = {
- { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB },
- { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB },
- { DXGI_FORMAT_BC1_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB },
- { DXGI_FORMAT_BC2_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB },
- { DXGI_FORMAT_BC3_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB },
- { DXGI_FORMAT_BC7_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB },
-};
-
// Forward declarations for XR helper functions
static bool D3D12_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension);
static XrResult D3D12_INTERNAL_GetXrGraphicsRequirements(XrInstance instance, XrSystemId systemId, D3D_FEATURE_LEVEL *minimumFeatureLevel, LUID *adapter);
static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter);
-static bool D3D12_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 supportedFormatsCount, SDL_GPUTextureFormat *sdlFormat, DXGI_FORMAT *dxgiFormat);
#endif /* HAVE_GPU_OPENXR */
static D3D12_COMPARISON_FUNC SDLToD3D12_CompareOp[] = {
@@ -9019,24 +9002,6 @@ static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, I
IDXGIAdapter1_Release(adapter);
}
}
-
-static bool D3D12_INTERNAL_FindXRSrgbSwapchain(
- int64_t *supportedFormats,
- Uint32 supportedFormatsCount,
- SDL_GPUTextureFormat *sdlFormat,
- DXGI_FORMAT *dxgiFormat)
-{
- for (Uint32 i = 0; i < SDL_arraysize(SDLToD3D12_TextureFormat_SrgbOnly); i++) {
- for (Uint32 j = 0; j < supportedFormatsCount; j++) {
- if (SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi == supportedFormats[j]) {
- *sdlFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].sdl;
- *dxgiFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi;
- return true;
- }
- }
- }
- return false;
-}
#endif /* HAVE_GPU_OPENXR */
static XrResult D3D12_DestroyXRSwapchain(
@@ -9106,38 +9071,37 @@ static SDL_GPUTextureFormat* D3D12_GetXRSwapchainFormats(
return NULL;
}
- // FIXME: For now we're just searching for the optimal format, not all supported formats.
- // FIXME: Expand this search for all SDL_GPU formats!
-
- SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID;
- DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN;
- // The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list
- if (!D3D12_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &dxgiFormat)) {
- // Iterate over all formats the runtime supports
- for (i = 0; i < num_supported_formats && dxgiFormat == DXGI_FORMAT_UNKNOWN; i++) {
- // Iterate over all formats we support
- for (j = 0; j < SDL_arraysize(SDLToD3D12_TextureFormat); j++) {
- // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference
- if (SDLToD3D12_TextureFormat[j] == supported_formats[i]) {
- dxgiFormat = (DXGI_FORMAT)supported_formats[i];
- sdlFormat = j;
- break;
- }
+ SDL_GPUTextureFormat *sdl_formats = SDL_stack_alloc(SDL_GPUTextureFormat, num_supported_formats);
+ uint32_t num_found_formats = 0;
+
+ // Iterate over all formats the runtime supports
+ for (i = 0; i < num_supported_formats; i++) {
+ // Iterate over all formats we support
+ for (j = 0; j < SDL_arraysize(SDLToD3D12_TextureFormat); j++) {
+ if (SDLToD3D12_TextureFormat[j] == supported_formats[i]) {
+ // Add the format match we found, linearly. The output order should match the order of the runtime.
+ sdl_formats[num_found_formats++] = j;
+ break;
}
}
}
SDL_stack_free(supported_formats);
- if (dxgiFormat == DXGI_FORMAT_UNKNOWN) {
+ if (num_found_formats == 0) {
SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL");
+ SDL_stack_free(sdl_formats);
return NULL;
}
- SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2);
- retval[0] = sdlFormat;
- retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID;
- *num_formats = 1;
+ SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat *)SDL_calloc((size_t)num_found_formats + 1, sizeof(SDL_GPUTextureFormat));
+ SDL_memcpy(retval, sdl_formats, sizeof(SDL_GPUTextureFormat) * num_found_formats); // Copy the translated formats
+ retval[num_found_formats] = SDL_GPU_TEXTUREFORMAT_INVALID; // Add a termination for good measure
+
+ *num_formats = num_found_formats;
+
+ SDL_stack_free(supported_formats);
+
return retval;
#else
SDL_SetError("SDL not built with OpenXR support");
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index 51b9980fc6a34..bb463cb05f0ca 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -95,37 +95,6 @@ static VkPresentModeKHR SDLToVK_PresentMode[] = {
VK_PRESENT_MODE_MAILBOX_KHR
};
-// NOTE: this is behind an ifdef guard because without, it would trigger an "unused variable" error when OpenXR support is disabled
-#ifdef HAVE_GPU_OPENXR
-typedef struct TextureFormatPair {
- VkFormat vk;
- SDL_GPUTextureFormat sdl;
-} TextureFormatPair;
-
-static TextureFormatPair SDLToVK_TextureFormat_SrgbOnly[] = {
- {VK_FORMAT_R8G8B8A8_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB},
- {VK_FORMAT_B8G8R8A8_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB},
- {VK_FORMAT_BC1_RGBA_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC2_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC3_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC7_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB},
- {VK_FORMAT_ASTC_4x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB},
- {VK_FORMAT_ASTC_5x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB},
- {VK_FORMAT_ASTC_5x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_6x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_6x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB},
- {VK_FORMAT_ASTC_12x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB},
- {VK_FORMAT_ASTC_12x12_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB},
-};
-#endif // HAVE_GPU_OPENXR
-
static VkFormat SDLToVK_TextureFormat[] = {
VK_FORMAT_UNDEFINED, // INVALID
VK_FORMAT_R8_UNORM, // A8_UNORM
@@ -13126,23 +13095,6 @@ static XrResult VULKAN_DestroyXRSwapchain(
#endif
}
-#ifdef HAVE_GPU_OPENXR
-static bool VULKAN_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 numFormats, SDL_GPUTextureFormat *sdlFormat, int64_t *vkFormat)
-{
- for (Uint32 i = 0; i < SDL_arraysize(SDLToVK_TextureFormat_SrgbOnly); i++) {
- for (Uint32 j = 0; j < numFormats; j++) {
- if (SDLToVK_TextureFormat_SrgbOnly[i].vk == supportedFormats[j]) {
- *sdlFormat = SDLToVK_TextureFormat_SrgbOnly[i].sdl;
- *vkFormat = SDLToVK_TextureFormat_SrgbOnly[i].vk;
- return true;
- }
- }
- }
-
- return false;
-}
-#endif // HAVE_GPU_OPENXR
-
static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats(
SDL_GPURenderer *driverData,
XrSession session,
@@ -13163,38 +13115,37 @@ static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats(
return NULL;
}
- // FIXME: For now we're just searching for the optimal format, not all supported formats.
- // FIXME: Expand this search for all SDL_GPU formats!
-
- SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID;
- int64_t vkFormat = VK_FORMAT_UNDEFINED;
- // The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list
- if (!VULKAN_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &vkFormat)) {
- // Iterate over all formats the runtime supports
- for (i = 0; i < num_supported_formats && vkFormat == VK_FORMAT_UNDEFINED; i++) {
- // Iterate over all formats we support
- for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) {
- // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference
- if (SDLToVK_TextureFormat[j] == supported_formats[i]) {
- vkFormat = supported_formats[i];
- sdlFormat = j;
- break;
- }
+ SDL_GPUTextureFormat *sdl_formats = SDL_stack_alloc(SDL_GPUTextureFormat, num_supported_formats);
+ uint32_t num_found_formats = 0;
+
+ // Iterate over all formats the runtime supports
+ for (i = 0; i < num_supported_formats; i++) {
+ // Iterate over all formats we support
+ for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) {
+ if (SDLToVK_TextureFormat[j] == supported_formats[i]) {
+ // Add the format match we found, linearly. The output order should match the order of the runtime.
+ sdl_formats[num_found_formats++] = j;
+ break;
}
}
}
SDL_stack_free(supported_formats);
- if (vkFormat == VK_FORMAT_UNDEFINED) {
+ if (num_found_formats == 0) {
SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL");
+ SDL_stack_free(sdl_formats);
return NULL;
}
- SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2);
- retval[0] = sdlFormat;
- retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID;
- *num_formats = 1;
+ SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat *)SDL_calloc((size_t)num_found_formats + 1, sizeof(SDL_GPUTextureFormat));
+ SDL_memcpy(retval, sdl_formats, sizeof(SDL_GPUTextureFormat) * num_found_formats); // Copy the translated formats
+ retval[num_found_formats] = SDL_GPU_TEXTUREFORMAT_INVALID; // Add a termination for good measure
+
+ *num_formats = num_found_formats;
+
+ SDL_stack_free(supported_formats);
+
return retval;
#else
SDL_SetError("SDL not built with OpenXR support");
diff --git a/test/testgpu_spinning_cube_xr.c b/test/testgpu_spinning_cube_xr.c
index 01995c34af1a1..975a1c64b2251 100644
--- a/test/testgpu_spinning_cube_xr.c
+++ b/test/testgpu_spinning_cube_xr.c
@@ -185,8 +185,8 @@ typedef struct {
Uint32 image_count;
} VRSwapchain;
-/* Depth buffer format - use D24 for wide compatibility */
-static const SDL_GPUTextureFormat DEPTH_FORMAT = SDL_GPU_TEXTUREFORMAT_D24_UNORM;
+/* Depth buffer format, default to D24, but fall down to D16 if D24 is unsupported on this hardware. */
+static SDL_GPUTextureFormat depth_format = SDL_GPU_TEXTUREFORMAT_D24_UNORM;
static VRSwapchain *vr_swapchains = NULL;
static XrView *xr_views = NULL;
@@ -392,7 +392,7 @@ static bool create_pipeline(SDL_GPUTextureFormat color_format)
.format = color_format
}},
.has_depth_stencil_target = true,
- .depth_stencil_format = DEPTH_FORMAT
+ .depth_stencil_format = depth_format
},
.depth_stencil_state = {
.enable_depth_test = true,
@@ -584,6 +584,15 @@ static bool create_swapchains(void)
/* Use first available format (typically sRGB)
* Note: Could iterate with: while (formats[i] != SDL_GPU_TEXTUREFORMAT_INVALID) */
SDL_GPUTextureFormat swapchain_format = formats[0];
+
+ for (int i = 0; i < num_formats; i++) {
+ // Prefer an 8-bit sRGB format, if available, using the order the runtime wants first.
+ if (formats[i] == SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB || formats[i] == SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB) {
+ swapchain_format = formats[i];
+ break;
+ }
+ }
+
SDL_Log("Using swapchain format: %d (of %d available)", swapchain_format, num_formats);
/* Log all available formats for debugging */
@@ -592,6 +601,11 @@ static bool create_swapchains(void)
}
SDL_free(formats);
+ if (!SDL_GPUTextureSupportsFormat(gpu_device, depth_format, SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
+ // This format is *guarenteed* to be supported.
+ depth_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
+ }
+
for (Uint32 i = 0; i < view_count; i++) {
xr_views[i].type = XR_TYPE_VIEW;
xr_views[i].pose.orientation.w = 1.0f;
@@ -642,7 +656,7 @@ static bool create_swapchains(void)
* for proper z-ordering without requiring XR_KHR_composition_layer_depth. */
SDL_GPUTextureCreateInfo depth_info = {
.type = SDL_GPU_TEXTURETYPE_2D,
- .format = DEPTH_FORMAT,
+ .format = depth_format,
.width = swapchain_info.width,
.height = swapchain_info.height,
.layer_count_or_depth = 1,