diff options
author | Kunal Mohan <kunalmohan99@gmail.com> | 2020-06-04 19:28:25 +0530 |
---|---|---|
committer | Kunal Mohan <kunalmohan99@gmail.com> | 2020-06-13 17:46:12 +0530 |
commit | 71401e0855c24e4cf86a754171f0162ae08d8e55 (patch) | |
tree | 34587c934aa127849ed943c44ec79f71ee904935 /components/script | |
parent | 73760ea59434971d24e6aac7e5fe3c79c1ba5bf6 (diff) | |
download | servo-71401e0855c24e4cf86a754171f0162ae08d8e55.tar.gz servo-71401e0855c24e4cf86a754171f0162ae08d8e55.zip |
Implement GPUSwapChain and GPUCanvasContext and interface with Webrender
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 5 | ||||
-rw-r--r-- | components/script/dom/document.rs | 23 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 1 | ||||
-rw-r--r-- | components/script/dom/gpucanvascontext.rs | 204 | ||||
-rw-r--r-- | components/script/dom/gpudevice.rs | 4 | ||||
-rw-r--r-- | components/script/dom/gpuswapchain.rs | 85 | ||||
-rw-r--r-- | components/script/dom/gputexture.rs | 6 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 47 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 7 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 11 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUCanvasContext.webidl | 17 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUSwapChain.webidl | 10 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLCanvasElement.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/window.rs | 3 |
15 files changed, 409 insertions, 21 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 9518a2c0989..01cbde4bcfa 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -37,6 +37,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::utils::WindowProxyHandler; use crate::dom::gpubuffer::GPUBufferState; +use crate::dom::gpucanvascontext::WebGPUContextId; use crate::dom::gpucommandencoder::GPUCommandEncoderState; use crate::dom::htmlimageelement::SourceSet; use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer}; @@ -168,7 +169,7 @@ use webgpu::{ WebGPUPipelineLayout, WebGPUQueue, WebGPURenderPipeline, WebGPUSampler, WebGPUShaderModule, WebGPUTexture, WebGPUTextureView, }; -use webrender_api::{DocumentId, ImageKey}; +use webrender_api::{DocumentId, ExternalImageId, ImageKey}; use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::{Finger, Hand, Ray, View}; @@ -541,6 +542,7 @@ unsafe_no_jsmanaged_fields!(PathBuf); unsafe_no_jsmanaged_fields!(DrawAPaintImageResult); unsafe_no_jsmanaged_fields!(DocumentId); unsafe_no_jsmanaged_fields!(ImageKey); +unsafe_no_jsmanaged_fields!(ExternalImageId); unsafe_no_jsmanaged_fields!(WebGLBufferId); unsafe_no_jsmanaged_fields!(WebGLChan); unsafe_no_jsmanaged_fields!(WebGLFramebufferId); @@ -572,6 +574,7 @@ unsafe_no_jsmanaged_fields!(WebGPUShaderModule); unsafe_no_jsmanaged_fields!(WebGPUSampler); unsafe_no_jsmanaged_fields!(WebGPUTexture); unsafe_no_jsmanaged_fields!(WebGPUTextureView); +unsafe_no_jsmanaged_fields!(WebGPUContextId); unsafe_no_jsmanaged_fields!(WebGPUCommandBuffer); unsafe_no_jsmanaged_fields!(WebGPUCommandEncoder); unsafe_no_jsmanaged_fields!(WebGPUDevice); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 157829412ce..c685eb57cf4 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -53,6 +53,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable, EventDefault, Even use crate::dom::eventtarget::EventTarget; use crate::dom::focusevent::FocusEvent; use crate::dom::globalscope::GlobalScope; +use crate::dom::gpucanvascontext::{GPUCanvasContext, WebGPUContextId}; use crate::dom::hashchangeevent::HashChangeEvent; use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmlareaelement::HTMLAreaElement; @@ -377,6 +378,8 @@ pub struct Document { media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>, /// List of all WebGL context IDs that need flushing. dirty_webgl_contexts: DomRefCell<HashMap<WebGLContextId, Dom<WebGLRenderingContext>>>, + /// List of all WebGPU context IDs that need flushing. + dirty_webgpu_contexts: DomRefCell<HashMap<WebGPUContextId, Dom<GPUCanvasContext>>>, /// https://html.spec.whatwg.org/multipage/#concept-document-csp-list #[ignore_malloc_size_of = "Defined in rust-content-security-policy"] csp_list: DomRefCell<Option<CspList>>, @@ -2643,14 +2646,14 @@ impl Document { } } - pub fn add_dirty_canvas(&self, context: &WebGLRenderingContext) { + pub fn add_dirty_webgl_canvas(&self, context: &WebGLRenderingContext) { self.dirty_webgl_contexts .borrow_mut() .entry(context.context_id()) .or_insert_with(|| Dom::from_ref(context)); } - pub fn flush_dirty_canvases(&self) { + pub fn flush_dirty_webgl_canvases(&self) { let dirty_context_ids: Vec<_> = self .dirty_webgl_contexts .borrow_mut() @@ -2678,6 +2681,21 @@ impl Document { receiver.recv().unwrap(); } + pub fn add_dirty_webgpu_canvas(&self, context: &GPUCanvasContext) { + self.dirty_webgpu_contexts + .borrow_mut() + .entry(context.context_id()) + .or_insert_with(|| Dom::from_ref(context)); + } + + #[allow(unrooted_must_root)] + pub fn flush_dirty_webgpu_canvases(&self) { + self.dirty_webgpu_contexts + .borrow_mut() + .drain() + .for_each(|(_, context)| context.send_swap_chain_present()); + } + // https://html.spec.whatwg.org/multipage/#dom-tree-accessors:supported-property-names // (This takes the filter as a method so the window named getter can use it too) pub fn supported_property_names_impl( @@ -3039,6 +3057,7 @@ impl Document { shadow_roots_styles_changed: Cell::new(false), media_controls: DomRefCell::new(HashMap::new()), dirty_webgl_contexts: DomRefCell::new(HashMap::new()), + dirty_webgpu_contexts: DomRefCell::new(HashMap::new()), csp_list: DomRefCell::new(None), selection: MutNullableDom::new(None), animation_timeline: if pref!(layout.animations.test.enabled) { diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 517a1cbe8d3..987ae4e7c13 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -278,6 +278,7 @@ pub struct GlobalScope { /// An optional string allowing the user agent to be set for testing. user_agent: Cow<'static, str>, + /// Identity Manager for WebGPU resources #[ignore_malloc_size_of = "defined in wgpu"] gpu_id_hub: Arc<Mutex<Identities>>, diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs new file mode 100644 index 00000000000..5c239fc5c8d --- /dev/null +++ b/components/script/dom/gpucanvascontext.rs @@ -0,0 +1,204 @@ +/* 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 crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::GPUCanvasContextBinding::{ + GPUCanvasContextMethods, GPUSwapChainDescriptor, +}; +use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::GPUDeviceBinding::GPUDeviceMethods; +use crate::dom::bindings::codegen::Bindings::GPUObjectBaseBinding::GPUObjectDescriptorBase; +use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::{ + GPUExtent3D, GPUExtent3DDict, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat, +}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::gpuswapchain::GPUSwapChain; +use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers}; +use crate::dom::node::{document_from_node, Node, NodeDamage}; +use dom_struct::dom_struct; +use euclid::default::Size2D; +use ipc_channel::ipc; +use script_layout_interface::HTMLCanvasDataSource; +use std::cell::Cell; +use webgpu::{wgt, WebGPU, WebGPURequest}; + +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)] +pub struct WebGPUContextId(pub u64); + +#[dom_struct] +pub struct GPUCanvasContext { + reflector_: Reflector, + #[ignore_malloc_size_of = "channels are hard"] + channel: WebGPU, + canvas: Dom<HTMLCanvasElement>, + size: Cell<Size2D<u32>>, + swap_chain: DomRefCell<Option<Dom<GPUSwapChain>>>, + #[ignore_malloc_size_of = "Defined in webrender"] + webrender_image: Cell<Option<webrender_api::ImageKey>>, + context_id: WebGPUContextId, +} + +impl GPUCanvasContext { + fn new_inherited(canvas: &HTMLCanvasElement, size: Size2D<u32>, channel: WebGPU) -> Self { + let (sender, receiver) = ipc::channel().unwrap(); + let _ = channel.0.send(WebGPURequest::CreateContext(sender)); + let external_id = receiver.recv().unwrap(); + Self { + reflector_: Reflector::new(), + channel, + canvas: Dom::from_ref(canvas), + size: Cell::new(size), + swap_chain: DomRefCell::new(None), + webrender_image: Cell::new(None), + context_id: WebGPUContextId(external_id.0), + } + } + + pub fn new( + global: &GlobalScope, + canvas: &HTMLCanvasElement, + size: Size2D<u32>, + channel: WebGPU, + ) -> DomRoot<Self> { + reflect_dom_object( + Box::new(GPUCanvasContext::new_inherited(canvas, size, channel)), + global, + ) + } +} + +impl GPUCanvasContext { + fn layout_handle(&self) -> HTMLCanvasDataSource { + let image_key = if self.webrender_image.get().is_some() { + self.webrender_image.get().unwrap() + } else { + webrender_api::ImageKey::DUMMY + }; + HTMLCanvasDataSource::WebGPU(image_key) + } + + pub fn send_swap_chain_present(&self) { + let texture_id = self.swap_chain.borrow().as_ref().unwrap().texture_id().0; + let encoder_id = self + .global() + .wgpu_id_hub() + .lock() + .create_command_encoder_id(texture_id.backend()); + if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent { + external_id: self.context_id.0, + texture_id, + encoder_id, + image_key: self.webrender_image.get().unwrap(), + }) { + warn!( + "Failed to send UpdateWebrenderData({:?}) ({})", + self.context_id, e + ); + } + } + + pub fn context_id(&self) -> WebGPUContextId { + self.context_id + } + + pub fn mark_as_dirty(&self) { + self.canvas + .upcast::<Node>() + .dirty(NodeDamage::OtherNodeDamage); + + let document = document_from_node(&*self.canvas); + document.add_dirty_webgpu_canvas(self); + } +} + +impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> { + #[allow(unsafe_code)] + unsafe fn canvas_data_source(self) -> HTMLCanvasDataSource { + (*self.unsafe_get()).layout_handle() + } +} + +impl GPUCanvasContextMethods for GPUCanvasContext { + /// https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configureswapchain + fn ConfigureSwapChain(&self, descriptor: &GPUSwapChainDescriptor) -> DomRoot<GPUSwapChain> { + if let Some(chain) = &*self.swap_chain.borrow() { + chain.destroy(self.context_id.0, self.webrender_image.get().unwrap()); + self.webrender_image.set(None); + } + *self.swap_chain.borrow_mut() = None; + + let buffer_id = self + .global() + .wgpu_id_hub() + .lock() + .create_buffer_id(descriptor.device.id().0.backend()); + + let image_desc = webrender_api::ImageDescriptor { + format: match descriptor.format { + GPUTextureFormat::Rgba8unorm => webrender_api::ImageFormat::RGBA8, + GPUTextureFormat::Bgra8unorm => webrender_api::ImageFormat::BGRA8, + _ => panic!("SwapChain format({:?}) not supported", descriptor.format), + }, + size: webrender_api::units::DeviceIntSize::new( + self.size.get().width as i32, + self.size.get().height as i32, + ), + stride: Some( + (((self.size.get().width * 4) | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1) + as i32, + ), + offset: 0, + flags: webrender_api::ImageDescriptorFlags::from_bits(1).unwrap(), + }; + + let image_data = webrender_api::ImageData::External(webrender_api::ExternalImageData { + id: webrender_api::ExternalImageId(self.context_id.0), + channel_index: 0, + image_type: webrender_api::ExternalImageType::Buffer, + }); + + let (sender, receiver) = ipc::channel().unwrap(); + + self.channel + .0 + .send(WebGPURequest::CreateSwapChain { + device_id: descriptor.device.id().0, + buffer_id, + external_id: self.context_id.0, + sender, + image_desc, + image_data, + }) + .expect("Failed to create WebGPU SwapChain"); + + let usage = if descriptor.usage % 2 == 0 { + descriptor.usage + 1 + } else { + descriptor.usage + }; + let text_desc = GPUTextureDescriptor { + parent: GPUObjectDescriptorBase { label: None }, + dimension: GPUTextureDimension::_2d, + format: descriptor.format, + mipLevelCount: 1, + sampleCount: 1, + usage, + size: GPUExtent3D::GPUExtent3DDict(GPUExtent3DDict { + width: self.size.get().width, + height: self.size.get().height, + depth: 1, + }), + }; + + let texture = descriptor.device.CreateTexture(&text_desc); + + self.webrender_image.set(Some(receiver.recv().unwrap())); + + let swap_chain = GPUSwapChain::new(&self.global(), self.channel.clone(), &self, &*texture); + *self.swap_chain.borrow_mut() = Some(Dom::from_ref(&*swap_chain)); + swap_chain + } +} diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs index e8720bf2189..fbbfa541761 100644 --- a/components/script/dom/gpudevice.rs +++ b/components/script/dom/gpudevice.rs @@ -118,6 +118,10 @@ impl GPUDevice { } impl GPUDevice { + pub fn id(&self) -> webgpu::WebGPUDevice { + self.device + } + fn validate_buffer_descriptor( &self, descriptor: &GPUBufferDescriptor, diff --git a/components/script/dom/gpuswapchain.rs b/components/script/dom/gpuswapchain.rs new file mode 100644 index 00000000000..05fa3c99a5b --- /dev/null +++ b/components/script/dom/gpuswapchain.rs @@ -0,0 +1,85 @@ +/* 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 crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::GPUSwapChainBinding::GPUSwapChainMethods; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; +use crate::dom::globalscope::GlobalScope; +use crate::dom::gpucanvascontext::GPUCanvasContext; +use crate::dom::gputexture::GPUTexture; +use dom_struct::dom_struct; +use webgpu::{WebGPU, WebGPURequest, WebGPUTexture}; + +#[dom_struct] +pub struct GPUSwapChain { + reflector_: Reflector, + #[ignore_malloc_size_of = "channels are hard"] + channel: WebGPU, + label: DomRefCell<Option<DOMString>>, + context: Dom<GPUCanvasContext>, + texture: Dom<GPUTexture>, +} + +impl GPUSwapChain { + fn new_inherited(channel: WebGPU, context: &GPUCanvasContext, texture: &GPUTexture) -> Self { + Self { + reflector_: Reflector::new(), + channel, + context: Dom::from_ref(context), + texture: Dom::from_ref(texture), + label: DomRefCell::new(None), + } + } + + pub fn new( + global: &GlobalScope, + channel: WebGPU, + context: &GPUCanvasContext, + texture: &GPUTexture, + ) -> DomRoot<Self> { + reflect_dom_object( + Box::new(GPUSwapChain::new_inherited(channel, context, texture)), + global, + ) + } +} + +impl GPUSwapChain { + pub fn destroy(&self, external_id: u64, image_key: webrender_api::ImageKey) { + if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain { + external_id, + image_key, + }) { + warn!( + "Failed to send DestroySwapChain-ImageKey({:?}) ({})", + image_key, e + ); + } + } + + pub fn texture_id(&self) -> WebGPUTexture { + self.texture.id() + } +} + +impl GPUSwapChainMethods for GPUSwapChain { + /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label + fn GetLabel(&self) -> Option<DOMString> { + self.label.borrow().clone() + } + + /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label + fn SetLabel(&self, value: Option<DOMString>) { + *self.label.borrow_mut() = value; + } + + /// https://gpuweb.github.io/gpuweb/#dom-gpuswapchain-getcurrenttexture + fn GetCurrentTexture(&self) -> DomRoot<GPUTexture> { + self.context.mark_as_dirty(); + //self.context.send_swap_chain_present(); + DomRoot::from_ref(&*self.texture) + } +} diff --git a/components/script/dom/gputexture.rs b/components/script/dom/gputexture.rs index be2d11bfc50..48060efa666 100644 --- a/components/script/dom/gputexture.rs +++ b/components/script/dom/gputexture.rs @@ -103,6 +103,12 @@ impl Drop for GPUTexture { } } +impl GPUTexture { + pub fn id(&self) -> WebGPUTexture { + self.texture + } +} + impl GPUTextureMethods for GPUTexture { /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label fn GetLabel(&self) -> Option<DOMString> { diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 87edeaeaab8..4b7d54b323d 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -20,13 +20,12 @@ use crate::dom::canvasrenderingcontext2d::{ use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers}; use crate::dom::globalscope::GlobalScope; +use crate::dom::gpucanvascontext::GPUCanvasContext; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{window_from_node, Node}; use crate::dom::virtualmethods::VirtualMethods; use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; -use crate::dom::webglrenderingcontext::{ - LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext, -}; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::script_runtime::JSContext; use base64; use canvas_traits::canvas::{CanvasId, CanvasMsg, FromScriptMsg}; @@ -36,11 +35,12 @@ use euclid::default::{Rect, Size2D}; use html5ever::{LocalName, Prefix}; use image::png::PNGEncoder; use image::ColorType; -use ipc_channel::ipc::IpcSharedMemory; +use ipc_channel::ipc::{self as ipcchan, IpcSharedMemory}; use js::error::throw_type_error; use js::rust::HandleValue; use profile_traits::ipc; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; +use script_traits::ScriptMsg; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; const DEFAULT_WIDTH: u32 = 300; @@ -52,6 +52,7 @@ pub enum CanvasContext { Context2d(Dom<CanvasRenderingContext2D>), WebGL(Dom<WebGLRenderingContext>), WebGL2(Dom<WebGL2RenderingContext>), + WebGPU(Dom<GPUCanvasContext>), } #[dom_struct] @@ -95,6 +96,7 @@ impl HTMLCanvasElement { }, CanvasContext::WebGL(ref context) => context.recreate(size), CanvasContext::WebGL2(ref context) => context.recreate(size), + CanvasContext::WebGPU(_) => unimplemented!(), } } } @@ -111,6 +113,11 @@ impl HTMLCanvasElement { } } +pub trait LayoutCanvasRenderingContextHelpers { + #[allow(unsafe_code)] + unsafe fn canvas_data_source(self) -> HTMLCanvasDataSource; +} + pub trait LayoutHTMLCanvasElementHelpers { fn data(self) -> HTMLCanvasData; fn get_width(self) -> LengthOrPercentageOrAuto; @@ -132,6 +139,9 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> { Some(&CanvasContext::WebGL2(ref context)) => { context.to_layout().canvas_data_source() }, + Some(&CanvasContext::WebGPU(ref context)) => { + context.to_layout().canvas_data_source() + }, None => HTMLCanvasDataSource::Image(None), } }; @@ -239,6 +249,26 @@ impl HTMLCanvasElement { Some(context) } + fn get_or_init_webgpu_context(&self) -> Option<DomRoot<GPUCanvasContext>> { + if let Some(ctx) = self.context() { + return match *ctx { + CanvasContext::WebGPU(ref ctx) => Some(DomRoot::from_ref(ctx)), + _ => None, + }; + } + let (sender, receiver) = ipcchan::channel().unwrap(); + let _ = self + .global() + .script_to_constellation_chan() + .send(ScriptMsg::GetWebGPUChan(sender)); + let window = window_from_node(self); + let size = self.get_size(); + let channel = receiver.recv().expect("Failed to get WebGPU channel"); + let context = GPUCanvasContext::new(window.upcast::<GlobalScope>(), self, size, channel); + *self.context.borrow_mut() = Some(CanvasContext::WebGPU(Dom::from_ref(&*context))); + Some(context) + } + /// Gets the base WebGLRenderingContext for WebGL or WebGL 2, if exists. pub fn get_base_webgl_context(&self) -> Option<DomRoot<WebGLRenderingContext>> { match *self.context.borrow() { @@ -296,6 +326,10 @@ impl HTMLCanvasElement { // TODO: add a method in WebGL2RenderingContext to get the pixels. return None; }, + Some(&CanvasContext::WebGPU(_)) => { + // TODO: add a method in GPUCanvasContext to get the pixels. + return None; + }, None => None, }; @@ -333,6 +367,9 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { "webgl2" | "experimental-webgl2" => self .get_or_init_webgl2_context(cx, options) .map(RenderingContext::WebGL2RenderingContext), + "gpupresent" => self + .get_or_init_webgpu_context() + .map(RenderingContext::GPUCanvasContext), _ => None, } } @@ -371,6 +408,8 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { None => return Ok(USVString("data:,".into())), } }, + //TODO: Add method get_image_data to GPUCanvasContext + Some(CanvasContext::WebGPU(_)) => return Ok(USVString("data:,".into())), None => { // Each pixel is fully-transparent black. vec![0; (self.Width() * self.Height() * 4) as usize] diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index a8e0a9cdc78..2ee17f3e74b 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -325,6 +325,7 @@ pub mod gpubindgroup; pub mod gpubindgrouplayout; pub mod gpubuffer; pub mod gpubufferusage; +pub mod gpucanvascontext; pub mod gpucolorwrite; pub mod gpucommandbuffer; pub mod gpucommandencoder; @@ -338,6 +339,7 @@ pub mod gpurenderpipeline; pub mod gpusampler; pub mod gpushadermodule; pub mod gpushaderstage; +pub mod gpuswapchain; pub mod gputexture; pub mod gputextureusage; pub mod gputextureview; diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 41d3cd5b66c..0ca44ab3d7c 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -17,7 +17,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; -use crate::dom::htmlcanvaselement::HTMLCanvasElement; +use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers}; use crate::dom::webgl_validations::tex_image_2d::{ TexImage2DValidator, TexImage2DValidatorResult, TexStorageValidator, TexStorageValidatorResult, }; @@ -29,8 +29,7 @@ use crate::dom::webglprogram::WebGLProgram; use crate::dom::webglquery::WebGLQuery; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::{ - uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, Operation, TexPixels, - VertexAttrib, WebGLRenderingContext, + uniform_get, uniform_typed, Operation, TexPixels, VertexAttrib, WebGLRenderingContext, }; use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue}; use crate::dom::webglshader::WebGLShader; @@ -4381,7 +4380,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } } -impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> { +impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> { #[allow(unsafe_code)] unsafe fn canvas_data_source(self) -> HTMLCanvasDataSource { let this = &*self.unsafe_get(); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index c602b294548..4c1adbc58d3 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -23,7 +23,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::element::cors_setting_for_element; use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::htmlcanvaselement::utils as canvas_utils; -use crate::dom::htmlcanvaselement::HTMLCanvasElement; +use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers}; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage}; use crate::dom::promise::Promise; @@ -539,7 +539,7 @@ impl WebGLRenderingContext { .dirty(NodeDamage::OtherNodeDamage); let document = document_from_node(&*self.canvas); - document.add_dirty_canvas(self); + document.add_dirty_webgl_canvas(self); } fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) { @@ -4697,12 +4697,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } -pub trait LayoutCanvasWebGLRenderingContextHelpers { - #[allow(unsafe_code)] - unsafe fn canvas_data_source(self) -> HTMLCanvasDataSource; -} - -impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> { +impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> { #[allow(unsafe_code)] unsafe fn canvas_data_source(self) -> HTMLCanvasDataSource { (*self.unsafe_get()).layout_handle() diff --git a/components/script/dom/webidls/GPUCanvasContext.webidl b/components/script/dom/webidls/GPUCanvasContext.webidl new file mode 100644 index 00000000000..5e19f1467e6 --- /dev/null +++ b/components/script/dom/webidls/GPUCanvasContext.webidl @@ -0,0 +1,17 @@ +/* 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/. */ + +// https://gpuweb.github.io/gpuweb/#gpucanvascontext +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPUCanvasContext { + GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor); + + //Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device); +}; + +dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase { + required GPUDevice device; + required GPUTextureFormat format; + GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.OUTPUT_ATTACHMENT +}; diff --git a/components/script/dom/webidls/GPUSwapChain.webidl b/components/script/dom/webidls/GPUSwapChain.webidl new file mode 100644 index 00000000000..aa64e232134 --- /dev/null +++ b/components/script/dom/webidls/GPUSwapChain.webidl @@ -0,0 +1,10 @@ +/* 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/. */ + +// https://gpuweb.github.io/gpuweb/#gpuswapchain +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPUSwapChain { + GPUTexture getCurrentTexture(); +}; +GPUSwapChain includes GPUObjectBase; diff --git a/components/script/dom/webidls/HTMLCanvasElement.webidl b/components/script/dom/webidls/HTMLCanvasElement.webidl index afc10fdd640..650357a905e 100644 --- a/components/script/dom/webidls/HTMLCanvasElement.webidl +++ b/components/script/dom/webidls/HTMLCanvasElement.webidl @@ -3,7 +3,10 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlcanvaselement -typedef (CanvasRenderingContext2D or WebGLRenderingContext or WebGL2RenderingContext) RenderingContext; +typedef (CanvasRenderingContext2D + or WebGLRenderingContext + or WebGL2RenderingContext + or GPUCanvasContext) RenderingContext; [Exposed=Window] interface HTMLCanvasElement : HTMLElement { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d7fde4f27d5..b555300e219 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1665,7 +1665,8 @@ impl Window { // If this reflow is for display, ensure webgl canvases are composited with // up-to-date contents. if for_display { - document.flush_dirty_canvases(); + document.flush_dirty_webgpu_canvases(); + document.flush_dirty_webgl_canvases(); } let pending_restyles = document.drain_pending_restyles(); |