Skip to content

Commit

Permalink
feat: switch to glutin (#163)
Browse files Browse the repository at this point in the history
* Add rendering module

* Remove swap chain

* Generate GL bindings

* Add create method

* Add surface methods

* Replace surfman with glutin context

* Fix macOS

* Fix wayland multiwindow

* Remove unused dependencies

* Remove comments

* Fix typo

---------

Signed-off-by: Ngo Iok Ui (Wu Yu Wei) <[email protected]>
Co-authored-by: Wu Yuwei <Wu Yu Wei>
  • Loading branch information
wusyong authored Aug 19, 2024
1 parent 7b61d8c commit e3352a9
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 153 deletions.
63 changes: 59 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 3 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ env_logger = "0.10"
euclid = "0.22"
getopts = "0.2.17"
gleam = "0.15"
glutin = "0.32.0"
glutin-winit = "0.5.0"
ipc-channel = "0.18"
keyboard-types = "0.7"
log = "0.4"
raw-window-handle = { version = "0.6", features = ["std"] }
sparkle = "0.1.26"
surfman = { version = "0.9", features = ["chains", "sm-raw-window-handle-06"] }
thiserror = "1.0"
winit = { version = "0.30", features = ["rwh_06"] }
# Servo repo crates
Expand Down Expand Up @@ -99,10 +100,6 @@ cargo-packager-resource-resolver = { version = "0.1.1", features = [
], optional = true }
url = "2.5.2"

[target.'cfg(target_os = "windows")'.dependencies]
surfman = { version = "0.9", features = ["sm-angle-default"] }
mozangle = { version = "0.5.1", features = ["egl", "build_dlls"] }

[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
objc2 = "0.5"
objc2-app-kit = {version = "0.2", features = ["NSView", "NSResponder", "NSWindow"]}
Expand All @@ -117,4 +114,4 @@ lto = true

# Tell clippy to allow e.g. #[cfg(macos)]
[lints.clippy]
mismatched_target_os = "allow"
mismatched_target_os = "allow"
122 changes: 35 additions & 87 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use script_traits::{
};
use servo_geometry::DeviceIndependentPixel;
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
use surfman::Surface;
use webrender::{RenderApi, Transaction};
use webrender_api::units::{
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, LayoutPoint, LayoutRect, LayoutSize,
Expand All @@ -39,11 +38,11 @@ use webrender_api::{
use webrender_traits::display_list::{HitTestInfo, ScrollTree};
use webrender_traits::{
CanvasToCompositorMsg, CompositorHitTestResult, FontToCompositorMsg, ImageUpdate,
NetToCompositorMsg, RenderingContext, ScriptToCompositorMsg, SerializedImageUpdate,
UntrustedNodeAddress,
NetToCompositorMsg, ScriptToCompositorMsg, SerializedImageUpdate, UntrustedNodeAddress,
};
use winit::window::WindowId;

use crate::rendering::RenderingContext;
use crate::touch::{TouchAction, TouchHandler};
use crate::window::Window;

Expand Down Expand Up @@ -104,9 +103,6 @@ const MIN_ZOOM: f32 = 0.1;
/// The compositor will communicate with Servo using messages from the Constellation,
/// then composite the WebRender frames and present the surface to the window.
pub struct IOCompositor {
/// All surfaces that Compositor currently owns.
pub surfaces: HashMap<WindowId, Option<Surface>>,

/// The current window that Compositor is handling.
pub current_window: WindowId,

Expand Down Expand Up @@ -176,7 +172,7 @@ pub struct IOCompositor {
/// The webrender interface, if enabled.
pub webrender_api: RenderApi,

/// The surfman instance that webrender targets
/// The glutin instance that webrender targets
pub rendering_context: RenderingContext,

/// The GL bindings for webrender
Expand Down Expand Up @@ -348,10 +344,7 @@ impl IOCompositor {
exit_after_load: bool,
convert_mouse_to_touch: bool,
) -> Self {
let mut surfaces = HashMap::new();
surfaces.insert(current_window, None);
let compositor = IOCompositor {
surfaces,
current_window,
viewport,
port: state.receiver,
Expand Down Expand Up @@ -394,15 +387,7 @@ impl IOCompositor {
}

/// Consume compositor itself and deinit webrender.
pub fn deinit(mut self) {
if let Err(err) = self.rendering_context.make_gl_context_current() {
warn!("Failed to make GL context current: {:?}", err);
}
for surface in self.surfaces.values_mut() {
surface
.take()
.map(|s| self.rendering_context.destroy_surface(s));
}
pub fn deinit(self) {
self.webrender.deinit();
}

Expand Down Expand Up @@ -453,34 +438,6 @@ impl IOCompositor {
self.shutdown_state = ShutdownState::FinishedShuttingDown;
}

/// The underlying native surface can be lost during servo's lifetime.
/// On Android, for example, this happens when the app is sent to background.
/// We need to unbind the surface so that we don't try to use it again.
pub fn invalidate_native_surface(&mut self) {
debug!("Invalidating native surface in compositor");
if let Err(e) = self.rendering_context.unbind_native_surface_from_context() {
warn!("Unbinding native surface from context failed ({:?})", e);
}
}

/// On Android, this function will be called when the app moves to foreground
/// and the system creates a new native surface that needs to bound to the current
/// context.
#[allow(unsafe_code)]
#[allow(clippy::not_unsafe_ptr_arg_deref)] // It has an unsafe block inside
pub fn replace_native_surface(&mut self, native_widget: *mut c_void, coords: DeviceIntSize) {
debug!("Replacing native surface in compositor: {native_widget:?}");
let connection = self.rendering_context.connection();
let native_widget =
unsafe { connection.create_native_widget_from_ptr(native_widget, coords.to_untyped()) };
if let Err(e) = self
.rendering_context
.bind_native_surface_to_context(native_widget)
{
warn!("Binding native surface to context failed ({:?})", e);
}
}

fn handle_browser_message(
&mut self,
msg: CompositorMsg,
Expand Down Expand Up @@ -1282,23 +1239,16 @@ impl IOCompositor {
self.current_window,
window.id()
);
if let Some(Some(new_surface)) = self.surfaces.insert(window.id(), None) {
// Swap the surface
self.rendering_context.with_front_buffer(|_, old_surface| {
self.surfaces.insert(self.current_window, Some(old_surface));
new_surface
});
self.current_window = window.id();
self.scale_factor = Scale::new(window.scale_factor() as f32);
self.resize(window.size(), window);
}
self.current_window = window.id();
self.scale_factor = Scale::new(window.scale_factor() as f32);
self.resize(window.size(), window);
}
}

/// Resize the rendering context and all web views. Return true if the compositor should repaint and present
/// after this.
pub fn resize(&mut self, size: Size2D<i32, DevicePixel>, window: &mut Window) -> bool {
let need_resize = self.on_resize_window_event(size);
let need_resize = self.on_resize_window_event(size, window);

if let Some(panel) = &mut window.panel {
let rect = DeviceIntRect::from_size(size);
Expand All @@ -1319,12 +1269,14 @@ impl IOCompositor {

/// Handle the window resize event and return a boolean to tell embedder if it should further
/// handle the resize event.
pub fn on_resize_window_event(&mut self, new_viewport: DeviceIntSize) -> bool {
pub fn on_resize_window_event(&mut self, new_viewport: DeviceIntSize, window: &Window) -> bool {
if self.shutdown_state != ShutdownState::NotShuttingDown {
return false;
}

let _ = self.rendering_context.resize(new_viewport.to_untyped());
let _ = self
.rendering_context
.resize(&window.surface, new_viewport.to_untyped());
self.viewport = new_viewport;
let mut transaction = Transaction::new();
transaction.set_document_view(DeviceIntRect::from_size(self.viewport));
Expand Down Expand Up @@ -1959,8 +1911,8 @@ impl IOCompositor {
}

/// Composite to the given target if any, or the current target otherwise.
pub fn composite(&mut self) {
match self.composite_specific_target() {
pub fn composite(&mut self, window: &Window) {
match self.composite_specific_target(window) {
Ok(_) => {
if self.exit_after_load {
println!("Shutting down the Constellation after generating an output file or exit flag specified");
Expand All @@ -1974,8 +1926,11 @@ impl IOCompositor {
}

/// Composite to the given target if any, or the current target otherwise.
fn composite_specific_target(&mut self) -> Result<(), UnableToComposite> {
if let Err(err) = self.rendering_context.make_gl_context_current() {
fn composite_specific_target(&mut self, window: &Window) -> Result<(), UnableToComposite> {
if let Err(err) = self
.rendering_context
.make_gl_context_current(&window.surface)
{
warn!("Failed to make GL context current: {:?}", err);
}
self.assert_no_gl_error();
Expand All @@ -1999,17 +1954,6 @@ impl IOCompositor {
}
}

// Bind the webrender framebuffer
let framebuffer_object = self
.rendering_context
.context_surface_info()
.unwrap_or(None)
.map(|info| info.framebuffer_object)
.unwrap_or(0);
self.webrender_gl
.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object);
self.assert_gl_framebuffer_complete();

profile(
ProfilerCategory::Compositing,
None,
Expand Down Expand Up @@ -2071,7 +2015,7 @@ impl IOCompositor {
}
}

if let Err(err) = self.rendering_context.present() {
if let Err(err) = self.rendering_context.present(&window.surface) {
warn!("Failed to present surface: {:?}", err);
}
self.composition_request = CompositionRequest::NoCompositingNecessary;
Expand Down Expand Up @@ -2147,19 +2091,21 @@ impl IOCompositor {
self.zoom_action = false;
}

match self.composition_request {
CompositionRequest::NoCompositingNecessary => {}
CompositionRequest::CompositeNow(_) => self.composite(),
}
if let Some(window) = windows.get(&self.current_window) {
match self.composition_request {
CompositionRequest::NoCompositingNecessary => {}
CompositionRequest::CompositeNow(_) => self.composite(window),
}

// Run the WebXR main thread
self.webxr_main_thread.run_one_frame();
// Run the WebXR main thread
self.webxr_main_thread.run_one_frame();

// The WebXR thread may make a different context current
let _ = self.rendering_context.make_gl_context_current();
// The WebXR thread may make a different context current
let _ = self
.rendering_context
.make_gl_context_current(&window.surface);

if !self.pending_scroll_zoom_events.is_empty() {
if let Some(window) = windows.get(&self.current_window) {
if !self.pending_scroll_zoom_events.is_empty() {
self.process_pending_scroll_events(window)
}
}
Expand All @@ -2175,7 +2121,9 @@ impl IOCompositor {
let need_recomposite = matches!(msg, CompositorMsg::NewWebRenderFrameReady(_));
let keep_going = self.handle_browser_message(msg, windows);
if need_recomposite {
self.composite();
if let Some(window) = windows.get(&self.current_window) {
self.composite(window);
}
break;
}
if !keep_going {
Expand Down
3 changes: 3 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ pub enum Error {
/// A general error that may occur while running the Winit event loop.
#[error(transparent)]
EventLoopError(#[from] winit::error::EventLoopError),
/// Glutin errors.
#[error(transparent)]
GlutinError(#[from] glutin::error::Error),
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub mod config;
pub mod errors;
/// Utilities to handle keyboard inputs and states.
pub mod keyboard;
/// Verso's rendering context.
pub mod rendering;
/// Utilities to handle touch inputs and states.
pub mod touch;
/// Main entry types and functions.
Expand Down
Loading

0 comments on commit e3352a9

Please sign in to comment.