Wire the vendored hardware context into SoftwareServoHost
`HardwareOffscreenContext` was vendored in 048c5df but the host's
per-webview `new_rendering_context` still hard-wired
`servo::SoftwareRenderingContext`. This commit threads a
`RenderingContextKind` enum through the host so existing call sites
keep their software path, and new callers can opt into the hardware
path through `SoftwareServoHost::new_with_config_dir_and_kind(...)`.
Three changes, kept tightly scoped:
* `runtime.rs` gains a public `RenderingContextKind { Software,
Hardware }` enum and a new constructor that takes it. The
existing `new` and `new_with_config_dir` keep their signatures
and default to `Software`, so the sidecar binary and the
integration tests pick up zero behavioural change. The
private `new_rendering_context` moves from a free function to a
`&self` method so it can read `self.rendering_context_kind` and
dispatch — `Software` constructs `SoftwareRenderingContext` as
before, `Hardware` constructs the vendored
`HardwareOffscreenContext`. When the `hardware-render` feature
isn't compiled in, the `Hardware` arm returns
`ServoHostError::HardwareRenderUnavailable` instead of silently
falling back; the new constructor also rejects the request
up-front before touching the global Servo runtime flag.
* `error.rs` gains `HardwareRenderUnavailable` so the wrong-feature
path is a typed error, not a panic.
* `lib.rs` exports `RenderingContextKind` alongside
`SoftwareServoHost` so downstream code (next commit will be the
sidecar's `--rendering-context` CLI flag and the live.rs
plumbing) can name the variant directly.
This is purely an extension point — no existing call path changes,
no existing test asserts on the new enum. The next commit will add
the sidecar CLI flag and wire `live.rs::run_live` to pass the kind
through to the host so users can pick the path at startup. The
follow-up commits then extract the IOSurface from the hardware
surfman surface and bridge it across the IPC channel to GPUI's
Metal renderer, deleting the host-side `Vec<u8>` from the per-frame
hot path entirely (full plan in docs/t10-iosurface-plan.md).
cargo test -p ely_servo_host --features servo-engine --lib: 2 passed.
cargo test -p ely_servo_host --features servo-engine --test sidecar: 9 passed.
cargo test -p ely_servo_host --features servo-engine,hardware-render
--test hardware_rendering_context: 1 passed.
cargo test --bin ely_app: 120 passed, 0 failed, 2 ignored.
This commit is contained in:
@@ -24,6 +24,12 @@ pub enum ServoHostError {
|
|||||||
#[error("servo rendering context could not be made current")]
|
#[error("servo rendering context could not be made current")]
|
||||||
RenderingContextNotCurrent,
|
RenderingContextNotCurrent,
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"hardware rendering context requested but the `hardware-render` feature \
|
||||||
|
was not compiled in; rebuild with --features servo-engine,hardware-render"
|
||||||
|
)]
|
||||||
|
HardwareRenderUnavailable,
|
||||||
|
|
||||||
#[error("servo rendered frame is unavailable")]
|
#[error("servo rendered frame is unavailable")]
|
||||||
RenderedFrameUnavailable,
|
RenderedFrameUnavailable,
|
||||||
|
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ pub use host::{
|
|||||||
TouchTapRequest, WebViewSnapshot, WebViewState,
|
TouchTapRequest, WebViewSnapshot, WebViewState,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "servo-engine")]
|
#[cfg(feature = "servo-engine")]
|
||||||
pub use runtime::{ServoSurfaceSize, SoftwareServoHost};
|
pub use runtime::{RenderingContextKind, ServoSurfaceSize, SoftwareServoHost};
|
||||||
|
|||||||
@@ -53,9 +53,27 @@ impl ServoSurfaceSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects the `RenderingContext` implementation each webview gets.
|
||||||
|
///
|
||||||
|
/// `Software` uses Servo's built-in `SoftwareRenderingContext`, which
|
||||||
|
/// rasterises on the CPU. `Hardware` uses the vendored
|
||||||
|
/// [`HardwareOffscreenContext`](crate::HardwareOffscreenContext),
|
||||||
|
/// which rasterises through the real GPU adapter against a
|
||||||
|
/// `SurfaceType::Generic` offscreen surface. The `Hardware` variant
|
||||||
|
/// is only available when the `hardware-render` feature is enabled;
|
||||||
|
/// requesting it without the feature is a configuration error
|
||||||
|
/// surfaced via `ServoHostError::HardwareRenderUnavailable`.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub enum RenderingContextKind {
|
||||||
|
#[default]
|
||||||
|
Software,
|
||||||
|
Hardware,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SoftwareServoHost {
|
pub struct SoftwareServoHost {
|
||||||
servo: Servo,
|
servo: Servo,
|
||||||
default_surface_size: ServoSurfaceSize,
|
default_surface_size: ServoSurfaceSize,
|
||||||
|
rendering_context_kind: RenderingContextKind,
|
||||||
webviews: HashMap<WebViewId, HostWebView>,
|
webviews: HashMap<WebViewId, HostWebView>,
|
||||||
permissions: PermissionStore,
|
permissions: PermissionStore,
|
||||||
wake_requested: Arc<AtomicBool>,
|
wake_requested: Arc<AtomicBool>,
|
||||||
@@ -64,13 +82,35 @@ pub struct SoftwareServoHost {
|
|||||||
|
|
||||||
impl SoftwareServoHost {
|
impl SoftwareServoHost {
|
||||||
pub fn new(size: ServoSurfaceSize) -> Result<Self, ServoHostError> {
|
pub fn new(size: ServoSurfaceSize) -> Result<Self, ServoHostError> {
|
||||||
Self::new_with_config_dir(size, None)
|
Self::new_with_config_dir_and_kind(size, None, RenderingContextKind::Software)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_config_dir(
|
pub fn new_with_config_dir(
|
||||||
size: ServoSurfaceSize,
|
size: ServoSurfaceSize,
|
||||||
config_dir: Option<PathBuf>,
|
config_dir: Option<PathBuf>,
|
||||||
) -> Result<Self, ServoHostError> {
|
) -> Result<Self, ServoHostError> {
|
||||||
|
Self::new_with_config_dir_and_kind(size, config_dir, RenderingContextKind::Software)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct the host with an explicit [`RenderingContextKind`].
|
||||||
|
///
|
||||||
|
/// `Hardware` requires the `hardware-render` feature; the call
|
||||||
|
/// fails with `ServoHostError::HardwareRenderUnavailable` if the
|
||||||
|
/// feature wasn't compiled in. This is the constructor the
|
||||||
|
/// sidecar binary will use once a `--rendering-context` CLI
|
||||||
|
/// flag lands; today the default path through `new` and
|
||||||
|
/// `new_with_config_dir` keeps the software behaviour unchanged.
|
||||||
|
pub fn new_with_config_dir_and_kind(
|
||||||
|
size: ServoSurfaceSize,
|
||||||
|
config_dir: Option<PathBuf>,
|
||||||
|
rendering_context_kind: RenderingContextKind,
|
||||||
|
) -> Result<Self, ServoHostError> {
|
||||||
|
if rendering_context_kind == RenderingContextKind::Hardware
|
||||||
|
&& !cfg!(feature = "hardware-render")
|
||||||
|
{
|
||||||
|
return Err(ServoHostError::HardwareRenderUnavailable);
|
||||||
|
}
|
||||||
|
|
||||||
if SERVO_RUNTIME_STARTED
|
if SERVO_RUNTIME_STARTED
|
||||||
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -78,7 +118,7 @@ impl SoftwareServoHost {
|
|||||||
return Err(ServoHostError::RuntimeAlreadyStarted);
|
return Err(ServoHostError::RuntimeAlreadyStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
let host = Self::new_started(size, config_dir);
|
let host = Self::new_started(size, config_dir, rendering_context_kind);
|
||||||
if host.is_err() {
|
if host.is_err() {
|
||||||
SERVO_RUNTIME_STARTED.store(false, Ordering::Release);
|
SERVO_RUNTIME_STARTED.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
@@ -97,6 +137,7 @@ impl SoftwareServoHost {
|
|||||||
fn new_started(
|
fn new_started(
|
||||||
size: ServoSurfaceSize,
|
size: ServoSurfaceSize,
|
||||||
config_dir: Option<PathBuf>,
|
config_dir: Option<PathBuf>,
|
||||||
|
rendering_context_kind: RenderingContextKind,
|
||||||
) -> Result<Self, ServoHostError> {
|
) -> Result<Self, ServoHostError> {
|
||||||
let wake_requested = Arc::new(AtomicBool::new(false));
|
let wake_requested = Arc::new(AtomicBool::new(false));
|
||||||
let mut builder = ServoBuilder::default()
|
let mut builder = ServoBuilder::default()
|
||||||
@@ -109,6 +150,7 @@ impl SoftwareServoHost {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
servo,
|
servo,
|
||||||
default_surface_size: size,
|
default_surface_size: size,
|
||||||
|
rendering_context_kind,
|
||||||
webviews: HashMap::new(),
|
webviews: HashMap::new(),
|
||||||
permissions: Rc::new(RefCell::new(HashMap::new())),
|
permissions: Rc::new(RefCell::new(HashMap::new())),
|
||||||
wake_requested,
|
wake_requested,
|
||||||
@@ -335,7 +377,7 @@ impl SoftwareServoHost {
|
|||||||
size: ServoSurfaceSize,
|
size: ServoSurfaceSize,
|
||||||
) -> Result<WebViewId, ServoHostError> {
|
) -> Result<WebViewId, ServoHostError> {
|
||||||
let webview_id = WebViewId::new();
|
let webview_id = WebViewId::new();
|
||||||
let rendering_context = Self::new_rendering_context(size)?;
|
let rendering_context = self.new_rendering_context(size)?;
|
||||||
let delegate =
|
let delegate =
|
||||||
Rc::new(HostWebViewDelegate::new(profile_id.clone(), self.permissions.clone()));
|
Rc::new(HostWebViewDelegate::new(profile_id.clone(), self.permissions.clone()));
|
||||||
let webview = WebViewBuilder::new(&self.servo, rendering_context.clone())
|
let webview = WebViewBuilder::new(&self.servo, rendering_context.clone())
|
||||||
@@ -365,12 +407,24 @@ impl SoftwareServoHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_rendering_context(
|
fn new_rendering_context(
|
||||||
|
&self,
|
||||||
size: ServoSurfaceSize,
|
size: ServoSurfaceSize,
|
||||||
) -> Result<Rc<dyn RenderingContext>, ServoHostError> {
|
) -> Result<Rc<dyn RenderingContext>, ServoHostError> {
|
||||||
let rendering_context = Rc::new(
|
let rendering_context: Rc<dyn RenderingContext> = match self.rendering_context_kind {
|
||||||
servo::SoftwareRenderingContext::new(size.physical())
|
RenderingContextKind::Software => Rc::new(
|
||||||
.map_err(|_| ServoHostError::RenderingContextUnavailable)?,
|
servo::SoftwareRenderingContext::new(size.physical())
|
||||||
);
|
.map_err(|_| ServoHostError::RenderingContextUnavailable)?,
|
||||||
|
),
|
||||||
|
#[cfg(feature = "hardware-render")]
|
||||||
|
RenderingContextKind::Hardware => Rc::new(
|
||||||
|
crate::HardwareOffscreenContext::new(size.physical())
|
||||||
|
.map_err(|_| ServoHostError::RenderingContextUnavailable)?,
|
||||||
|
),
|
||||||
|
#[cfg(not(feature = "hardware-render"))]
|
||||||
|
RenderingContextKind::Hardware => {
|
||||||
|
return Err(ServoHostError::HardwareRenderUnavailable);
|
||||||
|
}
|
||||||
|
};
|
||||||
rendering_context.make_current().map_err(|_| ServoHostError::RenderingContextNotCurrent)?;
|
rendering_context.make_current().map_err(|_| ServoHostError::RenderingContextNotCurrent)?;
|
||||||
Ok(rendering_context)
|
Ok(rendering_context)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user