diff options
author | Samson <16504129+sagudev@users.noreply.github.com> | 2025-01-31 16:24:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-31 15:24:33 +0000 |
commit | 35835af8570f0c91924b86d9688bff306ab012bc (patch) | |
tree | e3c2cb288d394a9d3822b4c7f9ba26fe64246cc9 | |
parent | 42b581a6f6a303679329acab928dc4396d1b281a (diff) | |
download | servo-35835af8570f0c91924b86d9688bff306ab012bc.tar.gz servo-35835af8570f0c91924b86d9688bff306ab012bc.zip |
webgpu: implement get image for webgpu canvas (#35237)
* Implement `get_image_data` for WebGPU canvas
Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
* Update expectations
Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
* Add docs
Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
---------
Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 8 | ||||
-rw-r--r-- | components/script/dom/webgpu/gpucanvascontext.rs | 24 | ||||
-rw-r--r-- | components/webgpu/ipc_messages/recv.rs | 5 | ||||
-rw-r--r-- | components/webgpu/swapchain.rs | 18 | ||||
-rw-r--r-- | components/webgpu/wgpu_thread.rs | 3 | ||||
-rw-r--r-- | tests/wpt/webgpu/meta/webgpu/cts.https.html.ini | 32 |
6 files changed, 50 insertions, 40 deletions
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index aee09ee4dd2..8fb2832915a 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -420,10 +420,7 @@ impl HTMLCanvasElement { return None; }, #[cfg(feature = "webgpu")] - Some(&CanvasContext::WebGPU(_)) => { - // TODO: add a method in GPUCanvasContext to get the pixels. - return None; - }, + Some(CanvasContext::WebGPU(context)) => Some(context.get_ipc_image()), Some(CanvasContext::Placeholder(context)) => { let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); @@ -450,9 +447,8 @@ impl HTMLCanvasElement { Some(CanvasContext::WebGL2(ref context)) => { context.base_context().get_image_data(self.get_size()) }, - //TODO: Add method get_image_data to GPUCanvasContext #[cfg(feature = "webgpu")] - Some(CanvasContext::WebGPU(_)) => None, + Some(CanvasContext::WebGPU(ref context)) => Some(context.get_image_data()), Some(CanvasContext::Placeholder(_)) | None => { // Each pixel is fully-transparent black. Some(vec![0; (self.Width() * self.Height() * 4) as usize]) diff --git a/components/script/dom/webgpu/gpucanvascontext.rs b/components/script/dom/webgpu/gpucanvascontext.rs index 51627071271..e1cfd4e5176 100644 --- a/components/script/dom/webgpu/gpucanvascontext.rs +++ b/components/script/dom/webgpu/gpucanvascontext.rs @@ -8,7 +8,7 @@ use std::cell::RefCell; use arrayvec::ArrayVec; use dom_struct::dom_struct; use euclid::default::Size2D; -use ipc_channel::ipc; +use ipc_channel::ipc::{self, IpcSharedMemory}; use script_layout_interface::HTMLCanvasDataSource; use webgpu::swapchain::WebGPUContextId; use webgpu::wgc::id; @@ -306,6 +306,28 @@ impl GPUCanvasContext { .replace(Some(self.texture_descriptor_for_canvas(configuration))); } } + + /// <https://gpuweb.github.io/gpuweb/#ref-for-abstract-opdef-get-a-copy-of-the-image-contents-of-a-context%E2%91%A5> + pub(crate) fn get_ipc_image(&self) -> IpcSharedMemory { + // 1. Return a copy of the image contents of context. + if self.drawing_buffer.borrow().cleared { + IpcSharedMemory::from_byte(0, self.size().area() as usize * 4) + } else { + let (sender, receiver) = ipc::channel().unwrap(); + self.channel + .0 + .send(WebGPURequest::GetImage { + context_id: self.context_id, + sender, + }) + .unwrap(); + receiver.recv().unwrap() + } + } + + pub(crate) fn get_image_data(&self) -> Vec<u8> { + self.get_ipc_image().to_vec() + } } impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> { diff --git a/components/webgpu/ipc_messages/recv.rs b/components/webgpu/ipc_messages/recv.rs index 0ae97e4ec22..6355cb932a8 100644 --- a/components/webgpu/ipc_messages/recv.rs +++ b/components/webgpu/ipc_messages/recv.rs @@ -154,6 +154,11 @@ pub enum WebGPURequest { texture_id: id::TextureId, encoder_id: id::CommandEncoderId, }, + /// Obtains image from latest presentation buffer (same as wr update) + GetImage { + context_id: WebGPUContextId, + sender: IpcSender<IpcSharedMemory>, + }, ValidateTextureDescriptor { device_id: id::DeviceId, texture_id: id::TextureId, diff --git a/components/webgpu/swapchain.rs b/components/webgpu/swapchain.rs index b1512eae809..cc4a645aba9 100644 --- a/components/webgpu/swapchain.rs +++ b/components/webgpu/swapchain.rs @@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex}; use arrayvec::ArrayVec; use euclid::default::Size2D; -use ipc_channel::ipc::IpcSender; +use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use log::{error, warn}; use malloc_size_of::MallocSizeOf; use serde::{Deserialize, Serialize}; @@ -382,6 +382,22 @@ impl crate::WGPU { ); } + pub(crate) fn get_image(&self, context_id: WebGPUContextId) -> IpcSharedMemory { + let webgpu_contexts = self.wgpu_image_map.lock().unwrap(); + let context_data = webgpu_contexts.get(&context_id).unwrap(); + let buffer_size = context_data.image_desc.buffer_size(); + let data = if let Some(present_buffer) = context_data + .swap_chain + .as_ref() + .and_then(|swap_chain| swap_chain.data.as_ref()) + { + IpcSharedMemory::from_bytes(present_buffer.slice()) + } else { + IpcSharedMemory::from_byte(0, buffer_size as usize) + }; + data + } + pub(crate) fn update_context( &self, context_id: WebGPUContextId, diff --git a/components/webgpu/wgpu_thread.rs b/components/webgpu/wgpu_thread.rs index e03513a0dbb..63b7825723c 100644 --- a/components/webgpu/wgpu_thread.rs +++ b/components/webgpu/wgpu_thread.rs @@ -531,6 +531,9 @@ impl WGPU { log::error!("Error occured in SwapChainPresent: {e:?}"); } }, + WebGPURequest::GetImage { context_id, sender } => { + sender.send(self.get_image(context_id)).unwrap() + }, WebGPURequest::ValidateTextureDescriptor { device_id, texture_id, diff --git a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini index bf265f02b54..d92953110f2 100644 --- a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini @@ -546023,48 +546023,32 @@ if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba16float";alphaMode="opaque";colorSpace="display-p3";snapshotType="imageBitmap"] expected: @@ -546119,48 +546103,32 @@ if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="imageBitmap"] expected: if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toDataURL"] - expected: - if os == "linux" and not debug: FAIL [cts.https.html?q=webgpu:web_platform,canvas,readbackFromWebGPUCanvas:onscreenCanvas,uploadToWebGL:*] |