mirror of
https://github.com/servo/servo.git
synced 2025-07-24 07:40:27 +01:00
Reuse same ImageKey
for 2d canvas (#35695)
this was not possible when original code was written due to wr limitations (image sizes could not be changed) Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
3cf4ef61ef
commit
ce9c988f79
1 changed files with 34 additions and 59 deletions
|
@ -14,7 +14,7 @@ use fonts::{
|
||||||
ShapingFlags, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE,
|
ShapingFlags, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE,
|
||||||
};
|
};
|
||||||
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
||||||
use log::{debug, warn};
|
use log::warn;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use range::Range;
|
use range::Range;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
|
@ -425,11 +425,7 @@ pub struct CanvasData<'a> {
|
||||||
state: CanvasPaintState<'a>,
|
state: CanvasPaintState<'a>,
|
||||||
saved_states: Vec<CanvasPaintState<'a>>,
|
saved_states: Vec<CanvasPaintState<'a>>,
|
||||||
compositor_api: CrossProcessCompositorApi,
|
compositor_api: CrossProcessCompositorApi,
|
||||||
image_key: Option<ImageKey>,
|
image_key: ImageKey,
|
||||||
/// An old webrender image key that can be deleted when the next epoch ends.
|
|
||||||
old_image_key: Option<ImageKey>,
|
|
||||||
/// An old webrender image key that can be deleted when the current epoch ends.
|
|
||||||
very_old_image_key: Option<ImageKey>,
|
|
||||||
font_context: Arc<FontContext>,
|
font_context: Arc<FontContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +441,18 @@ impl<'a> CanvasData<'a> {
|
||||||
) -> CanvasData<'a> {
|
) -> CanvasData<'a> {
|
||||||
let backend = create_backend();
|
let backend = create_backend();
|
||||||
let draw_target = backend.create_drawtarget(size);
|
let draw_target = backend.create_drawtarget(size);
|
||||||
|
let image_key = compositor_api.generate_image_key().unwrap();
|
||||||
|
let descriptor = ImageDescriptor {
|
||||||
|
size: size.cast().cast_unit(),
|
||||||
|
stride: None,
|
||||||
|
format: ImageFormat::BGRA8,
|
||||||
|
offset: 0,
|
||||||
|
flags: ImageDescriptorFlags::empty(),
|
||||||
|
};
|
||||||
|
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(
|
||||||
|
&draw_target.snapshot_data_owned(),
|
||||||
|
));
|
||||||
|
compositor_api.update_images(vec![ImageUpdate::AddImage(image_key, descriptor, data)]);
|
||||||
CanvasData {
|
CanvasData {
|
||||||
backend,
|
backend,
|
||||||
drawtarget: draw_target,
|
drawtarget: draw_target,
|
||||||
|
@ -452,9 +460,7 @@ impl<'a> CanvasData<'a> {
|
||||||
state: CanvasPaintState::default(),
|
state: CanvasPaintState::default(),
|
||||||
saved_states: vec![],
|
saved_states: vec![],
|
||||||
compositor_api,
|
compositor_api,
|
||||||
image_key: None,
|
image_key,
|
||||||
old_image_key: None,
|
|
||||||
very_old_image_key: None,
|
|
||||||
font_context,
|
font_context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1243,17 +1249,7 @@ impl<'a> CanvasData<'a> {
|
||||||
.create_drawtarget(Size2D::new(size.width, size.height));
|
.create_drawtarget(Size2D::new(size.width, size.height));
|
||||||
self.state = self.backend.recreate_paint_state(&self.state);
|
self.state = self.backend.recreate_paint_state(&self.state);
|
||||||
self.saved_states.clear();
|
self.saved_states.clear();
|
||||||
// Webrender doesn't let images change size, so we clear the webrender image key.
|
self.update_wr_image(size.cast().cast_unit());
|
||||||
// TODO: there is an annying race condition here: the display list builder
|
|
||||||
// might still be using the old image key. Really, we should be scheduling the image
|
|
||||||
// for later deletion, not deleting it immediately.
|
|
||||||
// https://github.com/servo/servo/issues/17534
|
|
||||||
if let Some(image_key) = self.image_key.take() {
|
|
||||||
// If this executes, then we are in a new epoch since we last recreated the canvas,
|
|
||||||
// so `old_image_key` must be `None`.
|
|
||||||
debug_assert!(self.old_image_key.is_none());
|
|
||||||
self.old_image_key = Some(image_key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_pixels(&mut self, chan: IpcSender<IpcSharedMemory>) {
|
pub fn send_pixels(&mut self, chan: IpcSender<IpcSharedMemory>) {
|
||||||
|
@ -1267,8 +1263,17 @@ impl<'a> CanvasData<'a> {
|
||||||
pub fn send_data(&mut self, chan: IpcSender<CanvasImageData>) {
|
pub fn send_data(&mut self, chan: IpcSender<CanvasImageData>) {
|
||||||
let size = self.drawtarget.get_size();
|
let size = self.drawtarget.get_size();
|
||||||
|
|
||||||
|
self.update_wr_image(size.cast_unit());
|
||||||
|
|
||||||
|
let data = CanvasImageData {
|
||||||
|
image_key: self.image_key,
|
||||||
|
};
|
||||||
|
chan.send(data).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_wr_image(&mut self, size: DeviceIntSize) {
|
||||||
let descriptor = ImageDescriptor {
|
let descriptor = ImageDescriptor {
|
||||||
size: DeviceIntSize::new(size.width, size.height),
|
size,
|
||||||
stride: None,
|
stride: None,
|
||||||
format: ImageFormat::BGRA8,
|
format: ImageFormat::BGRA8,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
|
@ -1278,35 +1283,12 @@ impl<'a> CanvasData<'a> {
|
||||||
&self.drawtarget.snapshot_data_owned(),
|
&self.drawtarget.snapshot_data_owned(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut updates = vec![];
|
self.compositor_api
|
||||||
|
.update_images(vec![ImageUpdate::UpdateImage(
|
||||||
match self.image_key {
|
self.image_key,
|
||||||
Some(image_key) => {
|
descriptor,
|
||||||
debug!("Updating image {:?}.", image_key);
|
data,
|
||||||
updates.push(ImageUpdate::UpdateImage(image_key, descriptor, data));
|
)]);
|
||||||
},
|
|
||||||
None => {
|
|
||||||
let Some(key) = self.compositor_api.generate_image_key() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
updates.push(ImageUpdate::AddImage(key, descriptor, data));
|
|
||||||
self.image_key = Some(key);
|
|
||||||
debug!("New image {:?}.", self.image_key);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(image_key) =
|
|
||||||
mem::replace(&mut self.very_old_image_key, self.old_image_key.take())
|
|
||||||
{
|
|
||||||
updates.push(ImageUpdate::DeleteImage(image_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.compositor_api.update_images(updates);
|
|
||||||
|
|
||||||
let data = CanvasImageData {
|
|
||||||
image_key: self.image_key.unwrap(),
|
|
||||||
};
|
|
||||||
chan.send(data).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
||||||
|
@ -1414,15 +1396,8 @@ impl<'a> CanvasData<'a> {
|
||||||
|
|
||||||
impl Drop for CanvasData<'_> {
|
impl Drop for CanvasData<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut updates = vec![];
|
self.compositor_api
|
||||||
if let Some(image_key) = self.old_image_key.take() {
|
.update_images(vec![ImageUpdate::DeleteImage(self.image_key)]);
|
||||||
updates.push(ImageUpdate::DeleteImage(image_key));
|
|
||||||
}
|
|
||||||
if let Some(image_key) = self.very_old_image_key.take() {
|
|
||||||
updates.push(ImageUpdate::DeleteImage(image_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.compositor_api.update_images(updates);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue