three_d/window/
headless.rs1use crate::{Context, CoreError};
2use glutin_029::{
3 dpi::PhysicalSize, event_loop::EventLoop, ContextBuilder, ContextCurrentState, CreationError,
4 NotCurrent, PossiblyCurrent,
5};
6use std::rc::Rc;
7use thiserror::Error;
8
9#[derive(Error, Debug)]
13#[allow(missing_docs)]
14pub enum HeadlessError {
15 #[error("glutin error")]
16 GlutinCreationError(#[from] glutin_029::CreationError),
17 #[error("glutin error")]
18 GlutinContextError(#[from] glutin_029::ContextError),
19 #[error("error in three-d")]
20 ThreeDError(#[from] CoreError),
21}
22
23#[derive(Clone)]
29pub struct HeadlessContext {
30 context: Context,
31 _glutin_context: Rc<glutin_029::Context<PossiblyCurrent>>,
32}
33
34impl HeadlessContext {
35 #[allow(unsafe_code)]
39 pub fn new() -> Result<Self, HeadlessError> {
40 let cb = ContextBuilder::new();
41 let glutin_context = build_context(cb)?;
42 let glutin_context = unsafe { glutin_context.make_current().map_err(|(_, e)| e)? };
43 let context = Context::from_gl_context(std::sync::Arc::new(unsafe {
44 crate::context::Context::from_loader_function(|s| {
45 glutin_context.get_proc_address(s) as *const _
46 })
47 }))?;
48 Ok(Self {
49 context,
50 _glutin_context: Rc::new(glutin_context),
51 })
52 }
53}
54
55impl std::ops::Deref for HeadlessContext {
56 type Target = Context;
57 fn deref(&self) -> &Self::Target {
58 &self.context
59 }
60}
61
62fn build_context_headless<T1: ContextCurrentState>(
72 cb: ContextBuilder<T1>,
73 el: &EventLoop<()>,
74) -> Result<glutin_029::Context<NotCurrent>, CreationError> {
75 let size_one = PhysicalSize::new(1, 1);
76 cb.build_headless(&el, size_one)
77}
78
79#[cfg(target_os = "linux")]
80fn build_context_osmesa<T1: ContextCurrentState>(
81 cb: ContextBuilder<T1>,
82) -> Result<glutin_029::Context<NotCurrent>, CreationError> {
83 use glutin_029::platform::unix::HeadlessContextExt;
84 let size_one = PhysicalSize::new(1, 1);
85 cb.build_osmesa(size_one)
86}
87
88#[cfg(target_os = "linux")]
89fn build_context<T1: ContextCurrentState>(
90 cb: ContextBuilder<T1>,
91) -> Result<glutin_029::Context<NotCurrent>, CreationError> {
92 let _err3 = match build_context_osmesa(cb.clone()) {
107 Ok(ctx) => return Ok(ctx),
108 Err(err) => err,
109 };
110
111 let el = EventLoop::new();
112
113 let err2 = match build_context_headless(cb, &el) {
114 Ok(ctx) => return Ok(ctx),
115 Err(err) => err,
116 };
117
118 Err(err2)
119}
120
121#[cfg(not(target_os = "linux"))]
122fn build_context<T1: ContextCurrentState>(
123 cb: ContextBuilder<T1>,
124) -> Result<glutin_029::Context<NotCurrent>, CreationError> {
125 let el = EventLoop::new();
126 build_context_headless(cb.clone(), &el)
127}