Skip to content
This repository has been archived by the owner on Feb 16, 2025. It is now read-only.

OpenXR: Separate graphics handling from main OpenXR code #243

Merged
merged 3 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions webxr/openxr/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use euclid::{Size2D, UnknownUnit};
use openxr::{ExtensionSet, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId};
use surfman::Context as SurfmanContext;
use surfman::Device as SurfmanDevice;
use surfman::Error as SurfmanError;
use surfman::SurfaceTexture;
use webxr_api::Error;

pub enum GraphicsProvider {}

pub trait GraphicsProviderMethods<G: Graphics> {
fn enable_graphics_extensions(exts: &mut ExtensionSet);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it is better if you use associated type, for example:

type GraphicsType: Graphics;

    fn create_session(
        device: &SurfmanDevice,
        instance: &Instance,
        system: SystemId,
    ) -> Result<(Session<Self::GraphicsType>, FrameWaiter, FrameStream<Self::GraphicsType>), Error>;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the PR code is strictly equivalent, and I don't have a good sense for whether we should prefer one style over the other when there's no behaviour difference like this case.

fn pick_format(formats: &[u32]) -> u32;
fn create_session(
device: &SurfmanDevice,
instance: &Instance,
system: SystemId,
) -> Result<(Session<G>, FrameWaiter, FrameStream<G>), Error>;
fn surface_texture_from_swapchain_texture(
image: <G as Graphics>::SwapchainImage,
device: &mut SurfmanDevice,
context: &mut SurfmanContext,
size: &Size2D<i32, UnknownUnit>,
) -> Result<SurfaceTexture, SurfmanError>;
}
138 changes: 138 additions & 0 deletions webxr/openxr/graphics_d3d11.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use std::{mem, ptr};

use euclid::{Size2D, UnknownUnit};
use log::warn;
use openxr::d3d::{Requirements, SessionCreateInfoD3D11, D3D11};
use openxr::{
ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId,
};
use surfman::Adapter as SurfmanAdapter;
use surfman::Context as SurfmanContext;
use surfman::Device as SurfmanDevice;
use surfman::Error as SurfmanError;
use surfman::SurfaceTexture;
use webxr_api::Error;
use winapi::shared::winerror::{DXGI_ERROR_NOT_FOUND, S_OK};
use winapi::shared::{dxgi, dxgiformat};
use winapi::um::d3d11::ID3D11Texture2D;
use winapi::Interface;
use wio::com::ComPtr;

use crate::openxr::graphics::{GraphicsProvider, GraphicsProviderMethods};
use crate::openxr::{create_instance, AppInfo};

pub type Backend = D3D11;

impl GraphicsProviderMethods<D3D11> 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 => 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<D3D11>, FrameWaiter, FrameStream<D3D11>), 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::<D3D11>(
system,
&SessionCreateInfoD3D11 {
device: d3d_device as *mut _,
},
)
.map_err(|e| Error::BackendSpecific(format!("Instance::create_session {:?}", e)))
}
}

fn surface_texture_from_swapchain_texture(
image: <D3D11 as Graphics>::SwapchainImage,
device: &mut SurfmanDevice,
context: &mut SurfmanContext,
size: &Size2D<i32, UnknownUnit>,
) -> Result<SurfaceTexture, SurfmanError> {
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<ComPtr<dxgi::IDXGIAdapter1>, 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<SurfmanAdapter> {
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()))
}
27 changes: 13 additions & 14 deletions webxr/openxr/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ use std::mem::MaybeUninit;

use euclid::RigidTransform3D;
use log::debug;
use openxr::d3d::D3D11;
use openxr::sys::{
HandJointLocationsEXT, HandJointsLocateInfoEXT, HandTrackingAimStateFB,
FB_HAND_TRACKING_AIM_EXTENSION_NAME,
};
use openxr::{
self, Action, ActionSet, Binding, FrameState, Hand as HandEnum, HandJoint, HandJointLocation,
HandTracker, HandTrackingAimFlagsFB, Instance, Path, Posef, Session, Space, SpaceLocationFlags,
HAND_JOINT_COUNT,
self, Action, ActionSet, Binding, FrameState, Graphics, Hand as HandEnum, HandJoint,
HandJointLocation, HandTracker, HandTrackingAimFlagsFB, Instance, Path, Posef, Session, Space,
SpaceLocationFlags, HAND_JOINT_COUNT,
};
use webxr_api::Finger;
use webxr_api::Hand;
Expand Down Expand Up @@ -70,10 +69,10 @@ pub struct Frame {
}

impl ClickState {
fn update_from_action(
fn update_from_action<G: Graphics>(
&mut self,
action: &Action<bool>,
session: &Session<D3D11>,
session: &Session<G>,
menu_selected: bool,
) -> (/* is_active */ bool, Option<SelectEvent>) {
let click = action.state(session, Path::NULL).unwrap();
Expand Down Expand Up @@ -147,11 +146,11 @@ fn hand_str(h: Handedness) -> &'static str {
}

impl OpenXRInput {
pub fn new(
pub fn new<G: Graphics>(
id: InputId,
handedness: Handedness,
action_set: &ActionSet,
session: &Session<D3D11>,
session: &Session<G>,
needs_hands: bool,
supported_interaction_profiles: Vec<&'static str>,
) -> Self {
Expand Down Expand Up @@ -306,9 +305,9 @@ impl OpenXRInput {
}
}

pub fn setup_inputs(
pub fn setup_inputs<G: Graphics>(
instance: &Instance,
session: &Session<D3D11>,
session: &Session<G>,
needs_hands: bool,
supported_interaction_profiles: Vec<&'static str>,
) -> (ActionSet, Self, Self) {
Expand Down Expand Up @@ -447,9 +446,9 @@ impl OpenXRInput {
ret
}

pub fn frame(
pub fn frame<G: Graphics>(
&mut self,
session: &Session<D3D11>,
session: &Session<G>,
frame_state: &FrameState,
base_space: &Space,
viewer: &RigidTransform3D<f32, Viewer, Native>,
Expand Down Expand Up @@ -637,12 +636,12 @@ fn pose_for(
}
}

fn locate_hand(
fn locate_hand<G: Graphics>(
base_space: &Space,
tracker: &HandTracker,
frame_state: &FrameState,
use_alternate_input_source: bool,
session: &Session<D3D11>,
session: &Session<G>,
aim_state: &mut Option<HandTrackingAimStateFB>,
) -> Option<Box<Hand<JointFrame>>> {
let mut state = HandTrackingAimStateFB::out(std::ptr::null_mut());
Expand Down
Loading
Loading