mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
webgpu: Factor out swapchain to separate file (#33367)
* Move some stuff to swapchain.rs Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Use typed WebGPUContextId instead of u64 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Extract create_swapchain function and move more stuff in it Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * extract destroy_swapchain Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * extract swapchain_present Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * extract update_wr_image callback Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
938fd8c12f
commit
687f356db9
9 changed files with 403 additions and 328 deletions
|
@ -153,6 +153,7 @@ use servo_rand::{random, Rng, ServoRng, SliceRandom};
|
||||||
use servo_url::{Host, ImmutableOrigin, ServoUrl};
|
use servo_url::{Host, ImmutableOrigin, ServoUrl};
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use tracing::{span, Level};
|
use tracing::{span, Level};
|
||||||
|
use webgpu::swapchain::WGPUImageMap;
|
||||||
use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse};
|
use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse};
|
||||||
use webrender::{RenderApi, RenderApiSender};
|
use webrender::{RenderApi, RenderApiSender};
|
||||||
use webrender_api::DocumentId;
|
use webrender_api::DocumentId;
|
||||||
|
@ -219,7 +220,7 @@ struct WebrenderWGPU {
|
||||||
webrender_external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
webrender_external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
|
|
||||||
/// WebGPU data that supplied to Webrender for rendering
|
/// WebGPU data that supplied to Webrender for rendering
|
||||||
wgpu_image_map: Arc<Mutex<HashMap<u64, webgpu::PresentationData>>>,
|
wgpu_image_map: WGPUImageMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Servo supports multiple top-level browsing contexts or “webviews”, so `Constellation` needs to
|
/// Servo supports multiple top-level browsing contexts or “webviews”, so `Constellation` needs to
|
||||||
|
@ -552,7 +553,7 @@ pub struct InitialConstellationState {
|
||||||
/// User agent string to report in network requests.
|
/// User agent string to report in network requests.
|
||||||
pub user_agent: Cow<'static, str>,
|
pub user_agent: Cow<'static, str>,
|
||||||
|
|
||||||
pub wgpu_image_map: Arc<Mutex<HashMap<u64, webgpu::PresentationData>>>,
|
pub wgpu_image_map: WGPUImageMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data needed for webdriver
|
/// Data needed for webdriver
|
||||||
|
|
|
@ -61,7 +61,6 @@ use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||||
use crate::dom::bindings::reflector::{DomObject, Reflector};
|
use crate::dom::bindings::reflector::{DomObject, Reflector};
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||||
use crate::dom::bindings::str::{DOMString, USVString};
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
use crate::dom::gpucanvascontext::WebGPUContextId;
|
|
||||||
use crate::dom::htmlimageelement::SourceSet;
|
use crate::dom::htmlimageelement::SourceSet;
|
||||||
use crate::dom::htmlmediaelement::HTMLMediaElementFetchContext;
|
use crate::dom::htmlmediaelement::HTMLMediaElementFetchContext;
|
||||||
use crate::dom::windowproxy::WindowProxyHandler;
|
use crate::dom::windowproxy::WindowProxyHandler;
|
||||||
|
@ -364,7 +363,6 @@ unsafe_no_jsmanaged_fields!(ContextForRequestInterrupt);
|
||||||
unsafe_no_jsmanaged_fields!(WindowProxyHandler);
|
unsafe_no_jsmanaged_fields!(WindowProxyHandler);
|
||||||
unsafe_no_jsmanaged_fields!(DOMString);
|
unsafe_no_jsmanaged_fields!(DOMString);
|
||||||
unsafe_no_jsmanaged_fields!(USVString);
|
unsafe_no_jsmanaged_fields!(USVString);
|
||||||
unsafe_no_jsmanaged_fields!(WebGPUContextId);
|
|
||||||
unsafe_no_jsmanaged_fields!(SourceSet);
|
unsafe_no_jsmanaged_fields!(SourceSet);
|
||||||
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
|
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
|
||||||
unsafe_no_jsmanaged_fields!(StreamConsumer);
|
unsafe_no_jsmanaged_fields!(StreamConsumer);
|
||||||
|
|
|
@ -65,6 +65,7 @@ use style::stylesheet_set::DocumentStylesheetSet;
|
||||||
use style::stylesheets::{Origin, OriginSet, Stylesheet};
|
use style::stylesheets::{Origin, OriginSet, Stylesheet};
|
||||||
use url::Host;
|
use url::Host;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use webgpu::swapchain::WebGPUContextId;
|
||||||
use webrender_api::units::DeviceIntRect;
|
use webrender_api::units::DeviceIntRect;
|
||||||
|
|
||||||
use crate::animation_timeline::AnimationTimeline;
|
use crate::animation_timeline::AnimationTimeline;
|
||||||
|
@ -123,7 +124,7 @@ use crate::dom::eventtarget::EventTarget;
|
||||||
use crate::dom::focusevent::FocusEvent;
|
use crate::dom::focusevent::FocusEvent;
|
||||||
use crate::dom::fontfaceset::FontFaceSet;
|
use crate::dom::fontfaceset::FontFaceSet;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::gpucanvascontext::{GPUCanvasContext, WebGPUContextId};
|
use crate::dom::gpucanvascontext::GPUCanvasContext;
|
||||||
use crate::dom::hashchangeevent::HashChangeEvent;
|
use crate::dom::hashchangeevent::HashChangeEvent;
|
||||||
use crate::dom::htmlanchorelement::HTMLAnchorElement;
|
use crate::dom::htmlanchorelement::HTMLAnchorElement;
|
||||||
use crate::dom::htmlareaelement::HTMLAreaElement;
|
use crate::dom::htmlareaelement::HTMLAreaElement;
|
||||||
|
@ -442,7 +443,7 @@ pub struct Document {
|
||||||
dirty_webgl_contexts:
|
dirty_webgl_contexts:
|
||||||
DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>,
|
DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>,
|
||||||
/// List of all WebGPU context IDs that need flushing.
|
/// List of all WebGPU context IDs that need flushing.
|
||||||
dirty_webgpu_contexts: DomRefCell<HashMap<WebGPUContextId, Dom<GPUCanvasContext>>>,
|
dirty_webgpu_contexts: DomRefCell<HashMapTracedValues<WebGPUContextId, Dom<GPUCanvasContext>>>,
|
||||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-csp-list>
|
/// <https://html.spec.whatwg.org/multipage/#concept-document-csp-list>
|
||||||
#[ignore_malloc_size_of = "Defined in rust-content-security-policy"]
|
#[ignore_malloc_size_of = "Defined in rust-content-security-policy"]
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
|
@ -3278,7 +3279,7 @@ impl Document {
|
||||||
shadow_roots_styles_changed: Cell::new(false),
|
shadow_roots_styles_changed: Cell::new(false),
|
||||||
media_controls: DomRefCell::new(HashMap::new()),
|
media_controls: DomRefCell::new(HashMap::new()),
|
||||||
dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()),
|
dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()),
|
||||||
dirty_webgpu_contexts: DomRefCell::new(HashMap::new()),
|
dirty_webgpu_contexts: DomRefCell::new(HashMapTracedValues::new()),
|
||||||
csp_list: DomRefCell::new(None),
|
csp_list: DomRefCell::new(None),
|
||||||
selection: MutNullableDom::new(None),
|
selection: MutNullableDom::new(None),
|
||||||
animation_timeline: if pref!(layout.animations.test.enabled) {
|
animation_timeline: if pref!(layout.animations.test.enabled) {
|
||||||
|
|
|
@ -9,12 +9,10 @@ use dom_struct::dom_struct;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use script_layout_interface::HTMLCanvasDataSource;
|
use script_layout_interface::HTMLCanvasDataSource;
|
||||||
|
use webgpu::swapchain::WebGPUContextId;
|
||||||
use webgpu::wgc::id;
|
use webgpu::wgc::id;
|
||||||
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT};
|
use webgpu::{WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT};
|
||||||
use webrender_api::{
|
use webrender_api::{units, ImageFormat, ImageKey};
|
||||||
units, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, ImageDescriptor,
|
|
||||||
ImageDescriptorFlags, ImageFormat, ImageKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::bindings::codegen::Bindings::WebGPUBinding::GPUTextureUsageConstants;
|
use super::bindings::codegen::Bindings::WebGPUBinding::GPUTextureUsageConstants;
|
||||||
use super::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
|
use super::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
|
||||||
|
@ -35,9 +33,6 @@ use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers};
|
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers};
|
||||||
use crate::dom::node::{document_from_node, Node, NodeDamage};
|
use crate::dom::node::{document_from_node, Node, NodeDamage};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
|
|
||||||
pub struct WebGPUContextId(pub u64);
|
|
||||||
|
|
||||||
// TODO: make all this derivables available via new Bindings.conf option
|
// TODO: make all this derivables available via new Bindings.conf option
|
||||||
impl Clone for GPUCanvasConfiguration {
|
impl Clone for GPUCanvasConfiguration {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -104,6 +99,7 @@ pub struct GPUCanvasContext {
|
||||||
#[ignore_malloc_size_of = "Defined in webrender"]
|
#[ignore_malloc_size_of = "Defined in webrender"]
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
webrender_image: Cell<Option<webrender_api::ImageKey>>,
|
webrender_image: Cell<Option<webrender_api::ImageKey>>,
|
||||||
|
#[no_trace]
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-currenttexture-slot>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-currenttexture-slot>
|
||||||
texture: MutNullableDom<GPUTexture>,
|
texture: MutNullableDom<GPUTexture>,
|
||||||
|
@ -154,7 +150,7 @@ impl GPUCanvasContext {
|
||||||
.wgpu_id_hub()
|
.wgpu_id_hub()
|
||||||
.create_command_encoder_id(texture_id.backend());
|
.create_command_encoder_id(texture_id.backend());
|
||||||
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
|
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
|
||||||
external_id: self.context_id.0,
|
context_id: self.context_id,
|
||||||
texture_id,
|
texture_id,
|
||||||
encoder_id,
|
encoder_id,
|
||||||
}) {
|
}) {
|
||||||
|
@ -250,22 +246,6 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
let image_desc = ImageDescriptor {
|
|
||||||
format,
|
|
||||||
size: units::DeviceIntSize::new(size.width as i32, size.height as i32),
|
|
||||||
stride: Some(
|
|
||||||
(((size.width as u32 * 4) | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1) as i32,
|
|
||||||
),
|
|
||||||
offset: 0,
|
|
||||||
flags: ImageDescriptorFlags::from_bits(1).unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let image_data = ImageData::External(ExternalImageData {
|
|
||||||
id: ExternalImageId(self.context_id.0),
|
|
||||||
channel_index: 0,
|
|
||||||
image_type: ExternalImageType::Buffer,
|
|
||||||
});
|
|
||||||
|
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
let mut buffer_ids = ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new();
|
let mut buffer_ids = ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new();
|
||||||
|
@ -283,10 +263,10 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
|
||||||
device_id: descriptor.device.id().0,
|
device_id: descriptor.device.id().0,
|
||||||
queue_id: descriptor.device.GetQueue().id().0,
|
queue_id: descriptor.device.GetQueue().id().0,
|
||||||
buffer_ids,
|
buffer_ids,
|
||||||
external_id: self.context_id.0,
|
context_id: self.context_id,
|
||||||
sender,
|
sender,
|
||||||
image_desc,
|
format,
|
||||||
image_data,
|
size: units::DeviceIntSize::new(size.width as i32, size.height as i32),
|
||||||
})
|
})
|
||||||
.expect("Failed to create WebGPU SwapChain");
|
.expect("Failed to create WebGPU SwapChain");
|
||||||
|
|
||||||
|
@ -301,7 +281,7 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
|
||||||
fn Unconfigure(&self) {
|
fn Unconfigure(&self) {
|
||||||
if let Some(image_key) = self.webrender_image.take() {
|
if let Some(image_key) = self.webrender_image.take() {
|
||||||
if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain {
|
if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain {
|
||||||
external_id: self.context_id.0,
|
context_id: self.context_id,
|
||||||
image_key,
|
image_key,
|
||||||
}) {
|
}) {
|
||||||
warn!(
|
warn!(
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
use std::borrow::{BorrowMut, Cow};
|
use std::borrow::{BorrowMut, Cow};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -90,6 +89,7 @@ use surfman::platform::generic::multi::context::NativeContext as LinuxNativeCont
|
||||||
use surfman::{GLApi, GLVersion};
|
use surfman::{GLApi, GLVersion};
|
||||||
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
|
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
|
||||||
use surfman::{NativeConnection, NativeContext};
|
use surfman::{NativeConnection, NativeContext};
|
||||||
|
use webgpu::swapchain::WGPUImageMap;
|
||||||
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
|
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
ColorF, DocumentId, FontInstanceFlags, FontInstanceKey, FontKey, FramePublishId, ImageKey,
|
ColorF, DocumentId, FontInstanceFlags, FontInstanceKey, FontKey, FramePublishId, ImageKey,
|
||||||
|
@ -1017,7 +1017,7 @@ fn create_constellation(
|
||||||
glplayer_threads: Option<GLPlayerThreads>,
|
glplayer_threads: Option<GLPlayerThreads>,
|
||||||
initial_window_size: WindowSizeData,
|
initial_window_size: WindowSizeData,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
wgpu_image_map: Arc<Mutex<HashMap<u64, webgpu::PresentationData>>>,
|
wgpu_image_map: WGPUImageMap,
|
||||||
protocols: ProtocolRegistry,
|
protocols: ProtocolRegistry,
|
||||||
) -> Sender<ConstellationMsg> {
|
) -> Sender<ConstellationMsg> {
|
||||||
// Global configuration options, parsed from the command line.
|
// Global configuration options, parsed from the command line.
|
||||||
|
|
|
@ -10,7 +10,8 @@ use base::id::PipelineId;
|
||||||
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use webrender_api::{ExternalImageId, ImageData, ImageDescriptor, ImageKey};
|
use webrender_api::units::DeviceIntSize;
|
||||||
|
use webrender_api::{ImageFormat, ImageKey};
|
||||||
use wgc::binding_model::{
|
use wgc::binding_model::{
|
||||||
BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
|
BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
|
||||||
};
|
};
|
||||||
|
@ -30,6 +31,7 @@ pub use {wgpu_core as wgc, wgpu_types as wgt};
|
||||||
|
|
||||||
use crate::identity::*;
|
use crate::identity::*;
|
||||||
use crate::render_commands::RenderCommand;
|
use crate::render_commands::RenderCommand;
|
||||||
|
use crate::swapchain::WebGPUContextId;
|
||||||
use crate::{Error, ErrorFilter, WebGPUResponse, PRESENTATION_BUFFER_COUNT};
|
use crate::{Error, ErrorFilter, WebGPUResponse, PRESENTATION_BUFFER_COUNT};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
@ -101,7 +103,7 @@ pub enum WebGPURequest {
|
||||||
/// present only on ASYNC versions
|
/// present only on ASYNC versions
|
||||||
async_sender: Option<IpcSender<WebGPUResponse>>,
|
async_sender: Option<IpcSender<WebGPUResponse>>,
|
||||||
},
|
},
|
||||||
CreateContext(IpcSender<ExternalImageId>),
|
CreateContext(IpcSender<WebGPUContextId>),
|
||||||
CreatePipelineLayout {
|
CreatePipelineLayout {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
pipeline_layout_id: id::PipelineLayoutId,
|
pipeline_layout_id: id::PipelineLayoutId,
|
||||||
|
@ -131,10 +133,10 @@ pub enum WebGPURequest {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
queue_id: id::QueueId,
|
queue_id: id::QueueId,
|
||||||
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
external_id: u64,
|
context_id: WebGPUContextId,
|
||||||
sender: IpcSender<ImageKey>,
|
sender: IpcSender<ImageKey>,
|
||||||
image_desc: ImageDescriptor,
|
format: ImageFormat,
|
||||||
image_data: ImageData,
|
size: DeviceIntSize,
|
||||||
},
|
},
|
||||||
CreateTexture {
|
CreateTexture {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
|
@ -154,7 +156,7 @@ pub enum WebGPURequest {
|
||||||
texture_id: id::TextureId,
|
texture_id: id::TextureId,
|
||||||
},
|
},
|
||||||
DestroySwapChain {
|
DestroySwapChain {
|
||||||
external_id: u64,
|
context_id: WebGPUContextId,
|
||||||
image_key: ImageKey,
|
image_key: ImageKey,
|
||||||
},
|
},
|
||||||
DropTexture(id::TextureId),
|
DropTexture(id::TextureId),
|
||||||
|
@ -256,7 +258,7 @@ pub enum WebGPURequest {
|
||||||
command_buffers: Vec<id::CommandBufferId>,
|
command_buffers: Vec<id::CommandBufferId>,
|
||||||
},
|
},
|
||||||
SwapChainPresent {
|
SwapChainPresent {
|
||||||
external_id: u64,
|
context_id: WebGPUContextId,
|
||||||
texture_id: id::TextureId,
|
texture_id: id::TextureId,
|
||||||
encoder_id: id::CommandEncoderId,
|
encoder_id: id::CommandEncoderId,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
use swapchain::WGPUImageMap;
|
||||||
|
pub use swapchain::{PresentationData, WGPUExternalImages};
|
||||||
use webrender::RenderApiSender;
|
use webrender::RenderApiSender;
|
||||||
use wgpu_thread::WGPU;
|
use wgpu_thread::WGPU;
|
||||||
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
||||||
|
@ -12,30 +14,25 @@ mod poll_thread;
|
||||||
mod wgpu_thread;
|
mod wgpu_thread;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use euclid::default::Size2D;
|
|
||||||
pub use gpu_error::{Error, ErrorFilter, PopError};
|
pub use gpu_error::{Error, ErrorFilter, PopError};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
pub use render_commands::RenderCommand;
|
pub use render_commands::RenderCommand;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
use webrender_api::{DocumentId, ImageData, ImageDescriptor, ImageKey};
|
use webrender_api::DocumentId;
|
||||||
use webrender_traits::{
|
use webrender_traits::WebrenderExternalImageRegistry;
|
||||||
WebrenderExternalImageApi, WebrenderExternalImageRegistry, WebrenderImageSource,
|
|
||||||
};
|
|
||||||
use wgc::id;
|
|
||||||
|
|
||||||
mod gpu_error;
|
mod gpu_error;
|
||||||
mod ipc_messages;
|
mod ipc_messages;
|
||||||
mod render_commands;
|
mod render_commands;
|
||||||
|
pub mod swapchain;
|
||||||
pub use identity::*;
|
pub use identity::*;
|
||||||
pub use ipc_messages::recv::*;
|
pub use ipc_messages::recv::*;
|
||||||
pub use ipc_messages::to_dom::*;
|
pub use ipc_messages::to_dom::*;
|
||||||
pub use ipc_messages::to_script::*;
|
pub use ipc_messages::to_script::*;
|
||||||
pub use wgpu_thread::PRESENTATION_BUFFER_COUNT;
|
pub use swapchain::PRESENTATION_BUFFER_COUNT;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct WebGPU(pub IpcSender<WebGPURequest>);
|
pub struct WebGPU(pub IpcSender<WebGPURequest>);
|
||||||
|
@ -45,7 +42,7 @@ impl WebGPU {
|
||||||
webrender_api_sender: RenderApiSender,
|
webrender_api_sender: RenderApiSender,
|
||||||
webrender_document: DocumentId,
|
webrender_document: DocumentId,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
|
wgpu_image_map: WGPUImageMap,
|
||||||
) -> Option<(Self, IpcReceiver<WebGPUMsg>)> {
|
) -> Option<(Self, IpcReceiver<WebGPUMsg>)> {
|
||||||
if !pref!(dom.webgpu.enabled) {
|
if !pref!(dom.webgpu.enabled) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -100,46 +97,3 @@ impl WebGPU {
|
||||||
.map_err(|_| "Failed to send Exit message")
|
.map_err(|_| "Failed to send Exit message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct WGPUExternalImages {
|
|
||||||
pub images: Arc<Mutex<HashMap<u64, PresentationData>>>,
|
|
||||||
pub locked_ids: HashMap<u64, Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebrenderExternalImageApi for WGPUExternalImages {
|
|
||||||
fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D<i32>) {
|
|
||||||
let size;
|
|
||||||
let data;
|
|
||||||
if let Some(present_data) = self.images.lock().unwrap().get(&id) {
|
|
||||||
size = present_data.size;
|
|
||||||
data = present_data.data.clone();
|
|
||||||
} else {
|
|
||||||
size = Size2D::new(0, 0);
|
|
||||||
data = Vec::new();
|
|
||||||
}
|
|
||||||
let _ = self.locked_ids.insert(id, data);
|
|
||||||
(
|
|
||||||
WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()),
|
|
||||||
size,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&mut self, id: u64) {
|
|
||||||
let _ = self.locked_ids.remove(&id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PresentationData {
|
|
||||||
device_id: id::DeviceId,
|
|
||||||
queue_id: id::QueueId,
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
pub size: Size2D<i32>,
|
|
||||||
unassigned_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
|
||||||
available_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
|
||||||
queued_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
|
||||||
buffer_stride: u32,
|
|
||||||
image_key: ImageKey,
|
|
||||||
image_desc: ImageDescriptor,
|
|
||||||
image_data: ImageData,
|
|
||||||
}
|
|
||||||
|
|
337
components/webgpu/swapchain.rs
Normal file
337
components/webgpu/swapchain.rs
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
use std::slice;
|
||||||
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
|
use euclid::default::Size2D;
|
||||||
|
use log::{error, warn};
|
||||||
|
use malloc_size_of::MallocSizeOf;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use webrender::{RenderApi, Transaction};
|
||||||
|
use webrender_api::units::DeviceIntSize;
|
||||||
|
use webrender_api::{
|
||||||
|
DirtyRect, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, ImageDescriptor,
|
||||||
|
ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||||
|
};
|
||||||
|
use webrender_traits::{WebrenderExternalImageApi, WebrenderImageSource};
|
||||||
|
use wgpu_core::device::HostMap;
|
||||||
|
use wgpu_core::global::Global;
|
||||||
|
use wgpu_core::id;
|
||||||
|
use wgpu_core::resource::{BufferAccessError, BufferMapCallback, BufferMapOperation};
|
||||||
|
|
||||||
|
use crate::{wgt, WebGPUMsg};
|
||||||
|
|
||||||
|
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
|
pub struct WebGPUContextId(pub u64);
|
||||||
|
|
||||||
|
impl MallocSizeOf for WebGPUContextId {
|
||||||
|
fn size_of(&self, _ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type WGPUImageMap = Arc<Mutex<HashMap<WebGPUContextId, PresentationData>>>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WGPUExternalImages {
|
||||||
|
pub images: WGPUImageMap,
|
||||||
|
pub locked_ids: HashMap<WebGPUContextId, Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebrenderExternalImageApi for WGPUExternalImages {
|
||||||
|
fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D<i32>) {
|
||||||
|
let id = WebGPUContextId(id);
|
||||||
|
let size;
|
||||||
|
let data;
|
||||||
|
if let Some(present_data) = self.images.lock().unwrap().get(&id) {
|
||||||
|
size = present_data.image_desc.size.cast_unit();
|
||||||
|
data = present_data.data.clone();
|
||||||
|
} else {
|
||||||
|
size = Size2D::new(0, 0);
|
||||||
|
data = Vec::new();
|
||||||
|
}
|
||||||
|
let _ = self.locked_ids.insert(id, data);
|
||||||
|
(
|
||||||
|
WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()),
|
||||||
|
size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlock(&mut self, id: u64) {
|
||||||
|
let id = WebGPUContextId(id);
|
||||||
|
let _ = self.locked_ids.remove(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PresentationData {
|
||||||
|
pub device_id: id::DeviceId,
|
||||||
|
pub queue_id: id::QueueId,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
pub unassigned_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
|
pub available_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
|
pub queued_buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
|
pub image_key: ImageKey,
|
||||||
|
pub image_desc: ImageDescriptor,
|
||||||
|
pub image_data: ImageData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PresentationData {
|
||||||
|
pub fn new(
|
||||||
|
device_id: id::DeviceId,
|
||||||
|
queue_id: id::QueueId,
|
||||||
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
|
image_key: ImageKey,
|
||||||
|
image_desc: ImageDescriptor,
|
||||||
|
image_data: ImageData,
|
||||||
|
) -> Self {
|
||||||
|
let height = image_desc.size.height;
|
||||||
|
Self {
|
||||||
|
device_id,
|
||||||
|
queue_id,
|
||||||
|
// TODO: transparent black image
|
||||||
|
data: vec![
|
||||||
|
255;
|
||||||
|
(image_desc
|
||||||
|
.stride
|
||||||
|
.expect("Stride should be set when creating swapchain") *
|
||||||
|
height) as usize
|
||||||
|
],
|
||||||
|
unassigned_buffer_ids: buffer_ids,
|
||||||
|
available_buffer_ids: ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new(),
|
||||||
|
queued_buffer_ids: ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new(),
|
||||||
|
image_key,
|
||||||
|
image_desc,
|
||||||
|
image_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::WGPU {
|
||||||
|
pub(crate) fn create_swapchain(
|
||||||
|
&self,
|
||||||
|
device_id: id::DeviceId,
|
||||||
|
queue_id: id::QueueId,
|
||||||
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
format: ImageFormat,
|
||||||
|
size: DeviceIntSize,
|
||||||
|
image_key: ImageKey,
|
||||||
|
mut wr: MutexGuard<RenderApi>,
|
||||||
|
) {
|
||||||
|
let image_desc = ImageDescriptor {
|
||||||
|
format,
|
||||||
|
size,
|
||||||
|
stride: Some(
|
||||||
|
(((size.width as u32 * 4) | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1) as i32,
|
||||||
|
),
|
||||||
|
offset: 0,
|
||||||
|
flags: ImageDescriptorFlags::IS_OPAQUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let image_data = ImageData::External(ExternalImageData {
|
||||||
|
id: ExternalImageId(context_id.0),
|
||||||
|
channel_index: 0,
|
||||||
|
image_type: ExternalImageType::Buffer,
|
||||||
|
});
|
||||||
|
let _ = self.wgpu_image_map.lock().unwrap().insert(
|
||||||
|
context_id,
|
||||||
|
PresentationData::new(
|
||||||
|
device_id,
|
||||||
|
queue_id,
|
||||||
|
buffer_ids,
|
||||||
|
image_key,
|
||||||
|
image_desc,
|
||||||
|
image_data.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut txn = Transaction::new();
|
||||||
|
txn.add_image(image_key, image_desc, image_data, None);
|
||||||
|
wr.send_transaction(self.webrender_document, txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn swapchain_present(
|
||||||
|
&mut self,
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
encoder_id: id::Id<id::markers::CommandEncoder>,
|
||||||
|
texture_id: id::Id<id::markers::Texture>,
|
||||||
|
) -> ControlFlow<()> {
|
||||||
|
let global = &self.global;
|
||||||
|
let device_id;
|
||||||
|
let queue_id;
|
||||||
|
let size;
|
||||||
|
let buffer_id;
|
||||||
|
let buffer_stride;
|
||||||
|
{
|
||||||
|
if let Some(present_data) = self.wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
||||||
|
size = present_data.image_desc.size;
|
||||||
|
device_id = present_data.device_id;
|
||||||
|
queue_id = present_data.queue_id;
|
||||||
|
buffer_stride = present_data
|
||||||
|
.image_desc
|
||||||
|
.stride
|
||||||
|
.expect("Stride should be set when creating swapchain");
|
||||||
|
buffer_id = if let Some(b_id) = present_data.available_buffer_ids.pop() {
|
||||||
|
b_id
|
||||||
|
} else if let Some(b_id) = present_data.unassigned_buffer_ids.pop() {
|
||||||
|
let buffer_size = (buffer_stride * size.height) as wgt::BufferAddress;
|
||||||
|
let buffer_desc = wgt::BufferDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: buffer_size,
|
||||||
|
usage: wgt::BufferUsages::MAP_READ | wgt::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
};
|
||||||
|
let _ = global.device_create_buffer(device_id, &buffer_desc, Some(b_id));
|
||||||
|
b_id
|
||||||
|
} else {
|
||||||
|
error!("No staging buffer available for {:?}", context_id);
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
};
|
||||||
|
present_data.queued_buffer_ids.push(buffer_id);
|
||||||
|
} else {
|
||||||
|
error!("Data not found for {:?}", context_id);
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let buffer_size = (size.height * buffer_stride) as wgt::BufferAddress;
|
||||||
|
let comm_desc = wgt::CommandEncoderDescriptor { label: None };
|
||||||
|
let _ = global.device_create_command_encoder(device_id, &comm_desc, Some(encoder_id));
|
||||||
|
let buffer_cv = wgt::ImageCopyBuffer {
|
||||||
|
buffer: buffer_id,
|
||||||
|
layout: wgt::ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(buffer_stride as u32),
|
||||||
|
rows_per_image: None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let texture_cv = wgt::ImageCopyTexture {
|
||||||
|
texture: texture_id,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgt::Origin3d::ZERO,
|
||||||
|
aspect: wgt::TextureAspect::All,
|
||||||
|
};
|
||||||
|
let copy_size = wgt::Extent3d {
|
||||||
|
width: size.width as u32,
|
||||||
|
height: size.height as u32,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
let _ = global.command_encoder_copy_texture_to_buffer(
|
||||||
|
encoder_id,
|
||||||
|
&texture_cv,
|
||||||
|
&buffer_cv,
|
||||||
|
©_size,
|
||||||
|
);
|
||||||
|
let _ = global.command_encoder_finish(encoder_id, &wgt::CommandBufferDescriptor::default());
|
||||||
|
let _ = global.queue_submit(queue_id, &[encoder_id.into_command_buffer_id()]);
|
||||||
|
let callback = {
|
||||||
|
let global = Arc::clone(&self.global);
|
||||||
|
let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
|
||||||
|
let webrender_api = Arc::clone(&self.webrender_api);
|
||||||
|
let webrender_document = self.webrender_document;
|
||||||
|
let token = self.poller.token();
|
||||||
|
BufferMapCallback::from_rust(Box::from(move |result| {
|
||||||
|
drop(token);
|
||||||
|
update_wr_image(
|
||||||
|
result,
|
||||||
|
global,
|
||||||
|
buffer_id,
|
||||||
|
buffer_size,
|
||||||
|
wgpu_image_map,
|
||||||
|
context_id,
|
||||||
|
webrender_api,
|
||||||
|
webrender_document,
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
let map_op = BufferMapOperation {
|
||||||
|
host: HostMap::Read,
|
||||||
|
callback: Some(callback),
|
||||||
|
};
|
||||||
|
let _ = global.buffer_map_async(buffer_id, 0, Some(buffer_size), map_op);
|
||||||
|
self.poller.wake();
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn destroy_swapchain(
|
||||||
|
&mut self,
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
image_key: webrender_api::ImageKey,
|
||||||
|
) {
|
||||||
|
let data = self
|
||||||
|
.wgpu_image_map
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.remove(&context_id)
|
||||||
|
.unwrap();
|
||||||
|
let global = &self.global;
|
||||||
|
for b_id in data.available_buffer_ids.iter() {
|
||||||
|
global.buffer_drop(*b_id);
|
||||||
|
}
|
||||||
|
for b_id in data.queued_buffer_ids.iter() {
|
||||||
|
global.buffer_drop(*b_id);
|
||||||
|
}
|
||||||
|
for b_id in data.unassigned_buffer_ids.iter() {
|
||||||
|
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(*b_id)) {
|
||||||
|
warn!("Unable to send FreeBuffer({:?}) ({:?})", *b_id, e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut txn = Transaction::new();
|
||||||
|
txn.delete_image(image_key);
|
||||||
|
self.webrender_api
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_transaction(self.webrender_document, txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_wr_image(
|
||||||
|
result: Result<(), BufferAccessError>,
|
||||||
|
global: Arc<Global>,
|
||||||
|
buffer_id: id::BufferId,
|
||||||
|
buffer_size: u64,
|
||||||
|
wgpu_image_map: WGPUImageMap,
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
webrender_api: Arc<Mutex<RenderApi>>,
|
||||||
|
webrender_document: webrender_api::DocumentId,
|
||||||
|
) {
|
||||||
|
match result {
|
||||||
|
Ok(()) => {
|
||||||
|
let (slice_pointer, range_size) = global
|
||||||
|
.buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64))
|
||||||
|
.unwrap();
|
||||||
|
let data =
|
||||||
|
unsafe { slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize) }
|
||||||
|
.to_vec();
|
||||||
|
if let Some(present_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
||||||
|
present_data.data = data;
|
||||||
|
let mut txn = Transaction::new();
|
||||||
|
txn.update_image(
|
||||||
|
present_data.image_key,
|
||||||
|
present_data.image_desc,
|
||||||
|
present_data.image_data.clone(),
|
||||||
|
&DirtyRect::All,
|
||||||
|
);
|
||||||
|
webrender_api
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_transaction(webrender_document, txn);
|
||||||
|
present_data
|
||||||
|
.queued_buffer_ids
|
||||||
|
.retain(|b_id| *b_id != buffer_id);
|
||||||
|
present_data.available_buffer_ids.push(buffer_id);
|
||||||
|
} else {
|
||||||
|
error!("Data not found for {:?}", context_id);
|
||||||
|
}
|
||||||
|
let _ = global.buffer_unmap(buffer_id);
|
||||||
|
},
|
||||||
|
_ => error!("Could not map buffer({:?})", buffer_id),
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,23 +6,20 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use euclid::default::Size2D;
|
|
||||||
use ipc_channel::ipc::{IpcReceiver, IpcSender, IpcSharedMemory};
|
use ipc_channel::ipc::{IpcReceiver, IpcSender, IpcSharedMemory};
|
||||||
use log::{error, info, warn};
|
use log::{info, warn};
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
use webrender::{RenderApi, RenderApiSender, Transaction};
|
use webrender::{RenderApi, RenderApiSender};
|
||||||
use webrender_api::{DirtyRect, DocumentId};
|
use webrender_api::DocumentId;
|
||||||
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
||||||
use wgc::command::{
|
use wgc::command::{ComputePass, ComputePassDescriptor, RenderPass};
|
||||||
ComputePass, ComputePassDescriptor, ImageCopyBuffer, ImageCopyTexture, RenderPass,
|
|
||||||
};
|
|
||||||
use wgc::device::queue::SubmittedWorkDoneClosure;
|
use wgc::device::queue::SubmittedWorkDoneClosure;
|
||||||
use wgc::device::{DeviceDescriptor, DeviceLostClosure, HostMap, ImplicitPipelineIds};
|
use wgc::device::{DeviceDescriptor, DeviceLostClosure, ImplicitPipelineIds};
|
||||||
use wgc::id;
|
use wgc::id;
|
||||||
use wgc::id::DeviceId;
|
use wgc::id::DeviceId;
|
||||||
use wgc::instance::parse_backends_from_comma_list;
|
use wgc::instance::parse_backends_from_comma_list;
|
||||||
|
@ -39,13 +36,12 @@ pub use {wgpu_core as wgc, wgpu_types as wgt};
|
||||||
use crate::gpu_error::ErrorScope;
|
use crate::gpu_error::ErrorScope;
|
||||||
use crate::poll_thread::Poller;
|
use crate::poll_thread::Poller;
|
||||||
use crate::render_commands::apply_render_command;
|
use crate::render_commands::apply_render_command;
|
||||||
|
use crate::swapchain::{WGPUImageMap, WebGPUContextId};
|
||||||
use crate::{
|
use crate::{
|
||||||
Adapter, ComputePassId, Error, Mapping, Pipeline, PopError, PresentationData, RenderPassId,
|
Adapter, ComputePassId, Error, Mapping, Pipeline, PopError, RenderPassId, WebGPU,
|
||||||
WebGPU, WebGPUAdapter, WebGPUDevice, WebGPUMsg, WebGPUQueue, WebGPURequest, WebGPUResponse,
|
WebGPUAdapter, WebGPUDevice, WebGPUMsg, WebGPUQueue, WebGPURequest, WebGPUResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
|
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
pub(crate) struct DeviceScope {
|
pub(crate) struct DeviceScope {
|
||||||
pub device_id: DeviceId,
|
pub device_id: DeviceId,
|
||||||
|
@ -103,8 +99,8 @@ impl<P> Pass<P> {
|
||||||
pub(crate) struct WGPU {
|
pub(crate) struct WGPU {
|
||||||
receiver: IpcReceiver<WebGPURequest>,
|
receiver: IpcReceiver<WebGPURequest>,
|
||||||
sender: IpcSender<WebGPURequest>,
|
sender: IpcSender<WebGPURequest>,
|
||||||
script_sender: IpcSender<WebGPUMsg>,
|
pub(crate) script_sender: IpcSender<WebGPUMsg>,
|
||||||
global: Arc<wgc::global::Global>,
|
pub(crate) global: Arc<wgc::global::Global>,
|
||||||
adapters: Vec<WebGPUAdapter>,
|
adapters: Vec<WebGPUAdapter>,
|
||||||
devices: Arc<Mutex<HashMap<DeviceId, DeviceScope>>>,
|
devices: Arc<Mutex<HashMap<DeviceId, DeviceScope>>>,
|
||||||
// Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid
|
// Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid
|
||||||
|
@ -114,12 +110,12 @@ pub(crate) struct WGPU {
|
||||||
/// because wgpu does not invalidate command encoder object
|
/// because wgpu does not invalidate command encoder object
|
||||||
/// (this is also reused for invalidation of command buffers)
|
/// (this is also reused for invalidation of command buffers)
|
||||||
error_command_encoders: HashMap<id::CommandEncoderId, String>,
|
error_command_encoders: HashMap<id::CommandEncoderId, String>,
|
||||||
webrender_api: Arc<Mutex<RenderApi>>,
|
pub(crate) webrender_api: Arc<Mutex<RenderApi>>,
|
||||||
webrender_document: DocumentId,
|
pub(crate) webrender_document: DocumentId,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
pub(crate) external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
|
pub(crate) wgpu_image_map: WGPUImageMap,
|
||||||
/// Provides access to poller thread
|
/// Provides access to poller thread
|
||||||
poller: Poller,
|
pub(crate) poller: Poller,
|
||||||
/// Store compute passes
|
/// Store compute passes
|
||||||
compute_passes: HashMap<ComputePassId, Pass<ComputePass>>,
|
compute_passes: HashMap<ComputePassId, Pass<ComputePass>>,
|
||||||
/// Store render passes
|
/// Store render passes
|
||||||
|
@ -134,7 +130,7 @@ impl WGPU {
|
||||||
webrender_api_sender: RenderApiSender,
|
webrender_api_sender: RenderApiSender,
|
||||||
webrender_document: DocumentId,
|
webrender_document: DocumentId,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
|
wgpu_image_map: WGPUImageMap,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let backend_pref = pref!(dom.webgpu.wgpu_backend);
|
let backend_pref = pref!(dom.webgpu.wgpu_backend);
|
||||||
let backends = if backend_pref.is_empty() {
|
let backends = if backend_pref.is_empty() {
|
||||||
|
@ -419,7 +415,7 @@ impl WGPU {
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Lock poisoned?")
|
.expect("Lock poisoned?")
|
||||||
.next_id(WebrenderImageHandlerType::WebGPU);
|
.next_id(WebrenderImageHandlerType::WebGPU);
|
||||||
if let Err(e) = sender.send(id) {
|
if let Err(e) = sender.send(WebGPUContextId(id.0)) {
|
||||||
warn!("Failed to send ExternalImageId to new context ({})", e);
|
warn!("Failed to send ExternalImageId to new context ({})", e);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -525,46 +521,20 @@ impl WGPU {
|
||||||
device_id,
|
device_id,
|
||||||
queue_id,
|
queue_id,
|
||||||
buffer_ids,
|
buffer_ids,
|
||||||
external_id,
|
context_id,
|
||||||
sender,
|
sender,
|
||||||
image_desc,
|
size,
|
||||||
image_data,
|
format,
|
||||||
} => {
|
} => {
|
||||||
let height = image_desc.size.height;
|
let wr = self.webrender_api.lock().unwrap();
|
||||||
let width = image_desc.size.width;
|
|
||||||
let buffer_stride =
|
|
||||||
((width * 4) as u32 | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1;
|
|
||||||
let mut wr = self.webrender_api.lock().unwrap();
|
|
||||||
let image_key = wr.generate_image_key();
|
let image_key = wr.generate_image_key();
|
||||||
if let Err(e) = sender.send(image_key) {
|
if let Err(e) = sender.send(image_key) {
|
||||||
warn!("Failed to send ImageKey ({})", e);
|
warn!("Failed to send ImageKey ({})", e);
|
||||||
}
|
}
|
||||||
let _ = self.wgpu_image_map.lock().unwrap().insert(
|
self.create_swapchain(
|
||||||
external_id,
|
device_id, queue_id, buffer_ids, context_id, format, size, image_key,
|
||||||
PresentationData {
|
wr,
|
||||||
device_id,
|
)
|
||||||
queue_id,
|
|
||||||
data: vec![255; (buffer_stride * height as u32) as usize],
|
|
||||||
size: Size2D::new(width, height),
|
|
||||||
unassigned_buffer_ids: buffer_ids,
|
|
||||||
available_buffer_ids: ArrayVec::<
|
|
||||||
id::BufferId,
|
|
||||||
PRESENTATION_BUFFER_COUNT,
|
|
||||||
>::new(),
|
|
||||||
queued_buffer_ids: ArrayVec::<
|
|
||||||
id::BufferId,
|
|
||||||
PRESENTATION_BUFFER_COUNT,
|
|
||||||
>::new(),
|
|
||||||
buffer_stride,
|
|
||||||
image_key,
|
|
||||||
image_desc,
|
|
||||||
image_data: image_data.clone(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut txn = Transaction::new();
|
|
||||||
txn.add_image(image_key, image_desc, image_data, None);
|
|
||||||
wr.send_transaction(self.webrender_document, txn);
|
|
||||||
},
|
},
|
||||||
WebGPURequest::CreateTexture {
|
WebGPURequest::CreateTexture {
|
||||||
device_id,
|
device_id,
|
||||||
|
@ -604,33 +574,10 @@ impl WGPU {
|
||||||
self.poller.wake();
|
self.poller.wake();
|
||||||
},
|
},
|
||||||
WebGPURequest::DestroySwapChain {
|
WebGPURequest::DestroySwapChain {
|
||||||
external_id,
|
context_id,
|
||||||
image_key,
|
image_key,
|
||||||
} => {
|
} => {
|
||||||
let data = self
|
self.destroy_swapchain(context_id, image_key);
|
||||||
.wgpu_image_map
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.remove(&external_id)
|
|
||||||
.unwrap();
|
|
||||||
let global = &self.global;
|
|
||||||
for b_id in data.available_buffer_ids.iter() {
|
|
||||||
global.buffer_drop(*b_id);
|
|
||||||
}
|
|
||||||
for b_id in data.queued_buffer_ids.iter() {
|
|
||||||
global.buffer_drop(*b_id);
|
|
||||||
}
|
|
||||||
for b_id in data.unassigned_buffer_ids.iter() {
|
|
||||||
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(*b_id)) {
|
|
||||||
warn!("Unable to send FreeBuffer({:?}) ({:?})", *b_id, e);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let mut txn = Transaction::new();
|
|
||||||
txn.delete_image(image_key);
|
|
||||||
self.webrender_api
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.send_transaction(self.webrender_document, txn);
|
|
||||||
},
|
},
|
||||||
WebGPURequest::DestroyTexture {
|
WebGPURequest::DestroyTexture {
|
||||||
device_id,
|
device_id,
|
||||||
|
@ -1040,160 +987,15 @@ impl WGPU {
|
||||||
self.maybe_dispatch_error(device_id, result.err());
|
self.maybe_dispatch_error(device_id, result.err());
|
||||||
},
|
},
|
||||||
WebGPURequest::SwapChainPresent {
|
WebGPURequest::SwapChainPresent {
|
||||||
external_id,
|
context_id,
|
||||||
texture_id,
|
texture_id,
|
||||||
encoder_id,
|
encoder_id,
|
||||||
} => {
|
} => {
|
||||||
let global = &self.global;
|
if let ControlFlow::Break(_) =
|
||||||
let device_id;
|
self.swapchain_present(context_id, encoder_id, texture_id)
|
||||||
let queue_id;
|
|
||||||
let size;
|
|
||||||
let buffer_id;
|
|
||||||
let buffer_stride;
|
|
||||||
{
|
{
|
||||||
if let Some(present_data) =
|
continue;
|
||||||
self.wgpu_image_map.lock().unwrap().get_mut(&external_id)
|
|
||||||
{
|
|
||||||
size = present_data.size;
|
|
||||||
device_id = present_data.device_id;
|
|
||||||
queue_id = present_data.queue_id;
|
|
||||||
buffer_stride = present_data.buffer_stride;
|
|
||||||
buffer_id = if let Some(b_id) =
|
|
||||||
present_data.available_buffer_ids.pop()
|
|
||||||
{
|
|
||||||
b_id
|
|
||||||
} else if let Some(b_id) = present_data.unassigned_buffer_ids.pop()
|
|
||||||
{
|
|
||||||
let buffer_size =
|
|
||||||
(buffer_stride * size.height as u32) as wgt::BufferAddress;
|
|
||||||
let buffer_desc = wgt::BufferDescriptor {
|
|
||||||
label: None,
|
|
||||||
size: buffer_size,
|
|
||||||
usage: wgt::BufferUsages::MAP_READ |
|
|
||||||
wgt::BufferUsages::COPY_DST,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
};
|
|
||||||
let _ = global.device_create_buffer(
|
|
||||||
device_id,
|
|
||||||
&buffer_desc,
|
|
||||||
Some(b_id),
|
|
||||||
);
|
|
||||||
b_id
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"No staging buffer available for ExternalImageId({:?})",
|
|
||||||
external_id
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
present_data.queued_buffer_ids.push(buffer_id);
|
|
||||||
} else {
|
|
||||||
warn!("Data not found for ExternalImageId({:?})", external_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer_size =
|
|
||||||
(size.height as u32 * buffer_stride) as wgt::BufferAddress;
|
|
||||||
let comm_desc = wgt::CommandEncoderDescriptor { label: None };
|
|
||||||
let _ = global.device_create_command_encoder(
|
|
||||||
device_id,
|
|
||||||
&comm_desc,
|
|
||||||
Some(encoder_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
let buffer_cv = ImageCopyBuffer {
|
|
||||||
buffer: buffer_id,
|
|
||||||
layout: wgt::ImageDataLayout {
|
|
||||||
offset: 0,
|
|
||||||
bytes_per_row: Some(buffer_stride),
|
|
||||||
rows_per_image: None,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let texture_cv = ImageCopyTexture {
|
|
||||||
texture: texture_id,
|
|
||||||
mip_level: 0,
|
|
||||||
origin: wgt::Origin3d::ZERO,
|
|
||||||
aspect: wgt::TextureAspect::All,
|
|
||||||
};
|
|
||||||
let copy_size = wgt::Extent3d {
|
|
||||||
width: size.width as u32,
|
|
||||||
height: size.height as u32,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
};
|
|
||||||
let _ = global.command_encoder_copy_texture_to_buffer(
|
|
||||||
encoder_id,
|
|
||||||
&texture_cv,
|
|
||||||
&buffer_cv,
|
|
||||||
©_size,
|
|
||||||
);
|
|
||||||
let _ = global.command_encoder_finish(
|
|
||||||
encoder_id,
|
|
||||||
&wgt::CommandBufferDescriptor::default(),
|
|
||||||
);
|
|
||||||
let _ =
|
|
||||||
global.queue_submit(queue_id, &[encoder_id.into_command_buffer_id()]);
|
|
||||||
|
|
||||||
let glob = Arc::clone(&self.global);
|
|
||||||
let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
|
|
||||||
let webrender_api = Arc::clone(&self.webrender_api);
|
|
||||||
let webrender_document = self.webrender_document;
|
|
||||||
let token = self.poller.token();
|
|
||||||
let callback = BufferMapCallback::from_rust(Box::from(move |result| {
|
|
||||||
drop(token);
|
|
||||||
match result {
|
|
||||||
Ok(()) => {
|
|
||||||
let global = &glob;
|
|
||||||
let (slice_pointer, range_size) = global
|
|
||||||
.buffer_get_mapped_range(
|
|
||||||
buffer_id,
|
|
||||||
0,
|
|
||||||
Some(buffer_size as u64),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let data = unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
slice_pointer.as_ptr(),
|
|
||||||
range_size as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.to_vec();
|
|
||||||
if let Some(present_data) =
|
|
||||||
wgpu_image_map.lock().unwrap().get_mut(&external_id)
|
|
||||||
{
|
|
||||||
present_data.data = data;
|
|
||||||
let mut txn = Transaction::new();
|
|
||||||
txn.update_image(
|
|
||||||
present_data.image_key,
|
|
||||||
present_data.image_desc,
|
|
||||||
present_data.image_data.clone(),
|
|
||||||
&DirtyRect::All,
|
|
||||||
);
|
|
||||||
webrender_api
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.send_transaction(webrender_document, txn);
|
|
||||||
present_data
|
|
||||||
.queued_buffer_ids
|
|
||||||
.retain(|b_id| *b_id != buffer_id);
|
|
||||||
present_data.available_buffer_ids.push(buffer_id);
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"Data not found for ExternalImageId({:?})",
|
|
||||||
external_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let _ = global.buffer_unmap(buffer_id);
|
|
||||||
},
|
|
||||||
_ => error!("Could not map buffer({:?})", buffer_id),
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
let map_op = BufferMapOperation {
|
|
||||||
host: HostMap::Read,
|
|
||||||
callback: Some(callback),
|
|
||||||
};
|
|
||||||
let _ = global.buffer_map_async(buffer_id, 0, Some(buffer_size), map_op);
|
|
||||||
self.poller.wake();
|
|
||||||
},
|
},
|
||||||
WebGPURequest::UnmapBuffer {
|
WebGPURequest::UnmapBuffer {
|
||||||
buffer_id,
|
buffer_id,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue