/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::{mem, ptr}; use euclid::{Size2D, UnknownUnit}; use log::warn; use openxr::d3d::{D3D11, Requirements, SessionCreateInfoD3D11}; use openxr::{ ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId, }; use surfman::{ Adapter as SurfmanAdapter, Context as SurfmanContext, Device as SurfmanDevice, Error as SurfmanError, SurfaceTexture, }; use webxr_api::Error; use winapi::Interface; use winapi::shared::winerror::{DXGI_ERROR_NOT_FOUND, S_OK}; use winapi::shared::{dxgi, dxgiformat}; use winapi::um::d3d11::ID3D11Texture2D; use wio::com::ComPtr; use crate::openxr::graphics::{GraphicsProvider, GraphicsProviderMethods}; use crate::openxr::{AppInfo, create_instance}; pub type Backend = D3D11; impl GraphicsProviderMethods for GraphicsProvider { fn enable_graphics_extensions(exts: &mut ExtensionSet) { exts.khr_d3d11_enable = true; } fn pick_format(formats: &[u32]) -> u32 { // TODO: extract the format from surfman's device and pick a matching // valid format based on that. For now, assume that eglChooseConfig will // gravitate to B8G8R8A8. warn!("Available formats: {:?}", formats); for format in formats { match *format { dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM_SRGB => return *format, dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM => return *format, //dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM => return *format, f => { warn!("Backend requested unsupported format {:?}", f); }, } } panic!("No formats supported amongst {:?}", formats); } fn create_session( device: &SurfmanDevice, instance: &Instance, system: SystemId, ) -> Result<(Session, FrameWaiter, FrameStream), Error> { // Get the current surfman device and extract its D3D device. This will ensure // that the OpenXR runtime's texture will be shareable with surfman's surfaces. let native_device = device.native_device(); let d3d_device = native_device.d3d11_device; // FIXME: we should be using these graphics requirements to drive the actual // d3d device creation, rather than assuming the device that surfman // already created is appropriate. OpenXR returns a validation error // unless we call this method, so we call it and ignore the results // in the short term. let _requirements = D3D11::requirements(instance, system) .map_err(|e| Error::BackendSpecific(format!("D3D11::requirements {:?}", e)))?; unsafe { instance .create_session::( system, &SessionCreateInfoD3D11 { device: d3d_device as *mut _, }, ) .map_err(|e| Error::BackendSpecific(format!("Instance::create_session {:?}", e))) } } fn surface_texture_from_swapchain_texture( image: ::SwapchainImage, device: &mut SurfmanDevice, context: &mut SurfmanContext, size: &Size2D, ) -> Result { unsafe { let image = ComPtr::from_raw(image as *mut ID3D11Texture2D); image.AddRef(); device.create_surface_texture_from_texture(context, size, image) } } } fn get_matching_adapter( requirements: &Requirements, ) -> Result, String> { unsafe { let mut factory_ptr: *mut dxgi::IDXGIFactory1 = ptr::null_mut(); let result = dxgi::CreateDXGIFactory1( &dxgi::IDXGIFactory1::uuidof(), &mut factory_ptr as *mut _ as *mut _, ); assert_eq!(result, S_OK); let factory = ComPtr::from_raw(factory_ptr); let index = 0; loop { let mut adapter_ptr = ptr::null_mut(); let result = factory.EnumAdapters1(index, &mut adapter_ptr); if result == DXGI_ERROR_NOT_FOUND { return Err("No matching adapter".to_owned()); } assert_eq!(result, S_OK); let adapter = ComPtr::from_raw(adapter_ptr); let mut adapter_desc = mem::zeroed(); let result = adapter.GetDesc1(&mut adapter_desc); assert_eq!(result, S_OK); let adapter_luid = &adapter_desc.AdapterLuid; if adapter_luid.LowPart == requirements.adapter_luid.LowPart && adapter_luid.HighPart == requirements.adapter_luid.HighPart { return Ok(adapter); } } } } #[allow(unused)] pub fn create_surfman_adapter() -> Option { let instance = create_instance(false, false, false, &AppInfo::default()).ok()?; let system = instance .instance .system(FormFactor::HEAD_MOUNTED_DISPLAY) .ok()?; let requirements = D3D11::requirements(&instance.instance, system).ok()?; let adapter = get_matching_adapter(&requirements).ok()?; Some(SurfmanAdapter::from_dxgi_adapter(adapter.up())) }