Skip to content

Commit ef5df74

Browse files
committed
1.2.4 - Updated OpenVR SDK to 2.12.14, Added DX12 support (fixes Unity 6)
1 parent 35e0a1d commit ef5df74

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1352
-390
lines changed

CommonHeaders/OpenVR/openvr.h

Lines changed: 241 additions & 29 deletions
Large diffs are not rendered by default.

CommonHeaders/OpenVR/openvr_api.cs

Lines changed: 309 additions & 16 deletions
Large diffs are not rendered by default.

CommonHeaders/OpenVR/openvr_api.json

Lines changed: 249 additions & 19 deletions
Large diffs are not rendered by default.

CommonHeaders/OpenVR/openvr_capi.h

Lines changed: 119 additions & 16 deletions
Large diffs are not rendered by default.

CommonHeaders/OpenVR/openvr_driver.h

Lines changed: 170 additions & 34 deletions
Large diffs are not rendered by default.

CommonHeaders/ProviderInterface/XRMath.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
#include "UnityXRTypes.h"
44
#include <limits>
5-
6-
#ifdef __linux__
75
#include <cmath>
8-
#endif
96

107
#define EPSILON 0.00001F
118

Providers/Display/Display.cpp

Lines changed: 156 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::GfxThread_Start( UnityXRRendering
251251
m_eActiveTextureType = vr::TextureType_DirectX;
252252
break;
253253

254+
case kUnityGfxRendererD3D12:
255+
m_eActiveTextureType = vr::TextureType_DirectX12;
256+
break;
257+
254258
case kUnityGfxRendererVulkan:
255259
m_eActiveTextureType = vr::TextureType_Vulkan;
256260
break;
@@ -261,7 +265,7 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::GfxThread_Start( UnityXRRendering
261265
break;
262266

263267
default:
264-
XR_TRACE( "[OpenVR] [Error] Unsupported graphics api. Only DirectX, OpenGL and Vulkan are supported at this time." );
268+
XR_TRACE( "[OpenVR] [Error] Unsupported graphics api. Only DirectX 11/12, OpenGL and Vulkan are supported at this time." );
265269
return kUnitySubsystemErrorCodeFailure;
266270
break;
267271
}
@@ -459,7 +463,7 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::GfxThread_SubmitCurrentFrame()
459463
UnitySubsystemErrorCode OpenVRDisplayProvider::GfxThread_BlitToMirrorViewRenderTarget( const UnityXRMirrorViewBlitInfo *mirrorBlitInfo )
460464
{
461465
#ifndef __linux__
462-
// Set RTV
466+
// Set RTV for D3D11
463467
if ( XR_WIN && m_eActiveTextureType == vr::TextureType_DirectX )
464468
{
465469
ID3D11RenderTargetView *pRTV = s_pProviderContext->interfaces->Get<IUnityGraphicsD3D11>()->RTVFromRenderBuffer( mirrorBlitInfo->mirrorRtDesc->rtNative );
@@ -471,6 +475,7 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::GfxThread_BlitToMirrorViewRenderT
471475
const FLOAT clrColor[4] = { 0, 0, 0, 0 };
472476
pImmediateContext->ClearRenderTargetView( pRTV, clrColor );
473477
}
478+
// D3D12 doesn't need special handling here - Unity handles the render target setup
474479
#endif
475480

476481
return kUnitySubsystemErrorCodeSuccess;
@@ -748,15 +753,70 @@ bool OpenVRDisplayProvider::SubmitToCompositor( vr::EVREye eEye, int nStage )
748753
return false;
749754
}
750755
}
756+
#ifndef __linux__
757+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 )
758+
{
759+
ID3D12Resource *pD3D12Resource = (ID3D12Resource * )GetNativeEyeTexture( nStage, nTexIndex );
760+
if ( !pD3D12Resource )
761+
{
762+
XR_TRACE( "[OpenVR] [Error] Unable to get D3D12 resource for stage %i and eye %i\n", nStage, eEye );
763+
return false;
764+
}
765+
766+
IUnityGraphicsD3D12v5 *pD3D12v5 = s_pProviderContext->interfaces->Get<IUnityGraphicsD3D12v5>();
767+
IUnityGraphicsD3D12v4 *pD3D12v4 = s_pProviderContext->interfaces->Get<IUnityGraphicsD3D12v4>();
768+
IUnityGraphicsD3D12 *pD3D12 = s_pProviderContext->interfaces->Get<IUnityGraphicsD3D12>();
769+
770+
ID3D12CommandQueue *pCommandQueue = nullptr;
771+
if ( pD3D12v5 )
772+
{
773+
pCommandQueue = pD3D12v5->GetCommandQueue();
774+
}
775+
else if ( pD3D12v4 )
776+
{
777+
pCommandQueue = pD3D12v4->GetCommandQueue();
778+
}
779+
else if ( pD3D12 )
780+
{
781+
pCommandQueue = pD3D12->GetCommandQueue();
782+
}
783+
784+
if ( !pCommandQueue )
785+
{
786+
XR_TRACE( "[OpenVR] [Error] Unable to get D3D12 command queue for stage %i and eye %i\n", nStage, eEye );
787+
return false;
788+
}
789+
790+
m_vrD3D12Texture.m_pResource = pD3D12Resource;
791+
m_vrD3D12Texture.m_pCommandQueue = pCommandQueue;
792+
m_vrD3D12Texture.m_nNodeMask = 1;
793+
794+
XR_TRACE( "[OpenVR] D3D12 Resource: %p, CommandQueue: %p for stage %i eye %i\n",
795+
pD3D12Resource, pCommandQueue, nStage, eEye );
796+
}
797+
#endif
751798

752799
// Grab the correct texture for this stage
753800
vr::VRTextureWithDepth_t tex;
754-
tex.handle = m_eActiveTextureType == vr::TextureType_Vulkan ? &m_vrVulkanTexture : GetNativeEyeTexture( nStage, nTexIndex );
801+
if ( m_eActiveTextureType == vr::TextureType_Vulkan )
802+
{
803+
tex.handle = &m_vrVulkanTexture;
804+
}
805+
#ifndef __linux__
806+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 )
807+
{
808+
tex.handle = &m_vrD3D12Texture;
809+
}
810+
#endif
811+
else
812+
{
813+
tex.handle = GetNativeEyeTexture( nStage, nTexIndex );
814+
}
755815
tex.eType = m_eActiveTextureType;
756816
tex.eColorSpace = vr::ColorSpace_Auto;
757817

758818
// Check if we have a valid depth buffer
759-
if (m_pNativeDepthTextures[nStage][nTexIndex])
819+
if ( m_pNativeDepthTextures[nStage][nTexIndex] )
760820
{
761821
tex.depth.handle = m_pNativeDepthTextures[nStage][nTexIndex];
762822
}
@@ -767,12 +827,27 @@ bool OpenVRDisplayProvider::SubmitToCompositor( vr::EVREye eEye, int nStage )
767827
vr::EVRSubmitFlags nFlags = m_eActiveTextureType == vr::TextureType_Vulkan ? vr::Submit_VulkanTextureWithArrayData : vr::Submit_Default;
768828

769829
// Submit the texture to the Compositor
770-
vr::EVRCompositorError res = vr::VRCompositorError_None;
771-
res = vr::VRCompositor()->Submit( eEye, &tex, &m_textureBounds, nFlags );
830+
vr::EVRCompositorError res = vr::VRCompositor()->Submit( eEye, &tex, &m_textureBounds, nFlags );
772831

773832
if ( res != vr::VRCompositorError_None )
774833
{
775-
XR_TRACE( "[OpenVR] [Error] Unable to submit eye texture: [%i] [%x]\n", res, tex.handle );
834+
const char *errorName = "Unknown";
835+
switch ( res )
836+
{
837+
case vr::VRCompositorError_RequestFailed: errorName = "RequestFailed"; break;
838+
case vr::VRCompositorError_IncompatibleVersion: errorName = "IncompatibleVersion"; break;
839+
case vr::VRCompositorError_DoNotHaveFocus: errorName = "DoNotHaveFocus"; break;
840+
case vr::VRCompositorError_InvalidTexture: errorName = "InvalidTexture"; break;
841+
case vr::VRCompositorError_IsNotSceneApplication: errorName = "IsNotSceneApplication"; break;
842+
case vr::VRCompositorError_TextureIsOnWrongDevice: errorName = "TextureIsOnWrongDevice"; break;
843+
case vr::VRCompositorError_TextureUsesUnsupportedFormat: errorName = "TextureUsesUnsupportedFormat"; break;
844+
case vr::VRCompositorError_SharedTexturesNotSupported: errorName = "SharedTexturesNotSupported"; break;
845+
case vr::VRCompositorError_IndexOutOfRange: errorName = "IndexOutOfRange"; break;
846+
case vr::VRCompositorError_AlreadySubmitted: errorName = "AlreadySubmitted"; break;
847+
default: break;
848+
}
849+
XR_TRACE( "[OpenVR] [Error] Unable to submit eye %i texture for stage %i: [%i - %s] handle: %p, type: %i\n",
850+
eEye, nStage, res, errorName, tex.handle, tex.eType );
776851
return false;
777852
}
778853
}
@@ -790,6 +865,7 @@ void OpenVRDisplayProvider::SetupRenderPass( const vr::EVREye eEye, const UnityX
790865
int32_t nRenderPassesCount;
791866
int32_t nRenderParamsCount;
792867
int32_t nTextureArraySlice;
868+
int32_t nTextureIndex;
793869

794870
if ( m_bUseSinglePass )
795871
{
@@ -800,6 +876,7 @@ void OpenVRDisplayProvider::SetupRenderPass( const vr::EVREye eEye, const UnityX
800876
nRenderPassesCount = 1;
801877
nRenderParamsCount = 2;
802878
nTextureArraySlice = eEye;
879+
nTextureIndex = 0;
803880
}
804881
else
805882
{
@@ -810,14 +887,15 @@ void OpenVRDisplayProvider::SetupRenderPass( const vr::EVREye eEye, const UnityX
810887
nRenderPassesCount = 2;
811888
nRenderParamsCount = 1;
812889
nTextureArraySlice = 0;
890+
nTextureIndex = eEye;
813891
}
814892

815893
// Set the number of render passes for this frame
816894
pTargetFrame->renderPassesCount = nRenderPassesCount;
817895

818896
// Setup base render pass properties
819897
UnityXRNextFrameDesc::UnityXRRenderPass &renderPass = pTargetFrame->renderPasses[nRenderPasses];
820-
renderPass.textureId = m_UnityTextures[m_nCurFrame % m_nNumStages][nRenderPasses];
898+
renderPass.textureId = m_UnityTextures[m_nCurFrame % m_nNumStages][nTextureIndex];
821899
renderPass.renderParamsCount = nRenderParamsCount;
822900
renderPass.cullingPassIndex = nRenderPasses;
823901

@@ -1089,10 +1167,19 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::CreateEyeTextures( const UnityXRF
10891167
eyeWidth = (uint32_t )eyeWidthScaled;
10901168
eyeHeight = (uint32_t )eyeHeightScaled;
10911169

1170+
bool bUseTextureArrays = m_bUseSinglePass;
1171+
1172+
if ( m_bUseSinglePass )
1173+
{
1174+
XR_TRACE( "[OpenVR] Single-Pass mode: Creating texture array with 2 slices\n" );
1175+
}
1176+
10921177
// Create textures
10931178
for ( int stage = 0; stage < m_nNumStages; ++stage )
10941179
{
1095-
for ( int eye = 0; eye < nNumTextures; ++eye )
1180+
int nTextureCount = bUseTextureArrays ? 1 : nNumTextures;
1181+
1182+
for ( int eye = 0; eye < nTextureCount; ++eye )
10961183
{
10971184
UnityXRRenderTextureDesc unityDesc;
10981185
memset( &unityDesc, 0, sizeof( UnityXRRenderTextureDesc ) );
@@ -1108,11 +1195,22 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::CreateEyeTextures( const UnityXRF
11081195
unityDesc.flags |= kUnityXRRenderTextureFlagsSRGB;
11091196
}
11101197

1111-
if ( m_bUseSinglePass )
1198+
if ( bUseTextureArrays )
11121199
{
11131200
unityDesc.textureArrayLength = 2;
11141201
}
11151202

1203+
// Log texture creation details
1204+
const char *apiName = "Unknown";
1205+
if ( m_eActiveTextureType == vr::TextureType_DirectX ) apiName = "D3D11";
1206+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 ) apiName = "D3D12";
1207+
else if ( m_eActiveTextureType == vr::TextureType_Vulkan ) apiName = "Vulkan";
1208+
else if ( m_eActiveTextureType == vr::TextureType_OpenGL ) apiName = "OpenGL";
1209+
1210+
XR_TRACE( "[OpenVR] Creating %s texture (stage %i, eye %i): %ux%u, arrayLen: %u, sRGB: %i, depth: %i\n",
1211+
apiName, stage, eye, eyeWidth, eyeHeight, unityDesc.textureArrayLength,
1212+
(unityDesc.flags & kUnityXRRenderTextureFlagsSRGB) ? 1 : 0, unityDesc.depthFormat );
1213+
11161214
// Create an UnityXRRenderTextureId for the native texture so we can tell unity to render to it later.
11171215
UnityXRRenderTextureId unityTexId;
11181216
UnitySubsystemErrorCode res = s_pXRDisplay->CreateTexture( s_DisplayHandle, &unityDesc, &unityTexId );
@@ -1122,9 +1220,23 @@ UnitySubsystemErrorCode OpenVRDisplayProvider::CreateEyeTextures( const UnityXRF
11221220
return res;
11231221
}
11241222

1125-
m_UnityTextures[stage][eye] = unityTexId;
1126-
m_pNativeColorTextures[stage][eye] = nullptr; // this is just registering a creation request, we'll grab the native textures later
1127-
m_pNativeDepthTextures[stage][eye] = nullptr;
1223+
if ( bUseTextureArrays )
1224+
{
1225+
// Single-pass: one texture array for both eyes
1226+
m_UnityTextures[stage][0] = unityTexId;
1227+
m_UnityTextures[stage][1] = unityTexId;
1228+
m_pNativeColorTextures[stage][0] = nullptr;
1229+
m_pNativeColorTextures[stage][1] = nullptr;
1230+
m_pNativeDepthTextures[stage][0] = nullptr;
1231+
m_pNativeDepthTextures[stage][1] = nullptr;
1232+
}
1233+
else
1234+
{
1235+
// Multi-pass: separate texture per eye
1236+
m_UnityTextures[stage][eye] = unityTexId;
1237+
m_pNativeColorTextures[stage][eye] = nullptr;
1238+
m_pNativeDepthTextures[stage][eye] = nullptr;
1239+
}
11281240
}
11291241
}
11301242

@@ -1162,15 +1274,28 @@ void *OpenVRDisplayProvider::GetNativeEyeTexture( int stage, int eye )
11621274
UnitySubsystemErrorCode res = s_pXRDisplay->QueryTextureDesc( s_DisplayHandle, unityTexId, &unityDesc );
11631275
if ( res != kUnitySubsystemErrorCodeSuccess )
11641276
{
1165-
XR_TRACE( "[OpenVR] Error querying texture: [%i]\n", res );
1277+
XR_TRACE( "[OpenVR] Error querying texture for stage %i eye %i: [%i]\n", stage, eye, res );
11661278
return nullptr;
11671279
}
11681280

11691281
m_pNativeColorTextures[stage][eye] = unityDesc.color.nativePtr;
1170-
XR_TRACE( "[OpenVR] Created Native Color: %x\n", unityDesc.color.nativePtr );
1171-
11721282
m_pNativeDepthTextures[stage][eye] = unityDesc.depth.nativePtr;
1173-
XR_TRACE( "[OpenVR] Created Native Depth: %x\n", unityDesc.depth.nativePtr );
1283+
1284+
// Log texture information with API type
1285+
const char *apiName = "Unknown";
1286+
if ( m_eActiveTextureType == vr::TextureType_DirectX ) apiName = "D3D11";
1287+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 ) apiName = "D3D12";
1288+
else if ( m_eActiveTextureType == vr::TextureType_Vulkan ) apiName = "Vulkan";
1289+
else if ( m_eActiveTextureType == vr::TextureType_OpenGL ) apiName = "OpenGL";
1290+
1291+
XR_TRACE( "[OpenVR] %s Native Color Texture (stage %i, eye %i): %p (width: %u, height: %u, arrayLen: %u)\n",
1292+
apiName, stage, eye, unityDesc.color.nativePtr, unityDesc.width, unityDesc.height, unityDesc.textureArrayLength );
1293+
1294+
if ( unityDesc.depth.nativePtr )
1295+
{
1296+
XR_TRACE( "[OpenVR] %s Native Depth Texture (stage %i, eye %i): %p\n",
1297+
apiName, stage, eye, unityDesc.depth.nativePtr );
1298+
}
11741299
}
11751300

11761301
return m_pNativeColorTextures[stage][eye];
@@ -1212,25 +1337,28 @@ void OpenVRDisplayProvider::SetupOverlayMirror()
12121337
}
12131338
}
12141339

1215-
ID3D11Device *m_pD3D11Device;
1340+
ID3D11Device *m_pD3D11Device = nullptr;
12161341
if ( m_eActiveTextureType == vr::TextureType_DirectX )
12171342
{
1218-
// Grab the active render device
1343+
// Grab the active render device for D3D11
12191344
m_pD3D11Device = s_pProviderContext->interfaces->Get< IUnityGraphicsD3D11 >()->GetDevice();
12201345

12211346
// Create a native device handle for OpenVR
12221347
m_nativeDevice.eType = vr::DeviceType_DirectX11;
12231348
m_nativeDevice.handle = m_pD3D11Device;
12241349
}
1350+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 )
1351+
{
1352+
// OpenVR overlay mirror only supports DirectX11 (no DeviceType_DirectX12 in API as of 2025)
1353+
// D3D12 will fall back to standard left/right eye mirror mode
1354+
m_nativeDevice.handle = nullptr;
1355+
m_pD3D11Device = nullptr;
1356+
}
12251357
else
12261358
{
12271359
m_nativeDevice.handle = nullptr;
12281360
m_pD3D11Device = nullptr;
12291361
}
1230-
1231-
// Create a native device handle for OpenVR
1232-
m_nativeDevice.eType = vr::DeviceType_DirectX11;
1233-
m_nativeDevice.handle = m_pD3D11Device;
12341362

12351363
// Get the active overlay view - should be our scene application now at this stage
12361364
if ( m_nMirrorMode == kUnityXRMirrorBlitDistort && !m_bOverlayFallback && m_hOverlay != k_ulInvalidOverlayHandle && m_bIsUsingRGB && !m_bIsUsingCustomMirrorMode && vr::VRSystem() && vr::VROverlayView() )
@@ -1343,6 +1471,11 @@ void OpenVRDisplayProvider::SetupOverlayMirror()
13431471
m_bOverlayFallback = true;
13441472
XR_TRACE( "[OpenVR] [Error] [Mirror] OpenVR View falling back to left eye texture. Project not using sRGB.\n" );
13451473
}
1474+
else if ( m_eActiveTextureType == vr::TextureType_DirectX12 )
1475+
{
1476+
m_bOverlayFallback = true;
1477+
XR_TRACE( "[OpenVR] [Mirror] OpenVR View falling back to left eye texture. DirectX 12 uses standard mirror mode.\n" );
1478+
}
13461479
else if ( m_eActiveTextureType != vr::TextureType_DirectX )
13471480
{
13481481
m_bOverlayFallback = true;

Providers/Display/Display.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
1919
#include "d3d11.h"
20+
#include "d3d12.h"
2021
#include "ProviderInterface/IUnityGraphicsD3D11.h"
22+
#include "ProviderInterface/IUnityGraphicsD3D12.h"
2123
#define XR_WIN 1
2224
#else
2325
#define XR_WIN 0
@@ -266,6 +268,11 @@ class OpenVRDisplayProvider
266268
/// Holds the OpenVR Vulkan Texture Array data for submitting to the compositor
267269
vr::VRVulkanTextureArrayData_t m_vrVulkanTexture = {};
268270

271+
#ifndef __linux__
272+
/// Holds the OpenVR DirectX 12 Texture data for submitting to the compositor
273+
vr::D3D12TextureData_t m_vrD3D12Texture = {};
274+
#endif
275+
269276
/// Holds the Unity equivalent eye textures per stage (0:Left, 1: Right, Single Pass only uses left with texture array size of 2)
270277
UnityXRRenderTextureId m_UnityTextures[k_nMaxNumStages][2];
271278

com.valve.openvr/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this package will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [1.2.4] - 2025-10-29
8+
### Added
9+
- Updated to OpenVR SDK 2.12.14
10+
- Added DX12 support. Note: Unity has a bug where single pass doesn't work with the built-in render pipeline. You'll need to use URP or multipass.
11+
712
## [1.2.3] - 2024-07-18
813
### Changed
914
- Updated to OpenVR SDK 2.5.1

com.valve.openvr/Documentation~/com.valvesoftware.unity.openvr.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ The purpose of this package is to provide OpenVR rendering to Unity XR. This pac
55
## Subsystems
66

77
### Display
8-
The display subsystem provides rendering support for the XR Plugin. It currently supports DirectX 11 and Vulcan.
8+
The display subsystem provides rendering support for the XR Plugin. It currently supports DirectX 11/12, and Vulcan.
99

1010
### Input
1111

1212
* **SteamVR Input**
13-
To use the full power of SteamVR we recommend also downloading our SteamVR for Unity plugin. It is in beta [on our github releases page.](https://github.com/ValveSoftware/steamvr_unity_plugin/releases/tag/2.6.0b1) This plugin can run alongside the OpenVR XR plugin. However, you will not be able to query Unity's input functions while using SteamVR Input. The two systems are currently incompatible and you must chose to use one or the other.
13+
To use the full power of SteamVR we recommend also downloading our SteamVR Unity plugin. It is in beta [on our github releases page.](https://github.com/ValveSoftware/steamvr_unity_plugin/releases/ or on the Unity Asset Store) This plugin can run alongside this OpenVR XR package. However, you will not be able to query Unity's input functions while using SteamVR Input. The two systems are currently incompatible and you must chose to use one or the other.
1414

1515
## XR Management
1616

0 commit comments

Comments
 (0)