mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
webgl: Lazily clear the canvas right before the first webgl command of the next frame.
This commit is contained in:
parent
4d7110aca5
commit
c53680b282
8 changed files with 138 additions and 124 deletions
|
@ -179,6 +179,17 @@ impl GLContextWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn framebuffer(&self) -> gl::GLuint {
|
||||||
|
match *self {
|
||||||
|
GLContextWrapper::Native(ref ctx) => {
|
||||||
|
ctx.borrow_draw_buffer().unwrap().get_framebuffer()
|
||||||
|
},
|
||||||
|
GLContextWrapper::OSMesa(ref ctx) => {
|
||||||
|
ctx.borrow_draw_buffer().unwrap().get_framebuffer()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_info(&self) -> (Size2D<i32>, u32, GLLimits, GLFormats) {
|
pub fn get_info(&self) -> (Size2D<i32>, u32, GLLimits, GLFormats) {
|
||||||
match *self {
|
match *self {
|
||||||
GLContextWrapper::Native(ref ctx) => {
|
GLContextWrapper::Native(ref ctx) => {
|
||||||
|
|
|
@ -239,6 +239,12 @@ impl WebGLThread {
|
||||||
let result = self.create_webgl_context(version, size, attributes);
|
let result = self.create_webgl_context(version, size, attributes);
|
||||||
result_sender
|
result_sender
|
||||||
.send(result.map(|(id, limits, share_mode, framebuffer_format)| {
|
.send(result.map(|(id, limits, share_mode, framebuffer_format)| {
|
||||||
|
let image_key = self
|
||||||
|
.cached_context_info
|
||||||
|
.get_mut(&id)
|
||||||
|
.expect("Where's the cached context info?")
|
||||||
|
.image_key;
|
||||||
|
|
||||||
let data = Self::make_current_if_needed(
|
let data = Self::make_current_if_needed(
|
||||||
id,
|
id,
|
||||||
&self.contexts,
|
&self.contexts,
|
||||||
|
@ -277,6 +283,7 @@ impl WebGLThread {
|
||||||
glsl_version,
|
glsl_version,
|
||||||
api_type,
|
api_type,
|
||||||
framebuffer_format,
|
framebuffer_format,
|
||||||
|
image_key,
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -299,12 +306,12 @@ impl WebGLThread {
|
||||||
WebGLMsg::Unlock(ctx_id) => {
|
WebGLMsg::Unlock(ctx_id) => {
|
||||||
self.handle_unlock(ctx_id);
|
self.handle_unlock(ctx_id);
|
||||||
},
|
},
|
||||||
WebGLMsg::UpdateWebRenderImage(ctx_id, sender) => {
|
|
||||||
self.handle_update_wr_image(ctx_id, sender);
|
|
||||||
},
|
|
||||||
WebGLMsg::DOMToTextureCommand(command) => {
|
WebGLMsg::DOMToTextureCommand(command) => {
|
||||||
self.handle_dom_to_texture(command);
|
self.handle_dom_to_texture(command);
|
||||||
},
|
},
|
||||||
|
WebGLMsg::SwapBuffers(context_ids, sender) => {
|
||||||
|
self.handle_swap_buffers(context_ids, sender);
|
||||||
|
},
|
||||||
WebGLMsg::Exit => {
|
WebGLMsg::Exit => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -326,6 +333,11 @@ impl WebGLThread {
|
||||||
&mut self.bound_context_id,
|
&mut self.bound_context_id,
|
||||||
);
|
);
|
||||||
if let Some(data) = data {
|
if let Some(data) = data {
|
||||||
|
let info = self.cached_context_info.get_mut(&context_id).unwrap();
|
||||||
|
if info.clear_required {
|
||||||
|
info.clear_required = false;
|
||||||
|
Self::clear_drawing_buffer(data);
|
||||||
|
}
|
||||||
data.ctx.apply_command(
|
data.ctx.apply_command(
|
||||||
command,
|
command,
|
||||||
data.use_apple_vertex_arrays,
|
data.use_apple_vertex_arrays,
|
||||||
|
@ -400,32 +412,36 @@ impl WebGLThread {
|
||||||
data.ctx.gl().delete_sync(gl_sync);
|
data.ctx.gl().delete_sync(gl_sync);
|
||||||
debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR);
|
debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clear_drawing_buffer(context_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_drawing_buffer(&mut self, context_id: WebGLContextId) {
|
#[allow(unsafe_code)]
|
||||||
let info = self.cached_context_info.get_mut(&context_id).unwrap();
|
fn clear_drawing_buffer(data: &mut GLContextData) {
|
||||||
if info.preserve_drawing_buffer {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = Self::make_current_if_needed(
|
|
||||||
context_id,
|
|
||||||
&self.contexts,
|
|
||||||
&mut self.bound_context_id,
|
|
||||||
)
|
|
||||||
.expect("WebGLContext not found when clearing drawing buffer");
|
|
||||||
trace!("clearing GL framebuffer");
|
trace!("clearing GL framebuffer");
|
||||||
|
|
||||||
|
// Ensure we're clearing the default framebuffer.
|
||||||
|
let mut fb = [0];
|
||||||
|
unsafe {
|
||||||
|
data.ctx
|
||||||
|
.gl()
|
||||||
|
.get_integer_v(gl::FRAMEBUFFER_BINDING, &mut fb);
|
||||||
|
}
|
||||||
|
data.ctx
|
||||||
|
.gl()
|
||||||
|
.bind_framebuffer(gl::FRAMEBUFFER, data.ctx.framebuffer());
|
||||||
|
|
||||||
data.ctx.gl().clear_color(0., 0., 0., 0.);
|
data.ctx.gl().clear_color(0., 0., 0., 0.);
|
||||||
data.ctx.gl().clear_depth(1.0);
|
data.ctx.gl().clear_depth(1.0);
|
||||||
data.ctx.gl().clear_stencil(0);
|
data.ctx.gl().clear_stencil(0);
|
||||||
data.ctx.gl().clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
data.ctx
|
||||||
|
.gl()
|
||||||
|
.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
let (r, g, b, a) = data.state.clear_color;
|
let (r, g, b, a) = data.state.clear_color;
|
||||||
data.ctx.gl().clear_color(r, g, b, a);
|
data.ctx.gl().clear_color(r, g, b, a);
|
||||||
data.ctx.gl().clear_depth(data.state.depth_clear_value);
|
data.ctx.gl().clear_depth(data.state.depth_clear_value);
|
||||||
data.ctx.gl().clear_stencil(data.state.stencil_clear_value);
|
data.ctx.gl().clear_stencil(data.state.stencil_clear_value);
|
||||||
|
|
||||||
|
data.ctx.gl().bind_framebuffer(gl::FRAMEBUFFER, fb[0] as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new WebGLContext
|
/// Creates a new WebGLContext
|
||||||
|
@ -475,17 +491,33 @@ impl WebGLThread {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let image_key = match share_mode {
|
||||||
|
WebGLContextShareMode::Readback => Self::create_wr_readback_image(
|
||||||
|
&self.webrender_api,
|
||||||
|
size,
|
||||||
|
attributes.alpha,
|
||||||
|
vec![0; 4 * size.width as usize * size.height as usize],
|
||||||
|
),
|
||||||
|
WebGLContextShareMode::SharedTexture => Self::create_wr_external_image(
|
||||||
|
&self.webrender_api,
|
||||||
|
size.to_i32(),
|
||||||
|
attributes.alpha,
|
||||||
|
id,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
self.cached_context_info.insert(
|
self.cached_context_info.insert(
|
||||||
id,
|
id,
|
||||||
WebGLContextInfo {
|
WebGLContextInfo {
|
||||||
texture_id,
|
texture_id,
|
||||||
size,
|
size,
|
||||||
alpha: attributes.alpha,
|
alpha: attributes.alpha,
|
||||||
image_key: None,
|
image_key: image_key,
|
||||||
share_mode,
|
share_mode,
|
||||||
gl_sync: None,
|
gl_sync: None,
|
||||||
render_state: ContextRenderState::Unlocked,
|
render_state: ContextRenderState::Unlocked,
|
||||||
preserve_drawing_buffer,
|
preserve_drawing_buffer,
|
||||||
|
clear_required: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -527,7 +559,7 @@ impl WebGLThread {
|
||||||
// Readback mode already updates the image every frame to send the raw pixels.
|
// Readback mode already updates the image every frame to send the raw pixels.
|
||||||
// See `handle_update_wr_image`.
|
// See `handle_update_wr_image`.
|
||||||
match (info.image_key, info.share_mode) {
|
match (info.image_key, info.share_mode) {
|
||||||
(Some(image_key), WebGLContextShareMode::SharedTexture) => {
|
(image_key, WebGLContextShareMode::SharedTexture) => {
|
||||||
Self::update_wr_external_image(
|
Self::update_wr_external_image(
|
||||||
&self.webrender_api,
|
&self.webrender_api,
|
||||||
info.size,
|
info.size,
|
||||||
|
@ -553,9 +585,7 @@ impl WebGLThread {
|
||||||
if let Some(info) = self.cached_context_info.remove(&context_id) {
|
if let Some(info) = self.cached_context_info.remove(&context_id) {
|
||||||
let mut txn = webrender_api::Transaction::new();
|
let mut txn = webrender_api::Transaction::new();
|
||||||
|
|
||||||
if let Some(image_key) = info.image_key {
|
txn.delete_image(info.image_key);
|
||||||
txn.delete_image(image_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.webrender_api.update_resources(txn.resource_updates)
|
self.webrender_api.update_resources(txn.resource_updates)
|
||||||
}
|
}
|
||||||
|
@ -571,68 +601,33 @@ impl WebGLThread {
|
||||||
self.bound_context_id = None;
|
self.bound_context_id = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the creation/update of webrender_api::ImageKeys for a specific WebGLContext.
|
fn handle_swap_buffers(
|
||||||
/// This method is invoked from a UpdateWebRenderImage message sent by the layout thread.
|
|
||||||
/// If SharedTexture is used the UpdateWebRenderImage message is sent only after a WebGLContext creation.
|
|
||||||
/// If Readback is used UpdateWebRenderImage message is sent always on each layout iteration in order to
|
|
||||||
/// submit the updated raw pixels.
|
|
||||||
fn handle_update_wr_image(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
context_id: WebGLContextId,
|
context_ids: Vec<WebGLContextId>,
|
||||||
sender: WebGLSender<webrender_api::ImageKey>,
|
completed_sender: WebGLSender<()>,
|
||||||
) {
|
) {
|
||||||
let info = self.cached_context_info.get_mut(&context_id).unwrap();
|
for context_id in context_ids {
|
||||||
let webrender_api = &self.webrender_api;
|
let info = self.cached_context_info.get_mut(&context_id).unwrap();
|
||||||
|
let webrender_api = &self.webrender_api;
|
||||||
|
|
||||||
let image_key = match info.share_mode {
|
if let WebGLContextShareMode::Readback = info.share_mode {
|
||||||
WebGLContextShareMode::SharedTexture => {
|
|
||||||
let size = info.size;
|
|
||||||
let alpha = info.alpha;
|
|
||||||
// Reuse existing ImageKey or generate a new one.
|
|
||||||
// When using a shared texture ImageKeys are only generated after a WebGLContext creation.
|
|
||||||
*info.image_key.get_or_insert_with(|| {
|
|
||||||
Self::create_wr_external_image(webrender_api, size, alpha, context_id)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
WebGLContextShareMode::Readback => {
|
|
||||||
let pixels = Self::raw_pixels(&self.contexts[&context_id].ctx, info.size);
|
let pixels = Self::raw_pixels(&self.contexts[&context_id].ctx, info.size);
|
||||||
match info.image_key.clone() {
|
// WR Images must be updated every frame in readback mode to send the new raw pixels.
|
||||||
Some(image_key) => {
|
Self::update_wr_readback_image(
|
||||||
// ImageKey was already created, but WR Images must
|
webrender_api,
|
||||||
// be updated every frame in readback mode to send the new raw pixels.
|
info.size,
|
||||||
Self::update_wr_readback_image(
|
info.alpha,
|
||||||
webrender_api,
|
info.image_key,
|
||||||
info.size,
|
pixels,
|
||||||
info.alpha,
|
);
|
||||||
image_key,
|
}
|
||||||
pixels,
|
|
||||||
);
|
|
||||||
|
|
||||||
image_key
|
if !info.preserve_drawing_buffer {
|
||||||
},
|
info.clear_required = true;
|
||||||
None => {
|
}
|
||||||
// Generate a new ImageKey for Readback mode.
|
|
||||||
let image_key = Self::create_wr_readback_image(
|
|
||||||
webrender_api,
|
|
||||||
info.size,
|
|
||||||
info.alpha,
|
|
||||||
pixels,
|
|
||||||
);
|
|
||||||
info.image_key = Some(image_key);
|
|
||||||
image_key
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send the ImageKey to the Layout thread.
|
|
||||||
sender.send(image_key).unwrap();
|
|
||||||
|
|
||||||
if let WebGLContextShareMode::Readback = info.share_mode {
|
|
||||||
// Ensure that the drawing buffer is cleared when webrender isn't involved
|
|
||||||
// in drawing the GL texture.
|
|
||||||
self.clear_drawing_buffer(context_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = completed_sender.send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_dom_to_texture(&mut self, command: DOMToTextureCommand) {
|
fn handle_dom_to_texture(&mut self, command: DOMToTextureCommand) {
|
||||||
|
@ -911,7 +906,7 @@ struct WebGLContextInfo {
|
||||||
/// True if the WebGLContext uses an alpha channel.
|
/// True if the WebGLContext uses an alpha channel.
|
||||||
alpha: bool,
|
alpha: bool,
|
||||||
/// Currently used WebRender image key.
|
/// Currently used WebRender image key.
|
||||||
image_key: Option<webrender_api::ImageKey>,
|
image_key: webrender_api::ImageKey,
|
||||||
/// The sharing mode used to send the image to WebRender.
|
/// The sharing mode used to send the image to WebRender.
|
||||||
share_mode: WebGLContextShareMode,
|
share_mode: WebGLContextShareMode,
|
||||||
/// GLSync Object used for a correct synchronization with Webrender external image callbacks.
|
/// GLSync Object used for a correct synchronization with Webrender external image callbacks.
|
||||||
|
@ -920,6 +915,8 @@ struct WebGLContextInfo {
|
||||||
render_state: ContextRenderState,
|
render_state: ContextRenderState,
|
||||||
/// Should the drawing buffer be preserved between frames?
|
/// Should the drawing buffer be preserved between frames?
|
||||||
preserve_drawing_buffer: bool,
|
preserve_drawing_buffer: bool,
|
||||||
|
/// Does the canvas need to be cleared before executing further WebGL commands?
|
||||||
|
clear_required: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data about the linked DOM<->WebGLTexture elements.
|
/// Data about the linked DOM<->WebGLTexture elements.
|
||||||
|
|
|
@ -64,10 +64,10 @@ pub enum WebGLMsg {
|
||||||
/// The WR unlocks a context when it finished reading the shared texture contents.
|
/// The WR unlocks a context when it finished reading the shared texture contents.
|
||||||
/// Unlock messages are always sent after a Lock message.
|
/// Unlock messages are always sent after a Lock message.
|
||||||
Unlock(WebGLContextId),
|
Unlock(WebGLContextId),
|
||||||
/// Creates or updates the image keys required for WebRender.
|
|
||||||
UpdateWebRenderImage(WebGLContextId, WebGLSender<ImageKey>),
|
|
||||||
/// Commands used for the DOMToTexture feature.
|
/// Commands used for the DOMToTexture feature.
|
||||||
DOMToTextureCommand(DOMToTextureCommand),
|
DOMToTextureCommand(DOMToTextureCommand),
|
||||||
|
/// Performs a buffer swap.
|
||||||
|
SwapBuffers(Vec<WebGLContextId>, WebGLSender<()>),
|
||||||
/// Frees all resources and closes the thread.
|
/// Frees all resources and closes the thread.
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,8 @@ pub struct WebGLCreateContextResult {
|
||||||
pub api_type: GlType,
|
pub api_type: GlType,
|
||||||
/// The format for creating new offscreen framebuffers for this context.
|
/// The format for creating new offscreen framebuffers for this context.
|
||||||
pub framebuffer_format: GLFormats,
|
pub framebuffer_format: GLFormats,
|
||||||
|
/// The WebRender image key.
|
||||||
|
pub image_key: ImageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||||
|
@ -174,12 +176,6 @@ impl WebGLMsgSender {
|
||||||
self.sender.send(WebGLMsg::RemoveContext(self.ctx_id))
|
self.sender.send(WebGLMsg::RemoveContext(self.ctx_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn send_update_wr_image(&self, sender: WebGLSender<ImageKey>) -> WebGLSendResult {
|
|
||||||
self.sender
|
|
||||||
.send(WebGLMsg::UpdateWebRenderImage(self.ctx_id, sender))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult {
|
pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult {
|
||||||
self.sender.send(WebGLMsg::DOMToTextureCommand(command))
|
self.sender.send(WebGLMsg::DOMToTextureCommand(command))
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle,
|
||||||
use canvas_traits::webgl::WebGLVertexArrayId;
|
use canvas_traits::webgl::WebGLVertexArrayId;
|
||||||
use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat};
|
use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat};
|
||||||
use canvas_traits::webgl::{GLFormats, GLLimits, WebGLQueryId, WebGLSamplerId};
|
use canvas_traits::webgl::{GLFormats, GLLimits, WebGLQueryId, WebGLSamplerId};
|
||||||
use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextShareMode, WebGLError};
|
use canvas_traits::webgl::{
|
||||||
|
WebGLBufferId, WebGLChan, WebGLContextId, WebGLContextShareMode, WebGLError,
|
||||||
|
};
|
||||||
use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId};
|
use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId};
|
||||||
use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender};
|
use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender};
|
||||||
use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion};
|
use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion};
|
||||||
|
@ -519,6 +521,7 @@ unsafe_no_jsmanaged_fields!(Rect<f32>);
|
||||||
unsafe_no_jsmanaged_fields!(CascadeData);
|
unsafe_no_jsmanaged_fields!(CascadeData);
|
||||||
unsafe_no_jsmanaged_fields!(WindowGLContext);
|
unsafe_no_jsmanaged_fields!(WindowGLContext);
|
||||||
unsafe_no_jsmanaged_fields!(Frame);
|
unsafe_no_jsmanaged_fields!(Frame);
|
||||||
|
unsafe_no_jsmanaged_fields!(WebGLContextId);
|
||||||
|
|
||||||
unsafe impl<'a> JSTraceable for &'a str {
|
unsafe impl<'a> JSTraceable for &'a str {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -109,6 +109,7 @@ use crate::stylesheet_set::StylesheetSetRef;
|
||||||
use crate::task::TaskBox;
|
use crate::task::TaskBox;
|
||||||
use crate::task_source::{TaskSource, TaskSourceName};
|
use crate::task_source::{TaskSource, TaskSourceName};
|
||||||
use crate::timers::OneshotTimerCallback;
|
use crate::timers::OneshotTimerCallback;
|
||||||
|
use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg};
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
@ -395,6 +396,8 @@ pub struct Document {
|
||||||
/// where `id` needs to match any of the registered ShadowRoots
|
/// where `id` needs to match any of the registered ShadowRoots
|
||||||
/// hosting the media controls UI.
|
/// hosting the media controls UI.
|
||||||
media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
|
media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
|
||||||
|
/// List of all WebGL context IDs that need flushing.
|
||||||
|
dirty_webgl_contexts: DomRefCell<HashSet<WebGLContextId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(JSTraceable, MallocSizeOf)]
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
@ -2490,6 +2493,24 @@ impl Document {
|
||||||
debug_assert!(false, "Trying to unregister unknown media controls");
|
debug_assert!(false, "Trying to unregister unknown media controls");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_dirty_canvas(&self, context_id: WebGLContextId) {
|
||||||
|
self.dirty_webgl_contexts.borrow_mut().insert(context_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush_dirty_canvases(&self) {
|
||||||
|
let dirty_context_ids: Vec<_> = self.dirty_webgl_contexts.borrow_mut().drain().collect();
|
||||||
|
if dirty_context_ids.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (sender, receiver) = webgl::webgl_channel().unwrap();
|
||||||
|
self.window
|
||||||
|
.webgl_chan()
|
||||||
|
.expect("Where's the WebGL channel?")
|
||||||
|
.send(WebGLMsg::SwapBuffers(dirty_context_ids, sender))
|
||||||
|
.unwrap();
|
||||||
|
receiver.recv().unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MallocSizeOf, PartialEq)]
|
#[derive(MallocSizeOf, PartialEq)]
|
||||||
|
@ -2784,6 +2805,7 @@ impl Document {
|
||||||
shadow_roots: DomRefCell::new(HashSet::new()),
|
shadow_roots: DomRefCell::new(HashSet::new()),
|
||||||
shadow_roots_styles_changed: Cell::new(false),
|
shadow_roots_styles_changed: Cell::new(false),
|
||||||
media_controls: DomRefCell::new(HashMap::new()),
|
media_controls: DomRefCell::new(HashMap::new()),
|
||||||
|
dirty_webgl_contexts: DomRefCell::new(HashSet::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,6 @@ use std::cell::Cell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use webrender_api::ImageKey;
|
|
||||||
|
|
||||||
// From the GLES 2.0.25 spec, page 85:
|
// From the GLES 2.0.25 spec, page 85:
|
||||||
//
|
//
|
||||||
|
@ -130,7 +129,7 @@ pub struct WebGLRenderingContext {
|
||||||
#[ignore_malloc_size_of = "Channels are hard"]
|
#[ignore_malloc_size_of = "Channels are hard"]
|
||||||
webgl_sender: WebGLMessageSender,
|
webgl_sender: WebGLMessageSender,
|
||||||
#[ignore_malloc_size_of = "Defined in webrender"]
|
#[ignore_malloc_size_of = "Defined in webrender"]
|
||||||
webrender_image: Cell<Option<webrender_api::ImageKey>>,
|
webrender_image: webrender_api::ImageKey,
|
||||||
share_mode: WebGLContextShareMode,
|
share_mode: WebGLContextShareMode,
|
||||||
webgl_version: WebGLVersion,
|
webgl_version: WebGLVersion,
|
||||||
glsl_version: WebGLSLVersion,
|
glsl_version: WebGLSLVersion,
|
||||||
|
@ -195,7 +194,7 @@ impl WebGLRenderingContext {
|
||||||
ctx_data.sender,
|
ctx_data.sender,
|
||||||
window.get_event_loop_waker(),
|
window.get_event_loop_waker(),
|
||||||
),
|
),
|
||||||
webrender_image: Cell::new(None),
|
webrender_image: ctx_data.image_key,
|
||||||
share_mode: ctx_data.share_mode,
|
share_mode: ctx_data.share_mode,
|
||||||
webgl_version,
|
webgl_version,
|
||||||
glsl_version: ctx_data.glsl_version,
|
glsl_version: ctx_data.glsl_version,
|
||||||
|
@ -453,13 +452,17 @@ impl WebGLRenderingContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_as_dirty(&self) {
|
fn mark_as_dirty(&self) {
|
||||||
// If we don't have a bound framebuffer, then don't mark the canvas
|
// If we have a bound framebuffer, then don't mark the canvas as dirty.
|
||||||
// as dirty.
|
if self.bound_framebuffer.get().is_some() {
|
||||||
if self.bound_framebuffer.get().is_none() {
|
return;
|
||||||
self.canvas
|
|
||||||
.upcast::<Node>()
|
|
||||||
.dirty(NodeDamage::OtherNodeDamage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.canvas
|
||||||
|
.upcast::<Node>()
|
||||||
|
.dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
|
||||||
|
let document = document_from_node(&*self.canvas);
|
||||||
|
document.add_dirty_canvas(self.context_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
|
fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
|
||||||
|
@ -808,26 +811,7 @@ impl WebGLRenderingContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_handle(&self) -> webrender_api::ImageKey {
|
pub fn layout_handle(&self) -> webrender_api::ImageKey {
|
||||||
match self.share_mode {
|
self.webrender_image
|
||||||
WebGLContextShareMode::SharedTexture => {
|
|
||||||
// WR using ExternalTexture requires a single update message.
|
|
||||||
self.webrender_image.get().unwrap_or_else(|| {
|
|
||||||
let (sender, receiver) = webgl_channel().unwrap();
|
|
||||||
self.webgl_sender.send_update_wr_image(sender).unwrap();
|
|
||||||
let image_key = receiver.recv().unwrap();
|
|
||||||
self.webrender_image.set(Some(image_key));
|
|
||||||
|
|
||||||
image_key
|
|
||||||
})
|
|
||||||
},
|
|
||||||
WebGLContextShareMode::Readback => {
|
|
||||||
// WR using Readback requires to update WR image every frame
|
|
||||||
// in order to send the new raw pixels.
|
|
||||||
let (sender, receiver) = webgl_channel().unwrap();
|
|
||||||
self.webgl_sender.send_update_wr_image(sender).unwrap();
|
|
||||||
receiver.recv().unwrap()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
||||||
|
@ -4438,10 +4422,6 @@ impl WebGLMessageSender {
|
||||||
self.wake_after_send(|| self.sender.send_remove())
|
self.wake_after_send(|| self.sender.send_remove())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_update_wr_image(&self, sender: WebGLSender<ImageKey>) -> WebGLSendResult {
|
|
||||||
self.wake_after_send(|| self.sender.send_update_wr_image(sender))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult {
|
pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult {
|
||||||
self.wake_after_send(|| self.sender.send_dom_to_texture(command))
|
self.wake_after_send(|| self.sender.send_dom_to_texture(command))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1520,6 +1520,13 @@ impl Window {
|
||||||
|
|
||||||
let stylesheets_changed = document.flush_stylesheets_for_reflow();
|
let stylesheets_changed = document.flush_stylesheets_for_reflow();
|
||||||
|
|
||||||
|
// If this reflow is for display, ensure webgl canvases are composited with
|
||||||
|
// up-to-date contents.
|
||||||
|
match reflow_goal {
|
||||||
|
ReflowGoal::Full => document.flush_dirty_canvases(),
|
||||||
|
ReflowGoal::TickAnimations | ReflowGoal::LayoutQuery(..) => {},
|
||||||
|
}
|
||||||
|
|
||||||
// Send new document and relevant styles to layout.
|
// Send new document and relevant styles to layout.
|
||||||
let needs_display = reflow_goal.needs_display();
|
let needs_display = reflow_goal.needs_display();
|
||||||
let reflow = ScriptReflow {
|
let reflow = ScriptReflow {
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[context-creation.html]
|
|
||||||
expected: TIMEOUT
|
|
Loading…
Add table
Add a link
Reference in a new issue