mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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>
This commit is contained in:
parent
42b581a6f6
commit
35835af857
6 changed files with 50 additions and 40 deletions
|
@ -420,10 +420,7 @@ impl HTMLCanvasElement {
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
Some(&CanvasContext::WebGPU(_)) => {
|
Some(CanvasContext::WebGPU(context)) => Some(context.get_ipc_image()),
|
||||||
// TODO: add a method in GPUCanvasContext to get the pixels.
|
|
||||||
return None;
|
|
||||||
},
|
|
||||||
Some(CanvasContext::Placeholder(context)) => {
|
Some(CanvasContext::Placeholder(context)) => {
|
||||||
let (sender, receiver) =
|
let (sender, receiver) =
|
||||||
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
@ -450,9 +447,8 @@ impl HTMLCanvasElement {
|
||||||
Some(CanvasContext::WebGL2(ref context)) => {
|
Some(CanvasContext::WebGL2(ref context)) => {
|
||||||
context.base_context().get_image_data(self.get_size())
|
context.base_context().get_image_data(self.get_size())
|
||||||
},
|
},
|
||||||
//TODO: Add method get_image_data to GPUCanvasContext
|
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
Some(CanvasContext::WebGPU(_)) => None,
|
Some(CanvasContext::WebGPU(ref context)) => Some(context.get_image_data()),
|
||||||
Some(CanvasContext::Placeholder(_)) | None => {
|
Some(CanvasContext::Placeholder(_)) | None => {
|
||||||
// Each pixel is fully-transparent black.
|
// Each pixel is fully-transparent black.
|
||||||
Some(vec![0; (self.Width() * self.Height() * 4) as usize])
|
Some(vec![0; (self.Width() * self.Height() * 4) as usize])
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::cell::RefCell;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||||
use script_layout_interface::HTMLCanvasDataSource;
|
use script_layout_interface::HTMLCanvasDataSource;
|
||||||
use webgpu::swapchain::WebGPUContextId;
|
use webgpu::swapchain::WebGPUContextId;
|
||||||
use webgpu::wgc::id;
|
use webgpu::wgc::id;
|
||||||
|
@ -306,6 +306,28 @@ impl GPUCanvasContext {
|
||||||
.replace(Some(self.texture_descriptor_for_canvas(configuration)));
|
.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> {
|
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
|
||||||
|
|
|
@ -154,6 +154,11 @@ pub enum WebGPURequest {
|
||||||
texture_id: id::TextureId,
|
texture_id: id::TextureId,
|
||||||
encoder_id: id::CommandEncoderId,
|
encoder_id: id::CommandEncoderId,
|
||||||
},
|
},
|
||||||
|
/// Obtains image from latest presentation buffer (same as wr update)
|
||||||
|
GetImage {
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
sender: IpcSender<IpcSharedMemory>,
|
||||||
|
},
|
||||||
ValidateTextureDescriptor {
|
ValidateTextureDescriptor {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
texture_id: id::TextureId,
|
texture_id: id::TextureId,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use malloc_size_of::MallocSizeOf;
|
use malloc_size_of::MallocSizeOf;
|
||||||
use serde::{Deserialize, Serialize};
|
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(
|
pub(crate) fn update_context(
|
||||||
&self,
|
&self,
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
|
|
|
@ -531,6 +531,9 @@ impl WGPU {
|
||||||
log::error!("Error occured in SwapChainPresent: {e:?}");
|
log::error!("Error occured in SwapChainPresent: {e:?}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
WebGPURequest::GetImage { context_id, sender } => {
|
||||||
|
sender.send(self.get_image(context_id)).unwrap()
|
||||||
|
},
|
||||||
WebGPURequest::ValidateTextureDescriptor {
|
WebGPURequest::ValidateTextureDescriptor {
|
||||||
device_id,
|
device_id,
|
||||||
texture_id,
|
texture_id,
|
||||||
|
|
32
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
32
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
|
@ -546023,48 +546023,32 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toBlob"]
|
[: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"]
|
[: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"]
|
[:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"]
|
[:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toDataURL"]
|
[: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"]
|
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toBlob"]
|
[: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"]
|
[: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"]
|
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"]
|
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:format="bgra8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toDataURL"]
|
[: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"]
|
[:format="rgba16float";alphaMode="opaque";colorSpace="display-p3";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -546119,48 +546103,32 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="opaque";colorSpace="display-p3";snapshotType="toBlob"]
|
[: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"]
|
[: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"]
|
[:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"]
|
[:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toBlob"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="opaque";colorSpace="srgb";snapshotType="toDataURL"]
|
[: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"]
|
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="display-p3";snapshotType="toBlob"]
|
[: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"]
|
[: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"]
|
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="imageBitmap"]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"]
|
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toBlob"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:format="rgba8unorm";alphaMode="premultiplied";colorSpace="srgb";snapshotType="toDataURL"]
|
[: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:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,readbackFromWebGPUCanvas:onscreenCanvas,uploadToWebGL:*]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue