diff --git a/drivers/d3d12/d3d12_hooks.cpp b/drivers/d3d12/d3d12_hooks.cpp new file mode 100644 index 00000000000..c6248263136 --- /dev/null +++ b/drivers/d3d12/d3d12_hooks.cpp @@ -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; + } +} diff --git a/drivers/d3d12/d3d12_hooks.h b/drivers/d3d12/d3d12_hooks.h new file mode 100644 index 00000000000..bd6b89b6601 --- /dev/null +++ b/drivers/d3d12/d3d12_hooks.h @@ -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; } +}; diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp index 3d1adc0d554..10699e75765 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp @@ -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" diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index b964cb85b6f..2b8e5294271 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -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(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 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 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 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 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 info_queue; res = device.As(&info_queue); diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index bc5ccc01235..2b9133344ca 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -275,6 +275,9 @@ private: UINT mapped_subresource = UINT_MAX; SelfList pending_clear{ this }; +#ifdef DEBUG_ENABLED + bool created_from_extension = false; +#endif }; SelfList::List textures_pending_clear; diff --git a/modules/openxr/extensions/SCsub b/modules/openxr/extensions/SCsub index 15eab5d707a..92e93299677 100644 --- a/modules/openxr/extensions/SCsub +++ b/modules/openxr/extensions/SCsub @@ -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 diff --git a/modules/openxr/extensions/platform/openxr_d3d12_extension.cpp b/modules/openxr/extensions/platform/openxr_d3d12_extension.cpp new file mode 100644 index 00000000000..747082b367e --- /dev/null +++ b/modules/openxr/extensions/platform/openxr_d3d12_extension.cpp @@ -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 OpenXRD3D12Extension::get_requested_extensions() { + HashMap 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 &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 &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 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 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 diff --git a/modules/openxr/extensions/platform/openxr_d3d12_extension.h b/modules/openxr/extensions/platform/openxr_d3d12_extension.h new file mode 100644 index 00000000000..7fef6e4862b --- /dev/null +++ b/modules/openxr/extensions/platform/openxr_d3d12_extension.h @@ -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 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 &p_usable_swap_chains) override; + virtual void get_usable_depth_formats(Vector &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 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 graphics_device; + ComPtr command_queue; +}; + +#endif // D3D12_ENABLED diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 4e0a0535c44..a51d3e3759f 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -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."); diff --git a/modules/openxr/openxr_platform_inc.h b/modules/openxr/openxr_platform_inc.h index 7c0aeedd3f8..20a6c25f3ea 100644 --- a/modules/openxr/openxr_platform_inc.h +++ b/modules/openxr/openxr_platform_inc.h @@ -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 #endif // X11_ENABLED diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 8910876ffa1..ad4a117dd87 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -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);