feat(terminal): recover webgl renderer context
This commit is contained in:
@@ -27,8 +27,10 @@ use super::mouse::{
|
||||
};
|
||||
use super::protocol::{ClientTerminalMessage, ServerTerminalMessage};
|
||||
use super::renderer::{
|
||||
CanvasDomState, CanvasPlanInput, CanvasSurfaceFrame, RenderCanvasSurfaceRequest,
|
||||
WebGlRendererState, canvas_render_plan, render_canvas_surface, render_webgl,
|
||||
CanvasDomState, CanvasPlanInput, CanvasSurfaceFrame, CanvasSurfaceMode,
|
||||
RenderCanvasSurfaceRequest, WebGlContextLifecycle, WebGlRendererState,
|
||||
attach_webgl_context_lifecycle, canvas_render_plan, render_canvas_surface, render_webgl,
|
||||
set_canvas_surface_mode, webgl_surface_mode,
|
||||
};
|
||||
use super::scrollback::ViewMode;
|
||||
use super::selection::{Selection, SelectionRect, selection_rects};
|
||||
@@ -472,6 +474,7 @@ pub fn TerminalPanel(
|
||||
let terminal_ref = NodeRef::<html::Div>::new();
|
||||
let ime_ref = NodeRef::<html::Textarea>::new();
|
||||
let canvas_ref = NodeRef::<html::Canvas>::new();
|
||||
let canvas_fallback_ref = NodeRef::<html::Canvas>::new();
|
||||
let measure_ref = NodeRef::<html::Span>::new();
|
||||
let connection_status = RwSignal::new("Connecting".to_owned());
|
||||
let ws_signal = RwSignal::new(None::<WebSocket>);
|
||||
@@ -525,8 +528,11 @@ pub fn TerminalPanel(
|
||||
Rc::new(std::cell::Cell::new(None));
|
||||
let canvas_state: Rc<std::cell::RefCell<Option<CanvasDomState>>> =
|
||||
Rc::new(std::cell::RefCell::new(None));
|
||||
let canvas_fallback_state: Rc<std::cell::RefCell<Option<CanvasDomState>>> =
|
||||
Rc::new(std::cell::RefCell::new(None));
|
||||
let webgl_state: Rc<std::cell::RefCell<Option<WebGlRendererState>>> =
|
||||
Rc::new(std::cell::RefCell::new(None));
|
||||
let webgl_context_lost: Rc<std::cell::Cell<bool>> = Rc::new(std::cell::Cell::new(false));
|
||||
|
||||
handle.serialize_text_fn.set_value(Some(Arc::new(move || {
|
||||
core_signal
|
||||
@@ -623,6 +629,34 @@ pub fn TerminalPanel(
|
||||
}
|
||||
});
|
||||
|
||||
let lifecycle_webgl_state = webgl_state.clone();
|
||||
let lifecycle_context_lost = webgl_context_lost.clone();
|
||||
Effect::new(move |prev: Option<Option<WebGlContextLifecycle>>| {
|
||||
drop(prev);
|
||||
|
||||
let renderer = options_signal.get().renderer;
|
||||
if renderer != Renderer::WebGl {
|
||||
lifecycle_context_lost.set(false);
|
||||
lifecycle_webgl_state.borrow_mut().take();
|
||||
return None;
|
||||
}
|
||||
let Some(canvas) = canvas_ref.get() else {
|
||||
return None;
|
||||
};
|
||||
let Some(canvas_el) = canvas.dyn_ref::<HtmlCanvasElement>() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
attach_webgl_context_lifecycle(
|
||||
canvas_el,
|
||||
lifecycle_webgl_state.clone(),
|
||||
lifecycle_context_lost.clone(),
|
||||
move || {
|
||||
let _ = render_tick.try_update(|t| *t += 1);
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
Effect::new(move |_| {
|
||||
let Some(on_selection_change) = on_selection_change else {
|
||||
return;
|
||||
@@ -815,6 +849,9 @@ pub fn TerminalPanel(
|
||||
let Some(canvas) = canvas_ref.get() else {
|
||||
return;
|
||||
};
|
||||
let Some(fallback_canvas) = canvas_fallback_ref.get() else {
|
||||
return;
|
||||
};
|
||||
let Some(element) = terminal_ref.get() else {
|
||||
return;
|
||||
};
|
||||
@@ -827,6 +864,9 @@ pub fn TerminalPanel(
|
||||
let Some(canvas_el) = canvas.dyn_ref::<HtmlCanvasElement>() else {
|
||||
return;
|
||||
};
|
||||
let Some(fallback_canvas_el) = fallback_canvas.dyn_ref::<HtmlCanvasElement>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let is_live = view_mode.get().is_live();
|
||||
let st = scroll_top.get();
|
||||
@@ -881,15 +921,35 @@ pub fn TerminalPanel(
|
||||
};
|
||||
match renderer {
|
||||
Renderer::WebGl => {
|
||||
if render_webgl(canvas_el, frame, &canvas_state, &webgl_state).is_err() {
|
||||
render_canvas_surface(RenderCanvasSurfaceRequest {
|
||||
if render_webgl(
|
||||
canvas_el,
|
||||
frame,
|
||||
&canvas_state,
|
||||
&webgl_state,
|
||||
&webgl_context_lost,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
set_canvas_surface_mode(
|
||||
canvas_el,
|
||||
fallback_canvas_el,
|
||||
webgl_surface_mode(true),
|
||||
);
|
||||
} else {
|
||||
set_canvas_surface_mode(
|
||||
canvas_el,
|
||||
fallback_canvas_el,
|
||||
webgl_surface_mode(false),
|
||||
);
|
||||
render_canvas_surface(RenderCanvasSurfaceRequest {
|
||||
canvas_el: fallback_canvas_el,
|
||||
frame,
|
||||
canvas_state: &canvas_state,
|
||||
canvas_state: &canvas_fallback_state,
|
||||
});
|
||||
}
|
||||
}
|
||||
Renderer::Canvas => {
|
||||
set_canvas_surface_mode(canvas_el, fallback_canvas_el, CanvasSurfaceMode::WebGl);
|
||||
render_canvas_surface(RenderCanvasSurfaceRequest {
|
||||
canvas_el,
|
||||
frame,
|
||||
@@ -1885,6 +1945,11 @@ pub fn TerminalPanel(
|
||||
node_ref=canvas_ref
|
||||
class="terminal-canvas"
|
||||
></canvas>
|
||||
<canvas
|
||||
node_ref=canvas_fallback_ref
|
||||
class="terminal-canvas"
|
||||
hidden
|
||||
></canvas>
|
||||
{move || {
|
||||
// Canvas-backed renderers: only the scroll sizer
|
||||
// and selection overlay are DOM; text/backgrounds
|
||||
|
||||
Reference in New Issue
Block a user