Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only start WebGPU thread if an adapter is requested #25030

Merged
merged 2 commits into from Jan 13, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Some generated files are not rendered by default. Learn more.

@@ -173,7 +173,7 @@ use std::sync::Arc;
use std::thread;
use style_traits::viewport::ViewportConstraints;
use style_traits::CSSPixel;
use webgpu::WebGPU;
use webgpu::{WebGPU, WebGPURequest};
use webvr_traits::{WebVREvent, WebVRMsg};

type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>;
@@ -242,6 +242,9 @@ struct BrowsingContextGroup {
/// share an event loop, since they can use `document.domain`
/// to become same-origin, at which point they can share DOM objects.
event_loops: HashMap<Host, Weak<EventLoop>>,

/// The set of all WebGPU channels in this BrowsingContextGroup.
webgpus: HashMap<Host, WebGPU>,
}

/// The `Constellation` itself. In the servo browser, there is one
@@ -450,10 +453,6 @@ pub struct Constellation<Message, LTF, STF> {
/// Entry point to create and get channels to a WebGLThread.
webgl_threads: Option<WebGLThreads>,

/// An IPC channel for the constellation to send messages to the
/// WebGPU threads.
webgpu: Option<WebGPU>,

/// A channel through which messages can be sent to the webvr thread.
webvr_chan: Option<IpcSender<WebVRMsg>>,

@@ -537,9 +536,6 @@ pub struct InitialConstellationState {
/// Entry point to create and get channels to a WebGLThread.
pub webgl_threads: Option<WebGLThreads>,

/// A channel to the WebGPU threads.
pub webgpu: Option<WebGPU>,

/// A channel to the webgl thread.
pub webvr_chan: Option<IpcSender<WebVRMsg>>,

@@ -973,7 +969,6 @@ where
(rng, prob)
}),
webgl_threads: state.webgl_threads,
webgpu: state.webgpu,
webvr_chan: state.webvr_chan,
webxr_registry: state.webxr_registry,
canvas_chan,
@@ -1230,7 +1225,6 @@ where
.webgl_threads
.as_ref()
.map(|threads| threads.pipeline()),
webgpu: self.webgpu.clone(),
webvr_chan: self.webvr_chan.clone(),
webxr_registry: self.webxr_registry.clone(),
player_context: self.player_context.clone(),
@@ -1945,9 +1939,65 @@ where
EmbedderMsg::MediaSessionEvent(event),
));
},
FromScriptMsg::RequestAdapter(sender, options, ids) => self
.handle_request_wgpu_adapter(
source_pipeline_id,
BrowsingContextId::from(source_top_ctx_id),
FromScriptMsg::RequestAdapter(sender, options, ids),
),
}
}

fn handle_request_wgpu_adapter(
&mut self,
source_pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
request: FromScriptMsg,
) {
let browsing_context_group_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(bc) => &bc.bc_group_id,
None => return warn!("Browsing context not found"),
};
let host = match self
.pipelines
.get(&source_pipeline_id)
.map(|pipeline| &pipeline.url)
{
Some(ref url) => match reg_host(&url) {
Some(host) => host,
None => return warn!("Invalid host url"),
},
None => return warn!("ScriptMsg from closed pipeline {:?}.", source_pipeline_id),
};
match self
.browsing_context_group_set
.get_mut(&browsing_context_group_id)
{
Some(browsing_context_group) => {
let adapter_request =
if let FromScriptMsg::RequestAdapter(sender, options, ids) = request {
WebGPURequest::RequestAdapter(sender, options, ids)
} else {
return warn!("Wrong message type in handle_request_wgpu_adapter");
};
let send = match browsing_context_group.webgpus.entry(host) {
Entry::Vacant(v) => v
.insert(match WebGPU::new() {
Some(webgpu) => webgpu,
None => return warn!("Failed to create new WebGPU thread"),
})
.0
.send(adapter_request),
Entry::Occupied(o) => o.get().0.send(adapter_request),
};
if send.is_err() {
return warn!("Failed to send request adapter message on WebGPU channel");
}
},
None => return warn!("Browsing context group not found"),
};
}

fn handle_request_from_layout(&mut self, message: FromLayoutMsg) {
debug!("Constellation got {:?} message", message);
match message {
@@ -2496,12 +2546,25 @@ where
}
}

if let Some(webgpu) = self.webgpu.as_ref() {
debug!("Exiting WebGPU thread.");
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
if let Err(e) = webgpu.exit(sender) {
warn!("Exit WebGPU Thread failed ({})", e);
}
debug!("Exiting WebGPU threads.");
let receivers = self
.browsing_context_group_set
.values()
.map(|browsing_context_group| {
browsing_context_group.webgpus.values().map(|webgpu| {
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
if let Err(e) = webgpu.exit(sender) {
warn!("Exit WebGPU Thread failed ({})", e);
None
} else {
Some(receiver)
}
})
})
.flatten()
.filter_map(|r| r);

for receiver in receivers {
if let Err(e) = receiver.recv() {
warn!("Failed to receive exit response from WebGPU ({})", e);
}
@@ -48,7 +48,6 @@ use std::process;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use webgpu::WebGPU;
use webvr_traits::WebVRMsg;

/// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an
@@ -194,9 +193,6 @@ pub struct InitialPipelineState {
/// A channel to the WebGL thread.
pub webgl_chan: Option<WebGLPipeline>,

/// A channel to the WebGPU threads.
pub webgpu: Option<WebGPU>,

/// A channel to the webvr thread.
pub webvr_chan: Option<IpcSender<WebVRMsg>>,

@@ -309,7 +305,6 @@ impl Pipeline {
webrender_document: state.webrender_document,
webgl_chan: state.webgl_chan,
webvr_chan: state.webvr_chan,
webgpu: state.webgpu,
webxr_registry: state.webxr_registry,
player_context: state.player_context,
};
@@ -516,7 +511,6 @@ pub struct UnprivilegedPipelineContent {
webrender_image_api_sender: net_traits::WebrenderIpcSender,
webrender_document: webrender_api::DocumentId,
webgl_chan: Option<WebGLPipeline>,
webgpu: Option<WebGPU>,
webvr_chan: Option<IpcSender<WebVRMsg>>,
webxr_registry: webxr_api::Registry,
player_context: WindowGLContext,
@@ -569,7 +563,6 @@ impl UnprivilegedPipelineContent {
pipeline_namespace_id: self.pipeline_namespace_id,
content_process_shutdown_chan: content_process_shutdown_chan,
webgl_chan: self.webgl_chan,
webgpu: self.webgpu,
webvr_chan: self.webvr_chan,
webxr_registry: self.webxr_registry,
webrender_document: self.webrender_document,
@@ -521,6 +521,7 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(RefCell<Option<WebGPU>>);
unsafe_no_jsmanaged_fields!(RefCell<Identities>);
unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
@@ -19,9 +19,10 @@ use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use js::jsapi::Heap;
use script_traits::ScriptMsg;
use std::rc::Rc;
use webgpu::wgpu;
use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
use webgpu::{WebGPUResponse, WebGPUResponseResult};

#[dom_struct]
pub struct GPU {
@@ -38,10 +39,6 @@ impl GPU {
pub fn new(global: &GlobalScope) -> DomRoot<GPU> {
reflect_dom_object(Box::new(GPU::new_inherited()), global, GPUBinding::Wrap)
}

fn wgpu_channel(&self) -> Option<WebGPU> {
self.global().as_window().webgpu_channel()
}
}

pub trait AsyncWGPUListener {
@@ -114,7 +111,8 @@ impl GPUMethods for GPU {
options: &GPURequestAdapterOptions,
comp: InCompartment,
) -> Rc<Promise> {
let promise = Promise::new_in_current_compartment(&self.global(), comp);
let global = &self.global();
let promise = Promise::new_in_current_compartment(global, comp);
let sender = response_async(&promise, self);
let power_preference = match options.powerPreference {
Some(GPUPowerPreference::Low_power) => wgpu::instance::PowerPreference::LowPower,
@@ -123,41 +121,37 @@ impl GPUMethods for GPU {
},
None => wgpu::instance::PowerPreference::Default,
};
let ids = self.global().as_window().Navigator().create_adapter_ids();
let ids = global.as_window().Navigator().create_adapter_ids();

match self.wgpu_channel() {
Some(channel) => {
channel
.0
.send(WebGPURequest::RequestAdapter(
sender,
wgpu::instance::RequestAdapterOptions { power_preference },
ids,
))
.unwrap();
},
None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
};
let script_to_constellation_chan = global.script_to_constellation_chan();
if script_to_constellation_chan
.send(ScriptMsg::RequestAdapter(
sender,
wgpu::instance::RequestAdapterOptions { power_preference },
ids,
))
.is_err()
{
promise.reject_error(Error::Operation);
}
promise
}
}

impl AsyncWGPUListener for GPU {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestAdapter(name, adapter) => {
WebGPUResponse::RequestAdapter(name, adapter, channel) => {
let adapter = GPUAdapter::new(
&self.global(),
channel,
DOMString::from(format!("{} ({:?})", name, adapter.0.backend())),
Heap::default(),
adapter,
);
promise.resolve_native(&adapter);
},
response => promise.reject_error(Error::Type(format!(
"Wrong response received for GPU from WebGPU thread {:?}",
response,
))),
_ => promise.reject_error(Error::Operation),
}
}
}
@@ -23,11 +23,13 @@ use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use std::rc::Rc;
use webgpu::{wgpu, WebGPUAdapter, WebGPURequest, WebGPUResponse};
use webgpu::{wgpu, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};

#[dom_struct]
pub struct GPUAdapter {
reflector_: Reflector,
#[ignore_malloc_size_of = "channels are hard"]
channel: WebGPU,
name: DOMString,
#[ignore_malloc_size_of = "mozjs"]
extensions: Heap<*mut JSObject>,
@@ -36,12 +38,14 @@ pub struct GPUAdapter {

impl GPUAdapter {
pub fn new_inherited(
channel: WebGPU,
name: DOMString,
extensions: Heap<*mut JSObject>,
adapter: WebGPUAdapter,
) -> GPUAdapter {
GPUAdapter {
reflector_: Reflector::new(),
channel,
name,
extensions,
adapter,
@@ -50,12 +54,15 @@ impl GPUAdapter {

pub fn new(
global: &GlobalScope,
channel: WebGPU,
name: DOMString,
extensions: Heap<*mut JSObject>,
adapter: WebGPUAdapter,
) -> DomRoot<GPUAdapter> {
reflect_dom_object(
Box::new(GPUAdapter::new_inherited(name, extensions, adapter)),
Box::new(GPUAdapter::new_inherited(
channel, name, extensions, adapter,
)),
global,
GPUAdapterBinding::Wrap,
)
@@ -89,15 +96,16 @@ impl GPUAdapterMethods for GPUAdapter {
let id = window
.Navigator()
.create_device_id(self.adapter.0.backend());
match window.webgpu_channel() {
Some(thread) => thread
.0
.send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
.unwrap(),
None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
if self
.channel
.0
.send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
.is_err()
{
promise.reject_error(Error::Operation);
}
} else {
promise.reject_error(Error::Type("No WebGPU thread...".to_owned()))
promise.reject_error(Error::Operation);
};
promise
}
@@ -109,16 +117,15 @@ impl AsyncWGPUListener for GPUAdapter {
WebGPUResponse::RequestDevice(device_id, _descriptor) => {
let device = GPUDevice::new(
&self.global(),
self.channel.clone(),
&self,
Heap::default(),
Heap::default(),
device_id,
);
promise.resolve_native(&device);
},
_ => promise.reject_error(Error::Type(
"Wrong response type from WebGPU thread...".to_owned(),
)),
_ => promise.reject_error(Error::Operation),
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.