Merge commit '411251c6242b04119edc41ce83f09f0714e2d32b' as 'external/SDL'

This commit is contained in:
2026-05-13 17:47:57 +02:00
2245 changed files with 975842 additions and 0 deletions
+3622
View File
File diff suppressed because it is too large Load Diff
+1240
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+97
View File
@@ -0,0 +1,97 @@
#define BlitRS \
"DescriptorTable ( Sampler(s0, space=2), visibility = SHADER_VISIBILITY_PIXEL ),"\
"DescriptorTable ( SRV(t0, space=2), visibility = SHADER_VISIBILITY_PIXEL ),"\
"CBV(b0, space=3, visibility = SHADER_VISIBILITY_PIXEL),"\
struct VertexToPixel
{
float2 tex : TEXCOORD0;
float4 pos : SV_POSITION;
};
cbuffer SourceRegionBuffer : register(b0, space3)
{
float2 UVLeftTop;
float2 UVDimensions;
uint MipLevel;
float LayerOrDepth;
};
Texture2D SourceTexture2D : register(t0, space2);
Texture2DArray SourceTexture2DArray : register(t0, space2);
Texture3D SourceTexture3D : register(t0, space2);
TextureCube SourceTextureCube : register(t0, space2);
TextureCubeArray SourceTextureCubeArray : register(t0, space2);
sampler SourceSampler : register(s0, space2);
[RootSignature(BlitRS)]
VertexToPixel FullscreenVert(uint vI : SV_VERTEXID)
{
float2 inTex = float2((vI << 1) & 2, vI & 2);
VertexToPixel Out = (VertexToPixel)0;
Out.tex = inTex;
Out.pos = float4(inTex * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
return Out;
}
[RootSignature(BlitRS)]
float4 BlitFrom2D(VertexToPixel input) : SV_Target0
{
float2 newCoord = UVLeftTop + UVDimensions * input.tex;
return SourceTexture2D.SampleLevel(SourceSampler, newCoord, MipLevel);
}
[RootSignature(BlitRS)]
float4 BlitFrom2DArray(VertexToPixel input) : SV_Target0
{
float3 newCoord = float3(UVLeftTop + UVDimensions * input.tex, (uint)LayerOrDepth);
return SourceTexture2DArray.SampleLevel(SourceSampler, newCoord, MipLevel);
}
[RootSignature(BlitRS)]
float4 BlitFrom3D(VertexToPixel input) : SV_Target0
{
float3 newCoord = float3(UVLeftTop + UVDimensions * input.tex, LayerOrDepth);
return SourceTexture3D.SampleLevel(SourceSampler, newCoord, MipLevel);
}
[RootSignature(BlitRS)]
float4 BlitFromCube(VertexToPixel input) : SV_Target0
{
// Thanks, Wikipedia! https://en.wikipedia.org/wiki/Cube_mapping
float3 newCoord;
float2 scaledUV = UVLeftTop + UVDimensions * input.tex;
float u = 2.0 * scaledUV.x - 1.0;
float v = 2.0 * scaledUV.y - 1.0;
switch ((uint)LayerOrDepth) {
case 0: newCoord = float3(1.0, -v, -u); break; // POSITIVE X
case 1: newCoord = float3(-1.0, -v, u); break; // NEGATIVE X
case 2: newCoord = float3(u, 1.0, -v); break; // POSITIVE Y
case 3: newCoord = float3(u, -1.0, v); break; // NEGATIVE Y
case 4: newCoord = float3(u, -v, 1.0); break; // POSITIVE Z
case 5: newCoord = float3(-u, -v, -1.0); break; // NEGATIVE Z
default: newCoord = float3(0, 0, 0); break; // silences warning
}
return SourceTextureCube.SampleLevel(SourceSampler, newCoord, MipLevel);
}
[RootSignature(BlitRS)]
float4 BlitFromCubeArray(VertexToPixel input) : SV_Target0
{
// Thanks, Wikipedia! https://en.wikipedia.org/wiki/Cube_mapping
float3 newCoord;
float2 scaledUV = UVLeftTop + UVDimensions * input.tex;
float u = 2.0 * scaledUV.x - 1.0;
float v = 2.0 * scaledUV.y - 1.0;
uint ArrayIndex = (uint)LayerOrDepth / 6;
switch ((uint)LayerOrDepth % 6) {
case 0: newCoord = float3(1.0, -v, -u); break; // POSITIVE X
case 1: newCoord = float3(-1.0, -v, u); break; // NEGATIVE X
case 2: newCoord = float3(u, 1.0, -v); break; // POSITIVE Y
case 3: newCoord = float3(u, -1.0, v); break; // NEGATIVE Y
case 4: newCoord = float3(u, -v, 1.0); break; // POSITIVE Z
case 5: newCoord = float3(-u, -v, -1.0); break; // NEGATIVE Z
default: newCoord = float3(0, 0, 0); break; // silences warning
}
return SourceTextureCubeArray.SampleLevel(SourceSampler, float4(newCoord, float(ArrayIndex)), MipLevel);
}
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
rem This script runs for the Windows build, but also via the _xbox variant with these vars set.
rem Make sure to default to building for Windows if they're not set.
if %DXC%.==. set DXC=dxc
if %SUFFIX%.==. set SUFFIX=.h
echo Building with %DXC%
echo Suffix %SUFFIX%
cd "%~dp0"
%DXC% -E FullscreenVert -T vs_6_0 -Fh D3D12_FullscreenVert.h D3D_Blit.hlsl
%DXC% -E BlitFrom2D -T ps_6_0 -Fh D3D12_BlitFrom2D.h D3D_Blit.hlsl
%DXC% -E BlitFrom2DArray -T ps_6_0 -Fh D3D12_BlitFrom2DArray.h D3D_Blit.hlsl
%DXC% -E BlitFrom3D -T ps_6_0 -Fh D3D12_BlitFrom3D.h D3D_Blit.hlsl
%DXC% -E BlitFromCube -T ps_6_0 -Fh D3D12_BlitFromCube.h D3D_Blit.hlsl
%DXC% -E BlitFromCubeArray -T ps_6_0 -Fh D3D12_BlitFromCubeArray.h D3D_Blit.hlsl
copy /b D3D12_FullscreenVert.h+D3D12_BlitFrom2D.h+D3D12_BlitFrom2DArray.h+D3D12_BlitFrom3D.h+D3D12_BlitFromCube.h+D3D12_BlitFromCubeArray.h D3D12_Blit%SUFFIX%
del D3D12_FullscreenVert.h D3D12_BlitFrom2D.h D3D12_BlitFrom2DArray.h D3D12_BlitFrom3D.h D3D12_BlitFromCube.h D3D12_BlitFromCubeArray.h
+13
View File
@@ -0,0 +1,13 @@
if %2.==one. goto setxboxone
rem Xbox Series compile
set DXC="%GameDKLatest%\GXDK\bin\Scarlett\DXC.exe"
set SUFFIX=_Series.h
goto startbuild
:setxboxone
set DXC="%GameDKLatest%\GXDK\bin\XboxOne\DXC.exe"
set SUFFIX=_One.h
:startbuild
call "%~dp0\compile_shaders.bat"
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
#include <metal_stdlib>
using namespace metal;
struct VertexToFragment {
float2 tex;
float4 pos [[position]];
};
struct SourceRegion {
float2 UVLeftTop;
float2 UVDimensions;
uint MipLevel;
float LayerOrDepth;
};
#if COMPILE_FullscreenVert
vertex VertexToFragment FullscreenVert(uint vI [[vertex_id]]) {
float2 inTex = float2((vI << 1) & 2, vI & 2);
VertexToFragment out;
out.tex = inTex;
out.pos = float4(inTex * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
return out;
}
#endif
#if COMPILE_BlitFrom2D
fragment float4 BlitFrom2D(
VertexToFragment input [[stage_in]],
constant SourceRegion &sourceRegion [[buffer(0)]],
texture2d<float> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]])
{
float2 newCoord = sourceRegion.UVLeftTop + sourceRegion.UVDimensions * input.tex;
return sourceTexture.sample(sourceSampler, newCoord, level(sourceRegion.MipLevel));
}
#endif
#if COMPILE_BlitFrom2DArray
fragment float4 BlitFrom2DArray(
VertexToFragment input [[stage_in]],
constant SourceRegion &sourceRegion [[buffer(0)]],
texture2d_array<float> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]])
{
float2 newCoord = sourceRegion.UVLeftTop + sourceRegion.UVDimensions * input.tex;
return sourceTexture.sample(sourceSampler, newCoord, (uint)sourceRegion.LayerOrDepth, level(sourceRegion.MipLevel));
}
#endif
#if COMPILE_BlitFrom3D
fragment float4 BlitFrom3D(
VertexToFragment input [[stage_in]],
constant SourceRegion &sourceRegion [[buffer(0)]],
texture3d<float> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]])
{
float2 newCoord = sourceRegion.UVLeftTop + sourceRegion.UVDimensions * input.tex;
return sourceTexture.sample(sourceSampler, float3(newCoord, sourceRegion.LayerOrDepth), level(sourceRegion.MipLevel));
}
#endif
#if COMPILE_BlitFromCube
fragment float4 BlitFromCube(
VertexToFragment input [[stage_in]],
constant SourceRegion &sourceRegion [[buffer(0)]],
texturecube<float> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]])
{
// Thanks, Wikipedia! https://en.wikipedia.org/wiki/Cube_mapping
float2 scaledUV = sourceRegion.UVLeftTop + sourceRegion.UVDimensions * input.tex;
float u = 2.0 * scaledUV.x - 1.0;
float v = 2.0 * scaledUV.y - 1.0;
float3 newCoord;
switch ((uint)sourceRegion.LayerOrDepth) {
case 0: newCoord = float3(1.0, -v, -u); break; // POSITIVE X
case 1: newCoord = float3(-1.0, -v, u); break; // NEGATIVE X
case 2: newCoord = float3(u, 1.0, -v); break; // POSITIVE Y
case 3: newCoord = float3(u, -1.0, v); break; // NEGATIVE Y
case 4: newCoord = float3(u, -v, 1.0); break; // POSITIVE Z
case 5: newCoord = float3(-u, -v, -1.0); break; // NEGATIVE Z
default: newCoord = float3(0, 0, 0); break; // silences warning
}
return sourceTexture.sample(sourceSampler, newCoord, level(sourceRegion.MipLevel));
}
#endif
#if COMPILE_BlitFromCubeArray
fragment float4 BlitFromCubeArray(
VertexToFragment input [[stage_in]],
constant SourceRegion &sourceRegion [[buffer(0)]],
texturecube_array<float> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]])
{
// Thanks, Wikipedia! https://en.wikipedia.org/wiki/Cube_mapping
float2 scaledUV = sourceRegion.UVLeftTop + sourceRegion.UVDimensions * input.tex;
float u = 2.0 * scaledUV.x - 1.0;
float v = 2.0 * scaledUV.y - 1.0;
float3 newCoord;
switch (((uint)sourceRegion.LayerOrDepth) % 6) {
case 0: newCoord = float3(1.0, -v, -u); break; // POSITIVE X
case 1: newCoord = float3(-1.0, -v, u); break; // NEGATIVE X
case 2: newCoord = float3(u, 1.0, -v); break; // POSITIVE Y
case 3: newCoord = float3(u, -1.0, v); break; // NEGATIVE Y
case 4: newCoord = float3(u, -v, 1.0); break; // POSITIVE Z
case 5: newCoord = float3(-u, -v, -1.0); break; // NEGATIVE Z
default: newCoord = float3(0, 0, 0); break; // silences warning
}
return sourceTexture.sample(sourceSampler, newCoord, (uint)sourceRegion.LayerOrDepth / 6, level(sourceRegion.MipLevel));
}
#endif
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
#!/bin/bash
set -x
set -e
cd `dirname "$0"`
shadernames=(FullscreenVert BlitFrom2D BlitFrom2DArray BlitFrom3D BlitFromCube BlitFromCubeArray)
generate_shaders()
{
fileplatform=$1
compileplatform=$2
sdkplatform=$3
minversion=$4
for shadername in "${shadernames[@]}"; do
xcrun -sdk $sdkplatform metal -c -std=$compileplatform-metal2.0 -m$sdkplatform-version-min=$minversion -Wall -O3 -D COMPILE_$shadername -o ./$shadername.air ./Metal_Blit.metal || exit $?
xcrun -sdk $sdkplatform metallib -o $shadername.metallib $shadername.air || exit $?
xxd -i $shadername.metallib | perl -w -p -e 's/\Aunsigned /const unsigned /;' >./${shadername}_$fileplatform.h
rm -f $shadername.air $shadername.metallib
done
}
generate_shaders macos macos macosx 10.11
generate_shaders ios ios iphoneos 11.0
generate_shaders iphonesimulator ios iphonesimulator 11.0
generate_shaders tvos ios appletvos 11.0
generate_shaders tvsimulator ios appletvsimulator 11.0
# Bundle together one mega-header
catShaders()
{
target=$1
for shadername in "${shadernames[@]}"; do
cat ${shadername}_$target.h >> Metal_Blit.h
done
}
rm -f Metal_Blit.h
echo "#if defined(SDL_PLATFORM_IOS)" >> Metal_Blit.h
echo "#if TARGET_OS_SIMULATOR" >> Metal_Blit.h
catShaders iphonesimulator
echo "#else" >> Metal_Blit.h
catShaders ios
echo "#endif" >> Metal_Blit.h
echo "#elif defined(SDL_PLATFORM_TVOS)" >> Metal_Blit.h
echo "#if TARGET_OS_SIMULATOR" >> Metal_Blit.h
catShaders tvsimulator
echo "#else" >> Metal_Blit.h
catShaders tvos
echo "#endif" >> Metal_Blit.h
echo "#else" >> Metal_Blit.h
catShaders macos
echo "#endif" >> Metal_Blit.h
# Clean up
cleanupShaders()
{
target=$1
for shadername in "${shadernames[@]}"; do
rm -f ${shadername}_$target.h
done
}
cleanupShaders iphonesimulator
cleanupShaders ios
cleanupShaders tvsimulator
cleanupShaders tvos
cleanupShaders macos
File diff suppressed because it is too large Load Diff
+179
View File
@@ -0,0 +1,179 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* Global functions from the Vulkan Loader
*/
#ifndef VULKAN_GLOBAL_FUNCTION
#define VULKAN_GLOBAL_FUNCTION(name)
#endif
VULKAN_GLOBAL_FUNCTION(vkCreateInstance)
VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties)
VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties)
/*
* vkInstance, created by global vkCreateInstance function
*/
#ifndef VULKAN_INSTANCE_FUNCTION
#define VULKAN_INSTANCE_FUNCTION(name)
#endif
// Vulkan 1.0
VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr)
VULKAN_INSTANCE_FUNCTION(vkCreateDevice)
VULKAN_INSTANCE_FUNCTION(vkDestroyInstance)
VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties)
VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)
// Vulkan 1.1 (Needed for opt-in feature checks)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures2)
// VK_KHR_get_physical_device_properties2, needed for KHR_driver_properties
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2KHR)
// VK_KHR_surface
VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)
// VK_EXT_debug_utils
VULKAN_INSTANCE_FUNCTION(vkCmdBeginDebugUtilsLabelEXT)
VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectNameEXT)
VULKAN_INSTANCE_FUNCTION(vkCmdEndDebugUtilsLabelEXT)
VULKAN_INSTANCE_FUNCTION(vkCmdInsertDebugUtilsLabelEXT)
/*
* vkDevice, created by a vkInstance
*/
#ifndef VULKAN_DEVICE_FUNCTION
#define VULKAN_DEVICE_FUNCTION(name)
#endif
// Vulkan 1.0
VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers)
VULKAN_DEVICE_FUNCTION(vkAllocateDescriptorSets)
VULKAN_DEVICE_FUNCTION(vkAllocateMemory)
VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer)
VULKAN_DEVICE_FUNCTION(vkBindBufferMemory)
VULKAN_DEVICE_FUNCTION(vkBindImageMemory)
VULKAN_DEVICE_FUNCTION(vkCmdBeginRenderPass)
VULKAN_DEVICE_FUNCTION(vkCmdBindDescriptorSets)
VULKAN_DEVICE_FUNCTION(vkCmdBindIndexBuffer)
VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline)
VULKAN_DEVICE_FUNCTION(vkCmdBindVertexBuffers)
VULKAN_DEVICE_FUNCTION(vkCmdBlitImage)
VULKAN_DEVICE_FUNCTION(vkCmdClearAttachments)
VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage)
VULKAN_DEVICE_FUNCTION(vkCmdClearDepthStencilImage)
VULKAN_DEVICE_FUNCTION(vkCmdCopyBuffer)
VULKAN_DEVICE_FUNCTION(vkCmdCopyImage)
VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage)
VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer)
VULKAN_DEVICE_FUNCTION(vkCmdDispatch)
VULKAN_DEVICE_FUNCTION(vkCmdDispatchIndirect)
VULKAN_DEVICE_FUNCTION(vkCmdDraw)
VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexed)
VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexedIndirect)
VULKAN_DEVICE_FUNCTION(vkCmdDrawIndirect)
VULKAN_DEVICE_FUNCTION(vkCmdEndRenderPass)
VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier)
VULKAN_DEVICE_FUNCTION(vkCmdResolveImage)
VULKAN_DEVICE_FUNCTION(vkCmdSetBlendConstants)
VULKAN_DEVICE_FUNCTION(vkCmdSetDepthBias)
VULKAN_DEVICE_FUNCTION(vkCmdSetScissor)
VULKAN_DEVICE_FUNCTION(vkCmdSetStencilReference)
VULKAN_DEVICE_FUNCTION(vkCmdSetViewport)
VULKAN_DEVICE_FUNCTION(vkCreateBuffer)
VULKAN_DEVICE_FUNCTION(vkCreateCommandPool)
VULKAN_DEVICE_FUNCTION(vkCreateDescriptorPool)
VULKAN_DEVICE_FUNCTION(vkCreateDescriptorSetLayout)
VULKAN_DEVICE_FUNCTION(vkCreateFence)
VULKAN_DEVICE_FUNCTION(vkCreateFramebuffer)
VULKAN_DEVICE_FUNCTION(vkCreateComputePipelines)
VULKAN_DEVICE_FUNCTION(vkCreateGraphicsPipelines)
VULKAN_DEVICE_FUNCTION(vkCreateImage)
VULKAN_DEVICE_FUNCTION(vkCreateImageView)
VULKAN_DEVICE_FUNCTION(vkCreatePipelineCache)
VULKAN_DEVICE_FUNCTION(vkCreatePipelineLayout)
VULKAN_DEVICE_FUNCTION(vkCreateRenderPass)
VULKAN_DEVICE_FUNCTION(vkCreateSampler)
VULKAN_DEVICE_FUNCTION(vkCreateSemaphore)
VULKAN_DEVICE_FUNCTION(vkCreateShaderModule)
VULKAN_DEVICE_FUNCTION(vkDestroyBuffer)
VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool)
VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorPool)
VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout)
VULKAN_DEVICE_FUNCTION(vkDestroyDevice)
VULKAN_DEVICE_FUNCTION(vkDestroyFence)
VULKAN_DEVICE_FUNCTION(vkDestroyFramebuffer)
VULKAN_DEVICE_FUNCTION(vkDestroyImage)
VULKAN_DEVICE_FUNCTION(vkDestroyImageView)
VULKAN_DEVICE_FUNCTION(vkDestroyPipeline)
VULKAN_DEVICE_FUNCTION(vkDestroyPipelineCache)
VULKAN_DEVICE_FUNCTION(vkDestroyPipelineLayout)
VULKAN_DEVICE_FUNCTION(vkDestroyRenderPass)
VULKAN_DEVICE_FUNCTION(vkDestroySampler)
VULKAN_DEVICE_FUNCTION(vkDestroySemaphore)
VULKAN_DEVICE_FUNCTION(vkDestroyShaderModule)
VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle)
VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer)
VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers)
VULKAN_DEVICE_FUNCTION(vkFreeMemory)
VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue)
VULKAN_DEVICE_FUNCTION(vkGetPipelineCacheData)
VULKAN_DEVICE_FUNCTION(vkGetFenceStatus)
VULKAN_DEVICE_FUNCTION(vkGetBufferMemoryRequirements)
VULKAN_DEVICE_FUNCTION(vkGetImageMemoryRequirements)
VULKAN_DEVICE_FUNCTION(vkMapMemory)
VULKAN_DEVICE_FUNCTION(vkQueueSubmit)
VULKAN_DEVICE_FUNCTION(vkQueueWaitIdle)
VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer)
VULKAN_DEVICE_FUNCTION(vkResetCommandPool)
VULKAN_DEVICE_FUNCTION(vkResetDescriptorPool)
VULKAN_DEVICE_FUNCTION(vkResetFences)
VULKAN_DEVICE_FUNCTION(vkUnmapMemory)
VULKAN_DEVICE_FUNCTION(vkUpdateDescriptorSets)
VULKAN_DEVICE_FUNCTION(vkWaitForFences)
// VK_KHR_swapchain
VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR)
VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR)
VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR)
VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR)
VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR)
/*
* Redefine these every time you include this header!
*/
#undef VULKAN_GLOBAL_FUNCTION
#undef VULKAN_INSTANCE_FUNCTION
#undef VULKAN_DEVICE_FUNCTION
+205
View File
@@ -0,0 +1,205 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef HAVE_GPU_OPENXR
#include "SDL_gpu_openxr.h"
#ifdef SDL_PLATFORM_ANDROID
#include "../../core/android/SDL_android.h"
#endif
#define VALIDATION_LAYER_API_NAME "XR_APILAYER_LUNARG_core_validation"
/* On Android, the OpenXR loader is initialized by SDL_OpenXR_LoadLibrary() in SDL_openxrdyn.c
* which must be called before this. That function handles the complex initialization using
* direct SDL_LoadFunction calls to avoid issues with xrGetInstanceProcAddr from runtime
* negotiation not supporting pre-instance calls. This stub is kept for API compatibility. */
#ifdef SDL_PLATFORM_ANDROID
static bool SDL_OPENXR_INTERNAL_InitializeAndroidLoader(void)
{
/* The loader should already be initialized by SDL_OpenXR_LoadLibrary().
* We just verify that xrGetInstanceProcAddr is available. */
if (xrGetInstanceProcAddr == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetInstanceProcAddr is NULL - SDL_OpenXR_LoadLibrary was not called first");
return false;
}
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Android OpenXR loader verified (was initialized by SDL_OpenXR_LoadLibrary)");
return true;
}
#endif /* SDL_PLATFORM_ANDROID */
static bool SDL_OPENXR_INTERNAL_ValidationLayerAvailable(void)
{
#ifdef SDL_PLATFORM_ANDROID
/* On Android/Quest, the xrGetInstanceProcAddr obtained through runtime negotiation
* crashes when used for pre-instance global functions. Skip validation layer check. */
return false;
#else
Uint32 apiLayerCount;
if (XR_FAILED(xrEnumerateApiLayerProperties(0, &apiLayerCount, NULL))) {
return false;
}
if (apiLayerCount <= 0) {
return false;
}
XrApiLayerProperties *apiLayerProperties = SDL_stack_alloc(XrApiLayerProperties, apiLayerCount);
if (XR_FAILED(xrEnumerateApiLayerProperties(apiLayerCount, &apiLayerCount, apiLayerProperties))) {
SDL_stack_free(apiLayerProperties);
return false;
}
bool found = false;
for (Uint32 i = 0; i < apiLayerCount; i++) {
XrApiLayerProperties apiLayer = apiLayerProperties[i];
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "api layer available: %s", apiLayer.layerName);
if (SDL_strcmp(apiLayer.layerName, VALIDATION_LAYER_API_NAME) == 0) {
found = true;
break;
}
}
SDL_stack_free(apiLayerProperties);
return found;
#endif
}
XrResult SDL_OPENXR_INTERNAL_GPUInitOpenXR(
bool debugMode,
XrExtensionProperties gpuExtension,
SDL_PropertiesID props,
XrInstance *instance,
XrSystemId *systemId,
XrInstancePfns **xr)
{
XrResult xrResult;
#ifdef SDL_PLATFORM_ANDROID
// Android requires loader initialization before any other XR calls
if (!SDL_OPENXR_INTERNAL_InitializeAndroidLoader()) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to initialize Android OpenXR loader");
return XR_ERROR_INITIALIZATION_FAILED;
}
#endif
bool validationLayersAvailable = SDL_OPENXR_INTERNAL_ValidationLayerAvailable();
Uint32 userApiLayerCount = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_COUNT_NUMBER, 0);
const char *const *userApiLayerNames = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_NAMES_POINTER, NULL);
Uint32 userExtensionCount = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_COUNT_NUMBER, 0);
const char *const *userExtensionNames = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_NAMES_POINTER, NULL);
// allocate enough space for the validation layer + the user's api layers
const char **apiLayerNames = SDL_stack_alloc(const char *, userApiLayerCount + 1);
SDL_memcpy((void *)apiLayerNames, userApiLayerNames, sizeof(const char *) * (userApiLayerCount));
apiLayerNames[userApiLayerCount] = VALIDATION_LAYER_API_NAME;
// On Android, we need an extra extension for android_create_instance
#ifdef SDL_PLATFORM_ANDROID
const Uint32 platformExtensionCount = 2; // GPU extension + Android create instance
#else
const Uint32 platformExtensionCount = 1; // GPU extension only
#endif
const char **extensionNames = SDL_stack_alloc(const char *, userExtensionCount + platformExtensionCount);
SDL_memcpy((void *)extensionNames, userExtensionNames, sizeof(const char *) * (userExtensionCount));
extensionNames[userExtensionCount] = gpuExtension.extensionName;
#ifdef SDL_PLATFORM_ANDROID
extensionNames[userExtensionCount + 1] = XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME;
#endif
XrInstanceCreateInfo xrInstanceCreateInfo;
SDL_zero(xrInstanceCreateInfo);
xrInstanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
xrInstanceCreateInfo.applicationInfo.apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0);
xrInstanceCreateInfo.enabledApiLayerCount = userApiLayerCount + ((debugMode && validationLayersAvailable) ? 1 : 0); // in debug mode, we enable the validation layer
xrInstanceCreateInfo.enabledApiLayerNames = apiLayerNames;
xrInstanceCreateInfo.enabledExtensionCount = userExtensionCount + platformExtensionCount;
xrInstanceCreateInfo.enabledExtensionNames = extensionNames;
#ifdef SDL_PLATFORM_ANDROID
// Get JNI environment and JavaVM for Android instance creation
JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv();
JavaVM *vm = NULL;
if (env) {
(*env)->GetJavaVM(env, &vm);
}
void *activity = SDL_GetAndroidActivity();
XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {};
instanceCreateInfoAndroid.type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR;
instanceCreateInfoAndroid.applicationVM = vm;
instanceCreateInfoAndroid.applicationActivity = activity;
xrInstanceCreateInfo.next = &instanceCreateInfoAndroid;
#endif
const char *applicationName = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_NAME_STRING, "SDL Application");
Uint32 applicationVersion = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_VERSION_NUMBER, 0);
SDL_strlcpy(xrInstanceCreateInfo.applicationInfo.applicationName, applicationName, XR_MAX_APPLICATION_NAME_SIZE);
xrInstanceCreateInfo.applicationInfo.applicationVersion = applicationVersion;
const char *engineName = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_NAME_STRING, "SDLGPU");
uint32_t engineVersion = (uint32_t)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_VERSION_NUMBER, SDL_VERSION);
SDL_strlcpy(xrInstanceCreateInfo.applicationInfo.engineName, engineName, XR_MAX_APPLICATION_NAME_SIZE);
xrInstanceCreateInfo.applicationInfo.engineVersion = engineVersion;
if ((xrResult = xrCreateInstance(&xrInstanceCreateInfo, instance)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance");
SDL_stack_free(apiLayerNames);
SDL_stack_free(extensionNames);
return false;
}
SDL_stack_free(apiLayerNames);
SDL_stack_free(extensionNames);
*xr = SDL_OPENXR_LoadInstanceSymbols(*instance);
if (!*xr) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load required OpenXR instance symbols");
/* NOTE: we can't actually destroy the created OpenXR instance here,
as we only get that function pointer by loading the instance symbols...
let's just hope that doesn't happen. */
return false;
}
XrSystemGetInfo systemGetInfo;
SDL_zero(systemGetInfo);
systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
systemGetInfo.formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY);
if ((xrResult = (*xr)->xrGetSystem(*instance, &systemGetInfo, systemId)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system");
(*xr)->xrDestroyInstance(*instance);
SDL_free(*xr);
return false;
}
return true;
}
#endif /* HAVE_GPU_OPENXR */
+30
View File
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_openxrdyn.h"
XrResult SDL_OPENXR_INTERNAL_GPUInitOpenXR(
bool debugMode,
XrExtensionProperties gpuExtension,
SDL_PropertiesID props,
XrInstance *instance,
XrSystemId *systemId,
XrInstancePfns **xr);
+52
View File
@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* This internal header provides access to the vendored OpenXR headers
* without requiring include path modifications in project files.
* Similar to SDL_vulkan_internal.h for Vulkan headers.
*/
#ifndef SDL_openxr_internal_h_
#define SDL_openxr_internal_h_
#include "SDL_internal.h"
/* Define platform-specific OpenXR macros BEFORE including openxr headers */
#ifdef SDL_PLATFORM_ANDROID
#include <jni.h>
#define XR_USE_PLATFORM_ANDROID
#endif
/* Include the vendored OpenXR headers using relative path */
#include "../../video/khronos/openxr/openxr.h"
#include "../../video/khronos/openxr/openxr_platform.h"
/* Compatibility: XR_API_VERSION_1_0 was added in OpenXR 1.1.x */
#ifndef XR_API_VERSION_1_0
#define XR_API_VERSION_1_0 XR_MAKE_VERSION(1, 0, XR_VERSION_PATCH(XR_CURRENT_API_VERSION))
#endif
#define SDL_OPENXR_CHECK_VERSION(x, y, z) \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) > x || \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) == x && XR_VERSION_MINOR(XR_CURRENT_API_VERSION) > y) || \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) == x && XR_VERSION_MINOR(XR_CURRENT_API_VERSION) == y && XR_VERSION_PATCH(XR_CURRENT_API_VERSION) >= z))
#endif /* SDL_openxr_internal_h_ */
+417
View File
@@ -0,0 +1,417 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_openxrdyn.h"
#ifdef HAVE_GPU_OPENXR
#include <SDL3/SDL_dlopennote.h>
#include <SDL3/SDL_openxr.h>
#if defined(SDL_PLATFORM_APPLE)
static const char *openxr_library_names[] = { "libopenxr_loader.dylib", NULL };
#elif defined(SDL_PLATFORM_WINDOWS)
static const char *openxr_library_names[] = { "openxr_loader.dll", NULL };
#elif defined(SDL_PLATFORM_ANDROID)
/* On Android, use the Khronos OpenXR loader (libopenxr_loader.so) which properly
* exports xrGetInstanceProcAddr. This is bundled via the Gradle dependency:
* implementation 'org.khronos.openxr:openxr_loader_for_android:X.Y.Z'
*
* The Khronos loader handles runtime discovery internally via the Android broker
* pattern and properly supports all pre-instance global functions.
*
* Note: Do NOT use Meta's forwardloader (libopenxr_forwardloader.so) - it doesn't
* export xrGetInstanceProcAddr directly and the function obtained via runtime
* negotiation crashes on pre-instance calls (e.g., xrEnumerateApiLayerProperties). */
static const char *openxr_library_names[] = { "libopenxr_loader.so", NULL };
#else
static const char *openxr_library_names[] = { "libopenxr_loader.so.1", NULL };
SDL_ELF_NOTE_DLOPEN(
"gpu-openxr",
"Support for OpenXR with SDL_GPU rendering",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libopenxr_loader.so.1"
)
#endif
#define DEBUG_DYNAMIC_OPENXR 0
typedef struct
{
SDL_SharedObject *lib;
} openxrdynlib;
static openxrdynlib openxr_loader = { NULL };
#ifndef SDL_PLATFORM_ANDROID
static void *OPENXR_GetSym(const char *fnname, bool *failed)
{
void *fn = SDL_LoadFunction(openxr_loader.lib, fnname);
#if DEBUG_DYNAMIC_OPENXR
if (fn) {
SDL_Log("OPENXR: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn);
} else {
SDL_Log("OPENXR: Symbol '%s' NOT FOUND!\n", fnname);
}
#endif
return fn;
}
#endif
// Define all the function pointers and wrappers...
#define SDL_OPENXR_SYM(name) PFN_##name OPENXR_##name = NULL;
#include "SDL_openxrsym.h"
static int openxr_load_refcount = 0;
#ifdef SDL_PLATFORM_ANDROID
#include <jni.h>
#include "../../video/khronos/openxr/openxr_platform.h"
/* On Android, we need to initialize the loader with JNI context before use */
static bool openxr_android_loader_initialized = false;
static bool OPENXR_InitializeAndroidLoader(void)
{
XrResult result;
PFN_xrInitializeLoaderKHR initializeLoader = NULL;
PFN_xrGetInstanceProcAddr loaderGetProcAddr = NULL;
JNIEnv *env = NULL;
JavaVM *vm = NULL;
jobject activity = NULL;
if (openxr_android_loader_initialized) {
return true;
}
/* The Khronos OpenXR loader (libopenxr_loader.so) properly exports xrGetInstanceProcAddr.
* Get it directly from the library - this is the standard approach. */
loaderGetProcAddr = (PFN_xrGetInstanceProcAddr)SDL_LoadFunction(openxr_loader.lib, "xrGetInstanceProcAddr");
if (loaderGetProcAddr == NULL) {
SDL_SetError("Failed to get xrGetInstanceProcAddr from OpenXR loader. "
"Make sure you're using the Khronos loader (libopenxr_loader.so), "
"not Meta's forwardloader.");
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Got xrGetInstanceProcAddr from loader: %p", (void*)loaderGetProcAddr);
#endif
/* Get xrInitializeLoaderKHR via xrGetInstanceProcAddr */
result = loaderGetProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&initializeLoader);
if (XR_FAILED(result) || initializeLoader == NULL) {
SDL_SetError("Failed to get xrInitializeLoaderKHR (result: %d)", (int)result);
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Got xrInitializeLoaderKHR: %p", (void*)initializeLoader);
#endif
/* Get Android environment info from SDL */
env = (JNIEnv *)SDL_GetAndroidJNIEnv();
if (!env) {
SDL_SetError("Failed to get Android JNI environment");
return false;
}
if ((*env)->GetJavaVM(env, &vm) != 0) {
SDL_SetError("Failed to get JavaVM from JNIEnv");
return false;
}
activity = (jobject)SDL_GetAndroidActivity();
if (!activity) {
SDL_SetError("Failed to get Android activity");
return false;
}
XrLoaderInitInfoAndroidKHR loaderInitInfo = {
.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR,
.next = NULL,
.applicationVM = vm,
.applicationContext = activity
};
result = initializeLoader((XrLoaderInitInfoBaseHeaderKHR *)&loaderInitInfo);
if (XR_FAILED(result)) {
SDL_SetError("xrInitializeLoaderKHR failed with result %d", (int)result);
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: xrInitializeLoaderKHR succeeded");
#endif
/* Store the xrGetInstanceProcAddr function - this one properly handles
* all pre-instance calls (unlike Meta's forwardloader runtime negotiation) */
OPENXR_xrGetInstanceProcAddr = loaderGetProcAddr;
xrGetInstanceProcAddr = loaderGetProcAddr;
openxr_android_loader_initialized = true;
return true;
}
#endif /* SDL_PLATFORM_ANDROID */
SDL_DECLSPEC void SDLCALL SDL_OpenXR_UnloadLibrary(void)
{
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: UnloadLibrary called, current refcount=%d", openxr_load_refcount);
#endif
// Don't actually unload if more than one module is using the libs...
if (openxr_load_refcount > 0) {
if (--openxr_load_refcount == 0) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Refcount reached 0, unloading library");
#endif
#ifdef SDL_PLATFORM_ANDROID
/* On Android/Quest, don't actually unload the library or reset the loader state.
* The Quest OpenXR runtime doesn't support being re-initialized after teardown.
* xrInitializeLoaderKHR and xrNegotiateLoaderRuntimeInterface must only be called once.
* We keep the library loaded and the loader initialized.
*
* IMPORTANT: We also keep xrGetInstanceProcAddr intact so we can reload other
* function pointers on the next LoadLibrary call. Only NULL out the other symbols. */
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Android - keeping library loaded and loader initialized");
#endif
// Only NULL out non-essential function pointers, keep xrGetInstanceProcAddr
#define SDL_OPENXR_SYM(name) \
if (SDL_strcmp(#name, "xrGetInstanceProcAddr") != 0) { \
OPENXR_##name = NULL; \
}
#include "SDL_openxrsym.h"
#else
// On non-Android, NULL everything and unload
#define SDL_OPENXR_SYM(name) OPENXR_##name = NULL;
#include "SDL_openxrsym.h"
SDL_UnloadObject(openxr_loader.lib);
openxr_loader.lib = NULL;
#endif
}
#if DEBUG_DYNAMIC_OPENXR
else {
SDL_Log("SDL/OpenXR: Refcount is now %d, not unloading", openxr_load_refcount);
}
#endif
}
}
// returns non-zero if all needed symbols were loaded.
SDL_DECLSPEC bool SDLCALL SDL_OpenXR_LoadLibrary(void)
{
bool result = true;
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: LoadLibrary called, current refcount=%d, lib=%p", openxr_load_refcount, (void*)openxr_loader.lib);
#endif
// deal with multiple modules (gpu, openxr, etc) needing these symbols...
if (openxr_load_refcount++ == 0) {
#ifdef SDL_PLATFORM_ANDROID
/* On Android, the library may already be loaded if this is a reload after
* unload (we don't actually unload on Android to preserve runtime state) */
if (openxr_loader.lib == NULL) {
#endif
const char *path_hint = SDL_GetHint(SDL_HINT_OPENXR_LIBRARY);
// If a hint was specified, try that first
if (path_hint && *path_hint) {
openxr_loader.lib = SDL_LoadObject(path_hint);
}
// If no hint or hint failed, try the default library names
if (!openxr_loader.lib) {
for (int i = 0; openxr_library_names[i] != NULL; i++) {
openxr_loader.lib = SDL_LoadObject(openxr_library_names[i]);
if (openxr_loader.lib) {
break;
}
}
}
if (!openxr_loader.lib) {
SDL_SetError("Failed to load OpenXR loader library. "
"On Windows, ensure openxr_loader.dll is in your application directory or PATH. "
"On Linux, install the OpenXR loader package (libopenxr-loader) or set LD_LIBRARY_PATH. "
"You can also use the SDL_HINT_OPENXR_LIBRARY hint to specify the loader path.");
openxr_load_refcount--;
return false;
}
#if defined(SDL_PLATFORM_ANDROID)
} else {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Library already loaded (Android reload), skipping SDL_LoadObject");
#endif
}
#endif
#ifdef SDL_PLATFORM_ANDROID
/* On Android, we need to initialize the loader before other functions work.
* OPENXR_InitializeAndroidLoader() will return early if already initialized. */
if (!OPENXR_InitializeAndroidLoader()) {
SDL_UnloadObject(openxr_loader.lib);
openxr_loader.lib = NULL;
openxr_load_refcount--;
return false;
}
#endif
bool failed = false;
#ifdef SDL_PLATFORM_ANDROID
/* On Android with Meta's forwardloader, we need special handling.
* After calling xrInitializeLoaderKHR, the global functions should be available
* either as direct exports from the forwardloader or via xrGetInstanceProcAddr(NULL, ...).
*
* Try getting functions directly from the forwardloader first since they'll go
* through the proper forwarding path. */
XrResult xrResult;
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Loading global functions...");
#endif
/* First try to get functions directly from the forwardloader library */
OPENXR_xrEnumerateApiLayerProperties = (PFN_xrEnumerateApiLayerProperties)SDL_LoadFunction(openxr_loader.lib, "xrEnumerateApiLayerProperties");
OPENXR_xrCreateInstance = (PFN_xrCreateInstance)SDL_LoadFunction(openxr_loader.lib, "xrCreateInstance");
OPENXR_xrEnumerateInstanceExtensionProperties = (PFN_xrEnumerateInstanceExtensionProperties)SDL_LoadFunction(openxr_loader.lib, "xrEnumerateInstanceExtensionProperties");
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Direct symbols - xrEnumerateApiLayerProperties=%p, xrCreateInstance=%p, xrEnumerateInstanceExtensionProperties=%p",
(void*)OPENXR_xrEnumerateApiLayerProperties,
(void*)OPENXR_xrCreateInstance,
(void*)OPENXR_xrEnumerateInstanceExtensionProperties);
#endif
/* If direct loading failed, fall back to xrGetInstanceProcAddr(NULL, ...) */
if (OPENXR_xrEnumerateApiLayerProperties == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateApiLayerProperties", (PFN_xrVoidFunction*)&OPENXR_xrEnumerateApiLayerProperties);
if (XR_FAILED(xrResult) || OPENXR_xrEnumerateApiLayerProperties == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrEnumerateApiLayerProperties via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
if (OPENXR_xrCreateInstance == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrCreateInstance", (PFN_xrVoidFunction*)&OPENXR_xrCreateInstance);
if (XR_FAILED(xrResult) || OPENXR_xrCreateInstance == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrCreateInstance via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
if (OPENXR_xrEnumerateInstanceExtensionProperties == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties", (PFN_xrVoidFunction*)&OPENXR_xrEnumerateInstanceExtensionProperties);
if (XR_FAILED(xrResult) || OPENXR_xrEnumerateInstanceExtensionProperties == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrEnumerateInstanceExtensionProperties via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Final symbols - xrEnumerateApiLayerProperties=%p, xrCreateInstance=%p, xrEnumerateInstanceExtensionProperties=%p",
(void*)OPENXR_xrEnumerateApiLayerProperties,
(void*)OPENXR_xrCreateInstance,
(void*)OPENXR_xrEnumerateInstanceExtensionProperties);
SDL_Log("SDL/OpenXR: Global functions loading %s", failed ? "FAILED" : "succeeded");
#endif
#else
#define SDL_OPENXR_SYM(name) OPENXR_##name = (PFN_##name)OPENXR_GetSym(#name, &failed);
#include "SDL_openxrsym.h"
#endif
if (failed) {
// in case something got loaded...
SDL_OpenXR_UnloadLibrary();
result = false;
}
}
#if DEBUG_DYNAMIC_OPENXR
else {
SDL_Log("SDL/OpenXR: Library already loaded (refcount=%d), skipping", openxr_load_refcount);
}
#endif
return result;
}
SDL_DECLSPEC PFN_xrGetInstanceProcAddr SDLCALL SDL_OpenXR_GetXrGetInstanceProcAddr(void)
{
if (xrGetInstanceProcAddr == NULL) {
SDL_SetError("The OpenXR loader has not been loaded");
}
return xrGetInstanceProcAddr;
}
XrInstancePfns *SDL_OPENXR_LoadInstanceSymbols(XrInstance instance)
{
XrResult result;
XrInstancePfns *pfns = SDL_calloc(1, sizeof(XrInstancePfns));
#define SDL_OPENXR_INSTANCE_SYM(name) \
result = xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)&pfns->name); \
if (result != XR_SUCCESS) { \
SDL_free(pfns); \
return NULL; \
}
#include "SDL_openxrsym.h"
return pfns;
}
#else
SDL_DECLSPEC bool SDLCALL SDL_OpenXR_LoadLibrary(void)
{
return SDL_SetError("OpenXR is not enabled in this build of SDL");
}
SDL_DECLSPEC void SDLCALL SDL_OpenXR_UnloadLibrary(void)
{
SDL_SetError("OpenXR is not enabled in this build of SDL");
}
SDL_DECLSPEC PFN_xrGetInstanceProcAddr SDLCALL SDL_OpenXR_GetXrGetInstanceProcAddr(void)
{
return (PFN_xrGetInstanceProcAddr)SDL_SetError("OpenXR is not enabled in this build of SDL");
}
#endif // HAVE_GPU_OPENXR
+55
View File
@@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_openxrdyn_h_
#define SDL_openxrdyn_h_
/* Use the internal header for vendored OpenXR includes */
#include "SDL_openxr_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct XrInstancePfns
{
#define SDL_OPENXR_INSTANCE_SYM(name) \
PFN_##name name;
#include "SDL_openxrsym.h"
} XrInstancePfns;
extern XrInstancePfns *SDL_OPENXR_LoadInstanceSymbols(XrInstance instance);
/* Define the function pointers */
#define SDL_OPENXR_SYM(name) \
extern PFN_##name OPENXR_##name;
#include "SDL_openxrsym.h"
#define xrGetInstanceProcAddr OPENXR_xrGetInstanceProcAddr
#define xrEnumerateApiLayerProperties OPENXR_xrEnumerateApiLayerProperties
#define xrEnumerateInstanceExtensionProperties OPENXR_xrEnumerateInstanceExtensionProperties
#define xrCreateInstance OPENXR_xrCreateInstance
#ifdef __cplusplus
}
#endif
#endif // SDL_openxrdyn_h_
+49
View File
@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* *INDENT-OFF* */ // clang-format off
#include "../../video/khronos/openxr/openxr.h"
#ifndef SDL_OPENXR_SYM
#define SDL_OPENXR_SYM(name)
#endif
#ifndef SDL_OPENXR_INSTANCE_SYM
#define SDL_OPENXR_INSTANCE_SYM(name)
#endif
SDL_OPENXR_SYM(xrGetInstanceProcAddr)
SDL_OPENXR_SYM(xrEnumerateApiLayerProperties)
SDL_OPENXR_SYM(xrCreateInstance)
SDL_OPENXR_SYM(xrEnumerateInstanceExtensionProperties)
SDL_OPENXR_INSTANCE_SYM(xrEnumerateSwapchainFormats)
SDL_OPENXR_INSTANCE_SYM(xrCreateSession)
SDL_OPENXR_INSTANCE_SYM(xrGetSystem)
SDL_OPENXR_INSTANCE_SYM(xrCreateSwapchain)
SDL_OPENXR_INSTANCE_SYM(xrEnumerateSwapchainImages)
SDL_OPENXR_INSTANCE_SYM(xrDestroyInstance)
SDL_OPENXR_INSTANCE_SYM(xrDestroySwapchain)
#undef SDL_OPENXR_SYM
#undef SDL_OPENXR_INSTANCE_SYM
/* *INDENT-ON* */ // clang-format on