Implement GPUSwapChain and GPUCanvasContext and interface with Webrender

This commit is contained in:
Kunal Mohan 2020-06-04 19:28:25 +05:30
parent 73760ea594
commit 71401e0855
28 changed files with 882 additions and 91 deletions

View file

@ -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]