compositor: Allow canvas to upload rendered contents asynchronously (#37776)

Adds epoch to each WR image op command that is sent to compositor. The
renderer now has a `FrameDelayer` data structure that is responsible for
tracking when a frame is ready to be displayed. When asking canvases to
update their rendering, they are given an optional `Epoch` which denotes
the `Document`'s canvas epoch. When all image updates for that `Epoch`
are seen in the renderer, the frame can be displayed.

Testing: Existing WPT tests
Fixes: #35733

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Sam 2025-08-29 12:04:41 +02:00 committed by GitHub
parent 4700149fcb
commit 8beef6c21f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 452 additions and 100 deletions

View file

@ -8,6 +8,7 @@ use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::{slice, thread};
use base::Epoch;
use base::generic_channel::RoutedReceiver;
use bitflags::bitflags;
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
@ -381,8 +382,8 @@ impl WebGLThread {
#[cfg(feature = "webxr")]
self.handle_webxr_command(_command);
},
WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => {
self.handle_swap_buffers(swap_ids, sender, sent_time);
WebGLMsg::SwapBuffers(swap_ids, canvas_epoch, sent_time) => {
self.handle_swap_buffers(canvas_epoch, swap_ids, sent_time);
},
WebGLMsg::Exit(sender) => {
// Call remove_context functions in order to correctly delete WebRender image keys.
@ -711,7 +712,7 @@ impl WebGLThread {
.state
.requested_flags
.contains(ContextAttributeFlags::ALPHA);
self.update_wr_image_for_context(context_id, size.to_i32(), has_alpha);
self.update_wr_image_for_context(context_id, size.to_i32(), has_alpha, None);
Ok(())
}
@ -766,8 +767,8 @@ impl WebGLThread {
fn handle_swap_buffers(
&mut self,
canvas_epoch: Option<Epoch>,
context_ids: Vec<WebGLContextId>,
completed_sender: WebGLSender<u64>,
_sent_time: u64,
) {
debug!("handle_swap_buffers()");
@ -846,12 +847,11 @@ impl WebGLThread {
.state
.requested_flags
.contains(ContextAttributeFlags::ALPHA);
self.update_wr_image_for_context(context_id, size, has_alpha);
self.update_wr_image_for_context(context_id, size, has_alpha, canvas_epoch);
}
#[allow(unused)]
let mut end_swap = 0;
completed_sender.send(end_swap).unwrap();
}
/// Which access mode to use
@ -921,6 +921,7 @@ impl WebGLThread {
context_id: WebGLContextId,
size: Size2D<i32>,
has_alpha: bool,
canvas_epoch: Option<Epoch>,
) {
let info = self.cached_context_info.get(&context_id).unwrap();
let image_buffer_kind = current_wr_image_buffer_kind(&self.device);
@ -929,7 +930,7 @@ impl WebGLThread {
let image_data = Self::external_image_data(context_id, image_buffer_kind);
self.compositor_api
.update_image(info.image_key, descriptor, image_data);
.update_image(info.image_key, descriptor, image_data, canvas_epoch);
}
/// Helper function to create a `ImageDescriptor`.