Merge pull request #104207 from mbucchia/d3d12-xr

Add support for Direct3D 12 OpenXR backend
This commit is contained in:
Thaddeus Crews 2025-04-21 08:24:16 -05:00
commit e5d1fdcfea
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
11 changed files with 826 additions and 6 deletions

View file

@ -0,0 +1,45 @@
/**************************************************************************/
/* d3d12_hooks.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "d3d12_hooks.h"
D3D12Hooks *D3D12Hooks::singleton = nullptr;
D3D12Hooks::D3D12Hooks() {
if (singleton == nullptr) {
singleton = this;
}
}
D3D12Hooks::~D3D12Hooks() {
if (singleton == this) {
singleton = nullptr;
}
}

View file

@ -0,0 +1,48 @@
/**************************************************************************/
/* d3d12_hooks.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "rendering_device_driver_d3d12.h"
class D3D12Hooks {
private:
static D3D12Hooks *singleton;
public:
D3D12Hooks();
virtual ~D3D12Hooks();
virtual D3D_FEATURE_LEVEL get_feature_level() const = 0;
virtual LUID get_adapter_luid() const = 0;
virtual void set_device(ID3D12Device *p_device) = 0;
virtual void set_command_queue(ID3D12CommandQueue *p_queue) = 0;
virtual void cleanup_device() = 0;
static D3D12Hooks *get_singleton() { return singleton; }
};

View file

@ -30,6 +30,8 @@
#include "rendering_context_driver_d3d12.h"
#include "d3d12_hooks.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/string/ustring.h"

View file

@ -30,6 +30,8 @@
#include "rendering_device_driver_d3d12.h"
#include "d3d12_hooks.h"
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "servers/rendering/rendering_device.h"
@ -1356,7 +1358,105 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p
}
RDD::TextureID RenderingDeviceDriverD3D12::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) {
ERR_FAIL_V_MSG(TextureID(), "Unimplemented!");
ID3D12Resource *texture = (ID3D12Resource *)p_native_texture;
#if defined(_MSC_VER) || !defined(_WIN32)
const D3D12_RESOURCE_DESC base_resource_desc = texture->GetDesc();
#else
D3D12_RESOURCE_DESC base_resource_desc;
texture->GetDesc(&base_resource_desc);
#endif
CD3DX12_RESOURCE_DESC resource_desc(base_resource_desc);
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
{
srv_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
srv_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_type];
srv_desc.Shader4ComponentMapping = _compute_component_mapping(TextureView{ p_format });
switch (srv_desc.ViewDimension) {
case D3D12_SRV_DIMENSION_TEXTURE1D: {
srv_desc.Texture1D.MipLevels = resource_desc.MipLevels;
} break;
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
srv_desc.Texture1DArray.MipLevels = resource_desc.MipLevels;
srv_desc.Texture1DArray.ArraySize = p_array_layers;
} break;
case D3D12_SRV_DIMENSION_TEXTURE2D: {
srv_desc.Texture2D.MipLevels = resource_desc.MipLevels;
} break;
case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
} break;
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
srv_desc.Texture2DArray.MipLevels = resource_desc.MipLevels;
srv_desc.Texture2DArray.ArraySize = p_array_layers;
} break;
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
srv_desc.Texture2DMSArray.ArraySize = p_array_layers;
} break;
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
srv_desc.TextureCubeArray.MipLevels = resource_desc.MipLevels;
srv_desc.TextureCubeArray.NumCubes = p_array_layers / 6;
} break;
case D3D12_SRV_DIMENSION_TEXTURE3D: {
srv_desc.Texture3D.MipLevels = resource_desc.MipLevels;
} break;
case D3D12_SRV_DIMENSION_TEXTURECUBE: {
srv_desc.TextureCube.MipLevels = resource_desc.MipLevels;
} break;
default: {
}
}
}
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
{
uav_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
uav_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_type] : D3D12_UAV_DIMENSION_UNKNOWN;
switch (uav_desc.ViewDimension) {
case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
uav_desc.Texture1DArray.ArraySize = p_array_layers;
} break;
case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
// Either for an actual 2D texture array, cubemap or cubemap array.
uav_desc.Texture2DArray.ArraySize = p_array_layers;
} break;
case D3D12_UAV_DIMENSION_TEXTURE3D: {
uav_desc.Texture3D.WSize = resource_desc.Depth();
} break;
default: {
}
}
}
TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
tex_info->resource = texture;
tex_info->owner_info.resource = nullptr; // Not allocated by us.
tex_info->owner_info.allocation = nullptr; // Not allocated by us.
tex_info->owner_info.states.subresource_states.resize(resource_desc.MipLevels * p_array_layers);
for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {
tex_info->owner_info.states.subresource_states[i] = !p_depth_stencil ? D3D12_RESOURCE_STATE_RENDER_TARGET : D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
tex_info->states_ptr = &tex_info->owner_info.states;
tex_info->format = p_format;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
tex_info->base_layer = 0;
tex_info->layers = p_array_layers;
tex_info->base_mip = 0;
tex_info->mipmaps = resource_desc.MipLevels;
tex_info->view_descs.srv = srv_desc;
tex_info->view_descs.uav = uav_desc;
#ifdef DEBUG_ENABLED
tex_info->created_from_extension = true;
#endif
return TextureID(tex_info);
}
RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
@ -2077,6 +2177,10 @@ void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_
if (texture_info->main_texture) {
texture_info = texture_info->main_texture;
}
// Textures created for simultaneous access do not need explicit transitions.
if (texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS) {
continue;
}
_rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore);
_rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter);
texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout);
@ -2126,7 +2230,9 @@ void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_
barrier_group.pTextureBarriers = texture_barriers.ptr();
}
cmd_list_7->Barrier(barrier_groups_count, barrier_groups);
if (barrier_groups_count) {
cmd_list_7->Barrier(barrier_groups_count, barrier_groups);
}
}
/****************/
@ -2212,6 +2318,10 @@ RDD::CommandQueueID RenderingDeviceDriverD3D12::command_queue_create(CommandQueu
HRESULT res = device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(d3d_queue.GetAddressOf()));
ERR_FAIL_COND_V(!SUCCEEDED(res), CommandQueueID());
if (p_identify_as_main_queue && D3D12Hooks::get_singleton() != nullptr) {
D3D12Hooks::get_singleton()->set_command_queue(d3d_queue.Get());
}
CommandQueueInfo *command_queue = memnew(CommandQueueInfo);
command_queue->d3d_queue = d3d_queue;
return CommandQueueID(command_queue);
@ -3141,6 +3251,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
}
// - Link NIR shaders.
bool can_use_multiview = D3D12Hooks::get_singleton() != nullptr;
for (int i = SHADER_STAGE_MAX - 1; i >= 0; i--) {
if (!stages_nir_shaders.has(i)) {
continue;
@ -3153,6 +3264,26 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
break;
}
}
// There is a bug in the Direct3D runtime during creation of a PSO with view instancing. If a fragment
// shader uses front/back face detection (SV_IsFrontFace), its signature must include the pixel position
// builtin variable (SV_Position), otherwise an Internal Runtime error will occur.
if (i == SHADER_STAGE_FRAGMENT && can_use_multiview) {
const bool use_front_face =
nir_find_variable_with_location(shader, nir_var_shader_in, VARYING_SLOT_FACE) ||
(shader->info.inputs_read & VARYING_BIT_FACE) ||
nir_find_variable_with_location(shader, nir_var_system_value, SYSTEM_VALUE_FRONT_FACE) ||
BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_FRONT_FACE);
const bool use_position =
nir_find_variable_with_location(shader, nir_var_shader_in, VARYING_SLOT_POS) ||
(shader->info.inputs_read & VARYING_BIT_POS) ||
nir_find_variable_with_location(shader, nir_var_system_value, SYSTEM_VALUE_FRAG_COORD) ||
BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_FRAG_COORD);
if (use_front_face && !use_position) {
nir_variable *const pos = nir_variable_create(shader, nir_var_shader_in, glsl_vec4_type(), "gl_FragCoord");
pos->data.location = VARYING_SLOT_POS;
shader->info.inputs_read |= VARYING_BIT_POS;
}
}
if (prev_shader) {
bool requires_runtime_data = {};
dxil_spirv_nir_link(shader, prev_shader, &dxil_runtime_conf, &requires_runtime_data);
@ -5615,7 +5746,7 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
VectorView<PipelineSpecializationConstant> p_specialization_constants) {
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
CD3DX12_PIPELINE_STATE_STREAM1 pipeline_desc = {};
const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
RenderPipelineInfo render_info;
@ -5808,6 +5939,15 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
render_info.dyn_params.blend_constant = p_blend_state.blend_constant;
// Multiview
// We are using render target slices for each view.
const D3D12_VIEW_INSTANCE_LOCATION viewInstanceLocations[D3D12_MAX_VIEW_INSTANCE_COUNT] = { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 } };
if (pass_info->view_count > 1) {
(&pipeline_desc.ViewInstancingDesc)->ViewInstanceCount = pass_info->view_count;
(&pipeline_desc.ViewInstancingDesc)->Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
(&pipeline_desc.ViewInstancingDesc)->pViewInstanceLocations = viewInstanceLocations;
}
// Stages bytecodes + specialization constants.
pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();
@ -6308,6 +6448,9 @@ RenderingDeviceDriverD3D12::RenderingDeviceDriverD3D12(RenderingContextDriverD3D
}
RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() {
if (D3D12Hooks::get_singleton() != nullptr) {
D3D12Hooks::get_singleton()->cleanup_device();
}
glsl_type_singleton_decref();
}
@ -6342,17 +6485,43 @@ Error RenderingDeviceDriverD3D12::_initialize_device() {
d3d_D3D12EnableExperimentalFeatures(1, experimental_features, nullptr, nullptr);
}
D3D_FEATURE_LEVEL requested_feature_level = D3D_FEATURE_LEVEL_11_0;
// Override the adapter and feature level if needed by the XR backend.
if (D3D12Hooks::get_singleton() != nullptr) {
const LUID adapter_luid = D3D12Hooks::get_singleton()->get_adapter_luid();
requested_feature_level = D3D12Hooks::get_singleton()->get_feature_level();
ComPtr<IDXGIAdapter1> desired_adapter;
for (UINT adapter_index = 0;; adapter_index++) {
// EnumAdapters1 will fail with DXGI_ERROR_NOT_FOUND when there are no more adapters to
// enumerate.
if (context_driver->dxgi_factory_get()->EnumAdapters1(adapter_index, desired_adapter.ReleaseAndGetAddressOf()) == DXGI_ERROR_NOT_FOUND) {
break;
}
DXGI_ADAPTER_DESC1 desc;
desired_adapter->GetDesc1(&desc);
if (!memcmp(&desc.AdapterLuid, &adapter_luid, sizeof(LUID))) {
break;
}
}
ERR_FAIL_NULL_V(desired_adapter, ERR_CANT_CREATE);
adapter = desired_adapter;
}
ID3D12DeviceFactory *device_factory = context_driver->device_factory_get();
if (device_factory != nullptr) {
res = device_factory->CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf()));
res = device_factory->CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));
} else {
PFN_D3D12_CREATE_DEVICE d3d_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateDevice");
ERR_FAIL_NULL_V(d3d_D3D12CreateDevice, ERR_CANT_CREATE);
res = d3d_D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf()));
res = d3d_D3D12CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));
}
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
if (D3D12Hooks::get_singleton() != nullptr) {
D3D12Hooks::get_singleton()->set_device(device.Get());
}
if (context_driver->use_validation_layers()) {
ComPtr<ID3D12InfoQueue> info_queue;
res = device.As(&info_queue);

View file

@ -275,6 +275,9 @@ private:
UINT mapped_subresource = UINT_MAX;
SelfList<TextureInfo> pending_clear{ this };
#ifdef DEBUG_ENABLED
bool created_from_extension = false;
#endif
};
SelfList<TextureInfo>::List textures_pending_clear;

View file

@ -17,5 +17,7 @@ if env["metal"]:
env_openxr.add_source_files(module_obj, "platform/openxr_metal_extension.mm")
if env["opengl3"] and env["platform"] != "macos":
env_openxr.add_source_files(module_obj, "platform/openxr_opengl_extension.cpp")
if env["d3d12"]:
env_openxr.add_source_files(module_obj, "platform/openxr_d3d12_extension.cpp")
env.modules_sources += module_obj

View file

@ -0,0 +1,450 @@
/**************************************************************************/
/* openxr_d3d12_extension.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_d3d12_extension.h"
#ifdef D3D12_ENABLED
#include "../../openxr_util.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
HashMap<String, bool *> OpenXRD3D12Extension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
request_extensions[XR_KHR_D3D12_ENABLE_EXTENSION_NAME] = nullptr;
return request_extensions;
}
void OpenXRD3D12Extension::on_instance_created(const XrInstance p_instance) {
// Obtain pointers to functions we're accessing here.
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
EXT_INIT_XR_FUNC(xrGetD3D12GraphicsRequirementsKHR);
EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
}
D3D_FEATURE_LEVEL OpenXRD3D12Extension::get_feature_level() const {
XrGraphicsRequirementsD3D12KHR d3d12_requirements = {
XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, // type
nullptr, // next
{ 0, 0 }, // adapterLuid
(D3D_FEATURE_LEVEL)0 // minFeatureLevel
};
XrResult result = xrGetD3D12GraphicsRequirementsKHR(OpenXRAPI::get_singleton()->get_instance(), OpenXRAPI::get_singleton()->get_system_id(), &d3d12_requirements);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get Direct3D 12 graphics requirements [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return D3D_FEATURE_LEVEL_11_0; // Good default.
}
// #ifdef DEBUG
print_line("OpenXR: xrGetD3D12GraphicsRequirementsKHR:");
print_line(" - minFeatureLevel: ", (uint32_t)d3d12_requirements.minFeatureLevel);
// #endif
return d3d12_requirements.minFeatureLevel;
}
LUID OpenXRD3D12Extension::get_adapter_luid() const {
XrGraphicsRequirementsD3D12KHR d3d12_requirements = {
XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, // type
nullptr, // next
{ 0, 0 }, // adapterLuid
(D3D_FEATURE_LEVEL)0 // minFeatureLevel
};
XrResult result = xrGetD3D12GraphicsRequirementsKHR(OpenXRAPI::get_singleton()->get_instance(), OpenXRAPI::get_singleton()->get_system_id(), &d3d12_requirements);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get Direct3D 12 graphics requirements [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return {};
}
return d3d12_requirements.adapterLuid;
}
void OpenXRD3D12Extension::set_device(ID3D12Device *p_device) {
graphics_device = p_device;
}
void OpenXRD3D12Extension::set_command_queue(ID3D12CommandQueue *p_queue) {
command_queue = p_queue;
}
void OpenXRD3D12Extension::cleanup_device() {
command_queue.Reset();
graphics_device.Reset();
}
XrGraphicsBindingD3D12KHR OpenXRD3D12Extension::graphics_binding_d3d12;
void *OpenXRD3D12Extension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
DEV_ASSERT(graphics_device && "Graphics Device was not specified yet.");
DEV_ASSERT(command_queue && "Command queue was not specified yet.");
graphics_binding_d3d12.type = XR_TYPE_GRAPHICS_BINDING_D3D12_KHR,
graphics_binding_d3d12.next = p_next_pointer;
graphics_binding_d3d12.device = graphics_device.Get();
graphics_binding_d3d12.queue = command_queue.Get();
return &graphics_binding_d3d12;
}
void OpenXRD3D12Extension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
p_usable_swap_chains.push_back(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
p_usable_swap_chains.push_back(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
p_usable_swap_chains.push_back(DXGI_FORMAT_R8G8B8A8_UNORM);
p_usable_swap_chains.push_back(DXGI_FORMAT_B8G8R8A8_UNORM);
}
void OpenXRD3D12Extension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) {
p_usable_depth_formats.push_back(DXGI_FORMAT_D32_FLOAT);
p_usable_depth_formats.push_back(DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
p_usable_depth_formats.push_back(DXGI_FORMAT_D24_UNORM_S8_UINT);
p_usable_depth_formats.push_back(DXGI_FORMAT_D16_UNORM);
}
bool OpenXRD3D12Extension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL_V(rendering_server, false);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL_V(rendering_device, false);
uint32_t swapchain_length;
XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchain image count [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return false;
}
LocalVector<XrSwapchainImageD3D12KHR> images;
images.resize(swapchain_length);
for (XrSwapchainImageD3D12KHR &image : images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR;
image.next = nullptr;
image.texture = nullptr;
}
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr());
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchain images [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return false;
}
SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
if (data == nullptr) {
print_line("OpenXR: Failed to allocate memory for swapchain data");
return false;
}
*r_swapchain_graphics_data = data;
data->is_multiview = (p_array_size > 1);
RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1;
uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT;
switch (p_swapchain_format) {
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
// Even though this is an sRGB framebuffer format we're using UNORM here.
// The reason here is because Godot does a linear to sRGB conversion while
// with the sRGB format, this conversion would be doubled by the hardware.
// This also means we're reading the values as is for our preview on screen.
// The OpenXR runtime however is still treating this as an sRGB format and
// will thus do an sRGB -> Linear conversion as expected.
//format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
//format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_R8G8B8A8_UNORM:
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_D32_FLOAT:
format = RenderingDevice::DATA_FORMAT_D32_SFLOAT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case DXGI_FORMAT_D16_UNORM:
format = RenderingDevice::DATA_FORMAT_D16_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
default:
// continue with our default value
print_line("OpenXR: Unsupported swapchain format", p_swapchain_format);
break;
}
switch (p_sample_count) {
case 1:
samples = RenderingDevice::TEXTURE_SAMPLES_1;
break;
case 2:
samples = RenderingDevice::TEXTURE_SAMPLES_2;
break;
case 4:
samples = RenderingDevice::TEXTURE_SAMPLES_4;
break;
case 8:
samples = RenderingDevice::TEXTURE_SAMPLES_8;
break;
case 16:
samples = RenderingDevice::TEXTURE_SAMPLES_16;
break;
case 32:
samples = RenderingDevice::TEXTURE_SAMPLES_32;
break;
case 64:
samples = RenderingDevice::TEXTURE_SAMPLES_64;
break;
default:
// continue with our default value
print_line("OpenXR: Unsupported sample count", p_sample_count);
break;
}
Vector<RID> texture_rids;
for (const XrSwapchainImageD3D12KHR &swapchain_image : images) {
RID texture_rid = rendering_device->texture_create_from_extension(
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
format,
samples,
usage_flags,
(uint64_t)swapchain_image.texture,
p_width,
p_height,
1,
p_array_size);
texture_rids.push_back(texture_rid);
}
data->texture_rids = texture_rids;
return true;
}
bool OpenXRD3D12Extension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
OpenXRUtil::XrMatrix4x4f matrix;
OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_D3D, p_fov, (float)p_z_near, (float)p_z_far);
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i];
}
}
return true;
}
RID OpenXRD3D12Extension::get_texture(void *p_swapchain_graphics_data, int p_image_index) {
SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
ERR_FAIL_NULL_V(data, RID());
ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID());
return data->texture_rids[p_image_index];
}
void OpenXRD3D12Extension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
if (*p_swapchain_graphics_data == nullptr) {
return;
}
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL(rendering_server);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL(rendering_device);
SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
for (const RID &texture_rid : data->texture_rids) {
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain.
rendering_device->free(texture_rid);
}
data->texture_rids.clear();
memdelete(data);
*p_swapchain_graphics_data = nullptr;
}
#define ENUM_TO_STRING_CASE(e) \
case e: { \
return String(#e); \
} break;
String OpenXRD3D12Extension::get_swapchain_format_name(int64_t p_swapchain_format) const {
// These are somewhat different per platform, will need to weed some stuff out...
switch (p_swapchain_format) {
ENUM_TO_STRING_CASE(DXGI_FORMAT_UNKNOWN)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32A32_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32A32_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32A32_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32A32_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32B32_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16B16A16_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G32_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32G8X24_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R10G10B10A2_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R10G10B10A2_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R10G10B10A2_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R11G11B10_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8B8A8_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16G16_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_D32_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R32_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R24G8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_D24_UNORM_S8_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R24_UNORM_X8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_X24_TYPELESS_G8_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_FLOAT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_D16_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R16_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8_UINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8_SINT)
ENUM_TO_STRING_CASE(DXGI_FORMAT_A8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R1_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R9G9B9E5_SHAREDEXP)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R8G8_B8G8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_G8R8_G8B8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC1_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC1_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC1_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC2_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC2_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC2_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC3_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC3_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC3_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC4_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC4_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC4_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC5_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC5_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC5_SNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B5G6R5_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B5G5R5A1_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8A8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8X8_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8A8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8X8_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC6H_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC6H_UF16)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC6H_SF16)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC7_TYPELESS)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC7_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_BC7_UNORM_SRGB)
ENUM_TO_STRING_CASE(DXGI_FORMAT_AYUV)
ENUM_TO_STRING_CASE(DXGI_FORMAT_Y410)
ENUM_TO_STRING_CASE(DXGI_FORMAT_Y416)
ENUM_TO_STRING_CASE(DXGI_FORMAT_NV12)
ENUM_TO_STRING_CASE(DXGI_FORMAT_P010)
ENUM_TO_STRING_CASE(DXGI_FORMAT_P016)
ENUM_TO_STRING_CASE(DXGI_FORMAT_420_OPAQUE)
ENUM_TO_STRING_CASE(DXGI_FORMAT_YUY2)
ENUM_TO_STRING_CASE(DXGI_FORMAT_Y210)
ENUM_TO_STRING_CASE(DXGI_FORMAT_Y216)
ENUM_TO_STRING_CASE(DXGI_FORMAT_NV11)
ENUM_TO_STRING_CASE(DXGI_FORMAT_AI44)
ENUM_TO_STRING_CASE(DXGI_FORMAT_IA44)
ENUM_TO_STRING_CASE(DXGI_FORMAT_P8)
ENUM_TO_STRING_CASE(DXGI_FORMAT_A8P8)
ENUM_TO_STRING_CASE(DXGI_FORMAT_B4G4R4A4_UNORM)
ENUM_TO_STRING_CASE(DXGI_FORMAT_P208)
ENUM_TO_STRING_CASE(DXGI_FORMAT_V208)
ENUM_TO_STRING_CASE(DXGI_FORMAT_V408)
ENUM_TO_STRING_CASE(DXGI_FORMAT_A4B4G4R4_UNORM)
default: {
return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
} break;
}
}
#endif // D3D12_ENABLED

View file

@ -0,0 +1,84 @@
/**************************************************************************/
/* openxr_d3d12_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifdef D3D12_ENABLED
#include "../../openxr_api.h"
#include "../../util.h"
#include "../openxr_extension_wrapper.h"
#include "core/templates/vector.h"
#include "drivers/d3d12/d3d12_hooks.h"
// Always include this as late as possible.
#include "../../openxr_platform_inc.h"
class OpenXRD3D12Extension : public OpenXRGraphicsExtensionWrapper, D3D12Hooks {
public:
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
virtual D3D_FEATURE_LEVEL get_feature_level() const override final;
virtual LUID get_adapter_luid() const override final;
virtual void set_device(ID3D12Device *p_device) override final;
virtual void set_command_queue(ID3D12CommandQueue *p_queue) override final;
virtual void cleanup_device() override final;
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
virtual RID get_density_map(void *p_swapchain_graphics_data, int p_image_index) override { return RID(); }
private:
static OpenXRD3D12Extension *singleton;
static XrGraphicsBindingD3D12KHR graphics_binding_d3d12;
struct SwapchainGraphicsData {
bool is_multiview;
Vector<RID> texture_rids;
};
EXT_PROTO_XRRESULT_FUNC3(xrGetD3D12GraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsD3D12KHR *), p_graphics_requirements)
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
ComPtr<ID3D12Device> graphics_device;
ComPtr<ID3D12CommandQueue> command_queue;
};
#endif // D3D12_ENABLED

View file

@ -52,6 +52,10 @@
#include "extensions/platform/openxr_opengl_extension.h"
#endif
#ifdef D3D12_ENABLED
#include "extensions/platform/openxr_d3d12_extension.h"
#endif
#include "extensions/openxr_composition_layer_depth_extension.h"
#include "extensions/openxr_debug_utils_extension.h"
#include "extensions/openxr_eye_gaze_interaction.h"
@ -1679,6 +1683,14 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
#else
// shouldn't be possible...
ERR_FAIL_V(false);
#endif
} else if (p_rendering_driver == "d3d12") {
#ifdef D3D12_ENABLED
graphics_extension = memnew(OpenXRD3D12Extension);
register_extension_wrapper(graphics_extension);
#else
// shouldn't be possible...
ERR_FAIL_V(false);
#endif
} else {
ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");

View file

@ -68,6 +68,11 @@
#endif // X11_ENABLED
#endif // defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
#ifdef D3D12_ENABLED
#define XR_USE_GRAPHICS_API_D3D12
#include "drivers/d3d12/rendering_context_driver_d3d12.h"
#endif // D3D12_ENABLED
#ifdef X11_ENABLED
#include <X11/Xlib.h>
#endif // X11_ENABLED

View file

@ -435,7 +435,7 @@ String ShaderRD::_version_get_sha1(Version *p_version) const {
}
static const char *shader_file_header = "GDSC";
static const uint32_t cache_file_version = 3;
static const uint32_t cache_file_version = 4;
String ShaderRD::_get_cache_file_path(Version *p_version, int p_group) {
const String &sha1 = _version_get_sha1(p_version);