aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamson <16504129+sagudev@users.noreply.github.com>2025-01-31 16:24:33 +0100
committerGitHub <noreply@github.com>2025-01-31 15:24:33 +0000
commit35835af8570f0c91924b86d9688bff306ab012bc (patch)
treee3c2cb288d394a9d3822b4c7f9ba26fe64246cc9
parent42b581a6f6a303679329acab928dc4396d1b281a (diff)
downloadservo-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.rs8
-rw-r--r--components/script/dom/webgpu/gpucanvascontext.rs24
-rw-r--r--components/webgpu/ipc_messages/recv.rs5
-rw-r--r--components/webgpu/swapchain.rs18
-rw-r--r--components/webgpu/wgpu_thread.rs3
-rw-r--r--tests/wpt/webgpu/meta/webgpu/cts.https.html.ini32
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:*]