Revert "Auto merge of #18114 - emilio:revert-webgl-refactor, r=nox"

This reverts commit 4d10d39e8f, reversing
changes made to ee94e2b7c0.
This commit is contained in:
Anthony Ramine 2017-08-16 23:23:18 +02:00
parent 4d10d39e8f
commit 676f2c8acf
54 changed files with 3154 additions and 1426 deletions

View file

@ -12,6 +12,7 @@ path = "lib.rs"
[dependencies]
azure = {git = "https://github.com/servo/rust-azure"}
canvas_traits = {path = "../canvas_traits"}
compositing = {path = "../compositing"}
cssparser = "0.19"
euclid = "0.15"
gleam = "0.4"
@ -19,5 +20,5 @@ ipc-channel = "0.8"
log = "0.3.5"
num-traits = "0.1.32"
offscreen_gl_context = { version = "0.11", features = ["serde"] }
servo_config = {path = "../config"}
webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}

View file

@ -8,7 +8,7 @@ use azure::azure_hl::{BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptio
use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, PathBuilder};
use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern};
use azure::azure_hl::SurfacePattern;
use canvas_traits::*;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D};
use ipc_channel::ipc::{self, IpcSender};
@ -193,12 +193,8 @@ impl<'a> CanvasPaintThread<'a> {
Canvas2dMsg::SetShadowColor(ref color) => painter.set_shadow_color(color.to_azure_style()),
}
},
CanvasMsg::Common(message) => {
match message {
CanvasCommonMsg::Close => break,
CanvasCommonMsg::Recreate(size) => painter.recreate(size),
}
},
CanvasMsg::Close => break,
CanvasMsg::Recreate(size) => painter.recreate(size),
CanvasMsg::FromScript(message) => {
match message {
FromScriptMsg::SendPixels(chan) => {
@ -213,8 +209,6 @@ impl<'a> CanvasPaintThread<'a> {
}
}
}
CanvasMsg::WebGL(_) => panic!("Wrong WebGL message sent to Canvas2D thread"),
CanvasMsg::WebVR(_) => panic!("Wrong WebVR message sent to Canvas2D thread"),
}
}
}).expect("Thread spawning failed");
@ -571,7 +565,7 @@ impl<'a> CanvasPaintThread<'a> {
})
}
fn send_data(&mut self, chan: IpcSender<CanvasData>) {
fn send_data(&mut self, chan: IpcSender<CanvasImageData>) {
self.drawtarget.snapshot().get_data_surface().with_data(|element| {
let size = self.drawtarget.get_size();
@ -614,7 +608,7 @@ impl<'a> CanvasPaintThread<'a> {
let data = CanvasImageData {
image_key: self.image_key.unwrap(),
};
chan.send(CanvasData::Image(data)).unwrap();
chan.send(data).unwrap();
})
}

View file

@ -0,0 +1,203 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use canvas_traits::webgl::WebGLCommand;
use compositing::compositor_thread::{CompositorProxy, self};
use euclid::Size2D;
use gleam::gl;
use offscreen_gl_context::{ColorAttachmentType, GLContext, GLContextAttributes, GLContextDispatcher, GLLimits};
use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle, NativeGLContextMethods};
use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
use std::sync::{Arc, Mutex};
use super::webgl_thread::WebGLImpl;
/// The GLContextFactory is used to create shared GL contexts with the main thread GL context.
/// Currently, shared textures are used to render WebGL textures into the WR compositor.
/// In order to create a shared context, the GLContextFactory stores the handle of the main GL context.
pub enum GLContextFactory {
Native(NativeGLContextHandle, Option<MainThreadDispatcher>),
OSMesa(OSMesaContextHandle),
}
impl GLContextFactory {
/// Creates a new GLContextFactory that uses the currently bound GL context to create shared contexts.
pub fn current_native_handle(proxy: &CompositorProxy) -> Option<GLContextFactory> {
NativeGLContext::current_handle().map(|handle| {
if cfg!(target_os = "windows") {
// Used to dispatch functions from the GLContext thread to the main thread's event loop.
// Required to allow WGL GLContext sharing in Windows.
GLContextFactory::Native(handle, Some(MainThreadDispatcher::new(proxy.clone_compositor_proxy())))
} else {
GLContextFactory::Native(handle, None)
}
})
}
/// Creates a new GLContextFactory that uses the currently bound OSMesa context to create shared contexts.
pub fn current_osmesa_handle() -> Option<GLContextFactory> {
OSMesaContext::current_handle().map(GLContextFactory::OSMesa)
}
/// Creates a new shared GLContext with the main GLContext
pub fn new_shared_context(&self,
size: Size2D<i32>,
attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> {
match *self {
GLContextFactory::Native(ref handle, ref dispatcher) => {
let dispatcher = dispatcher.as_ref().map(|d| Box::new(d.clone()) as Box<_>);
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
dispatcher);
ctx.map(GLContextWrapper::Native)
}
GLContextFactory::OSMesa(ref handle) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
None);
ctx.map(GLContextWrapper::OSMesa)
}
}
}
/// Creates a new non-shared GLContext
pub fn new_context(&self,
size: Size2D<i32>,
attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> {
match *self {
GLContextFactory::Native(..) => {
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None,
None);
ctx.map(GLContextWrapper::Native)
}
GLContextFactory::OSMesa(_) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None,
None);
ctx.map(GLContextWrapper::OSMesa)
}
}
}
}
/// GLContextWrapper used to abstract NativeGLContext and OSMesaContext types
pub enum GLContextWrapper {
Native(GLContext<NativeGLContext>),
OSMesa(GLContext<OSMesaContext>),
}
impl GLContextWrapper {
pub fn make_current(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.make_current().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.make_current().unwrap();
}
}
}
pub fn unbind(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.unbind().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.unbind().unwrap();
}
}
}
pub fn apply_command(&self, cmd: WebGLCommand) {
match *self {
GLContextWrapper::Native(ref ctx) => {
WebGLImpl::apply(ctx, cmd);
}
GLContextWrapper::OSMesa(ref ctx) => {
WebGLImpl::apply(ctx, cmd);
}
}
}
pub fn gl(&self) -> &gl::Gl {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.gl()
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.gl()
}
}
}
pub fn get_info(&self) -> (Size2D<i32>, u32, GLLimits) {
match *self {
GLContextWrapper::Native(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};
let limits = ctx.borrow_limits().clone();
(real_size, texture_id, limits)
}
GLContextWrapper::OSMesa(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};
let limits = ctx.borrow_limits().clone();
(real_size, texture_id, limits)
}
}
}
pub fn resize(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
match *self {
GLContextWrapper::Native(ref mut ctx) => {
ctx.resize(size)
}
GLContextWrapper::OSMesa(ref mut ctx) => {
ctx.resize(size)
}
}
}
}
/// Implements GLContextDispatcher to dispatch functions from GLContext threads to the main thread's event loop.
/// It's used in Windows to allow WGL GLContext sharing.
#[derive(Clone)]
pub struct MainThreadDispatcher {
compositor_proxy: Arc<Mutex<CompositorProxy>>
}
impl MainThreadDispatcher {
fn new(proxy: CompositorProxy) -> Self {
Self {
compositor_proxy: Arc::new(Mutex::new(proxy)),
}
}
}
impl GLContextDispatcher for MainThreadDispatcher {
fn dispatch(&self, f: Box<Fn() + Send>) {
self.compositor_proxy.lock().unwrap().send(compositor_thread::Msg::Dispatch(f));
}
}

View file

@ -6,16 +6,18 @@
extern crate azure;
extern crate canvas_traits;
extern crate compositing;
extern crate cssparser;
extern crate euclid;
extern crate gleam;
extern crate ipc_channel;
#[macro_use]
extern crate log;
#[macro_use] extern crate log;
extern crate num_traits;
extern crate offscreen_gl_context;
extern crate servo_config;
extern crate webrender;
extern crate webrender_api;
pub mod canvas_paint_thread;
pub mod webgl_paint_thread;
pub mod gl_context;
mod webgl_mode;
pub mod webgl_thread;

View file

@ -0,0 +1,95 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use ::gl_context::GLContextFactory;
use ::webgl_thread::{WebGLExternalImageApi, WebGLExternalImageHandler, WebGLThreadObserver, WebGLThread};
use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver};
use canvas_traits::webgl::{WebGLSender, WebVRCommand, WebVRRenderHandler};
use canvas_traits::webgl::webgl_channel;
use euclid::Size2D;
use std::marker::PhantomData;
use webrender;
use webrender_api;
/// WebGL Threading API entry point that lives in the constellation.
pub struct WebGLThreads(WebGLSender<WebGLMsg>);
impl WebGLThreads {
/// Creates a new WebGLThreads object
pub fn new(gl_factory: GLContextFactory,
webrender_api_sender: webrender_api::RenderApiSender,
webvr_compositor: Option<Box<WebVRRenderHandler>>)
-> (WebGLThreads, Box<webrender::ExternalImageHandler>) {
// This implementation creates a single `WebGLThread` for all the pipelines.
let channel = WebGLThread::start(gl_factory,
webrender_api_sender,
webvr_compositor.map(|c| WebVRRenderWrapper(c)),
PhantomData);
let external = WebGLExternalImageHandler::new(WebGLExternalImages::new(channel.clone()));
(WebGLThreads(channel), Box::new(external))
}
/// Gets the WebGLThread handle for each script pipeline.
pub fn pipeline(&self) -> WebGLPipeline {
// This mode creates a single thread, so the existing WebGLChan is just cloned.
WebGLPipeline(WebGLChan(self.0.clone()))
}
/// Sends a exit message to close the WebGLThreads and release all WebGLContexts.
pub fn exit(&self) -> Result<(), &'static str> {
self.0.send(WebGLMsg::Exit).map_err(|_| "Failed to send Exit message")
}
}
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
struct WebGLExternalImages {
webgl_channel: WebGLSender<WebGLMsg>,
// Used to avoid creating a new channel on each received WebRender request.
lock_channel: (WebGLSender<(u32, Size2D<i32>)>, WebGLReceiver<(u32, Size2D<i32>)>),
}
impl WebGLExternalImages {
fn new(channel: WebGLSender<WebGLMsg>) -> Self {
Self {
webgl_channel: channel,
lock_channel: webgl_channel().unwrap(),
}
}
}
impl WebGLExternalImageApi for WebGLExternalImages {
fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D<i32>) {
self.webgl_channel.send(WebGLMsg::Lock(ctx_id, self.lock_channel.0.clone())).unwrap();
self.lock_channel.1.recv().unwrap()
}
fn unlock(&mut self, ctx_id: WebGLContextId) {
self.webgl_channel.send(WebGLMsg::Unlock(ctx_id)).unwrap();
}
}
/// Custom observer used in a `WebGLThread`.
impl WebGLThreadObserver for PhantomData<()> {
fn on_context_create(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>) {
debug!("WebGLContext created (ctx_id: {:?} texture_id: {:?} size: {:?}", ctx_id, texture_id, size);
}
fn on_context_resize(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>) {
debug!("WebGLContext resized (ctx_id: {:?} texture_id: {:?} size: {:?}", ctx_id, texture_id, size);
}
fn on_context_delete(&mut self, ctx_id: WebGLContextId) {
debug!("WebGLContext deleted (ctx_id: {:?})", ctx_id);
}
}
/// Wrapper to send WebVR commands used in `WebGLThread`.
struct WebVRRenderWrapper(Box<WebVRRenderHandler>);
impl WebVRRenderHandler for WebVRRenderWrapper {
fn handle(&mut self, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>) {
self.0.handle(command, texture);
}
}

View file

@ -0,0 +1,6 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
mod inprocess;
pub use self::inprocess::WebGLThreads;

View file

@ -1,379 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use canvas_traits::{CanvasCommonMsg, CanvasData, CanvasMsg, CanvasImageData};
use canvas_traits::{FromLayoutMsg, FromScriptMsg, byte_swap};
use euclid::Size2D;
use gleam::gl;
use ipc_channel::ipc::{self, IpcSender};
use offscreen_gl_context::{ColorAttachmentType, GLContext, GLLimits};
use offscreen_gl_context::{GLContextAttributes, NativeGLContext, OSMesaContext};
use servo_config::opts;
use std::borrow::ToOwned;
use std::mem;
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::thread;
use webrender_api;
enum GLContextWrapper {
Native(GLContext<NativeGLContext>),
OSMesa(GLContext<OSMesaContext>),
}
impl GLContextWrapper {
fn new(size: Size2D<i32>,
attributes: GLContextAttributes,
gl_type: gl::GlType) -> Result<GLContextWrapper, &'static str> {
if opts::get().should_use_osmesa() {
let ctx = GLContext::<OSMesaContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl_type,
None);
ctx.map(GLContextWrapper::OSMesa)
} else {
let ctx = GLContext::<NativeGLContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl_type,
None);
ctx.map(GLContextWrapper::Native)
}
}
pub fn get_limits(&self) -> GLLimits {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.borrow_limits().clone()
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.borrow_limits().clone()
}
}
}
fn resize(&mut self, size: Size2D<i32>) -> Result<Size2D<i32>, &'static str> {
match *self {
GLContextWrapper::Native(ref mut ctx) => {
ctx.resize(size)?;
Ok(ctx.borrow_draw_buffer().unwrap().size())
}
GLContextWrapper::OSMesa(ref mut ctx) => {
ctx.resize(size)?;
Ok(ctx.borrow_draw_buffer().unwrap().size())
}
}
}
fn gl(&self) -> &gl::Gl {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.gl()
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.gl()
}
}
}
pub fn make_current(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.make_current().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.make_current().unwrap();
}
}
}
pub fn apply_command(&self, cmd: webrender_api::WebGLCommand) {
match *self {
GLContextWrapper::Native(ref ctx) => {
cmd.apply(ctx);
}
GLContextWrapper::OSMesa(ref ctx) => {
cmd.apply(ctx);
}
}
}
}
enum WebGLPaintTaskData {
WebRender(webrender_api::RenderApi, webrender_api::WebGLContextId),
Readback {
context: GLContextWrapper,
webrender_api: webrender_api::RenderApi,
image_key: Option<webrender_api::ImageKey>,
/// An old webrender image key that can be deleted when the next epoch ends.
old_image_key: Option<webrender_api::ImageKey>,
/// An old webrender image key that can be deleted when the current epoch ends.
very_old_image_key: Option<webrender_api::ImageKey>,
},
}
pub struct WebGLPaintThread {
size: Size2D<i32>,
data: WebGLPaintTaskData,
}
fn create_readback_painter(size: Size2D<i32>,
attrs: GLContextAttributes,
webrender_api: webrender_api::RenderApi,
gl_type: gl::GlType)
-> Result<(WebGLPaintThread, GLLimits), String> {
let context = GLContextWrapper::new(size, attrs, gl_type)?;
let limits = context.get_limits();
let painter = WebGLPaintThread {
size: size,
data: WebGLPaintTaskData::Readback {
context: context,
webrender_api: webrender_api,
image_key: None,
old_image_key: None,
very_old_image_key: None,
},
};
Ok((painter, limits))
}
impl WebGLPaintThread {
fn new(size: Size2D<i32>,
attrs: GLContextAttributes,
webrender_api_sender: webrender_api::RenderApiSender,
gl_type: gl::GlType)
-> Result<(WebGLPaintThread, GLLimits), String> {
let wr_api = webrender_api_sender.create_api();
let device_size = webrender_api::DeviceIntSize::from_untyped(&size);
match wr_api.request_webgl_context(&device_size, attrs) {
Ok((id, limits)) => {
let painter = WebGLPaintThread {
data: WebGLPaintTaskData::WebRender(wr_api, id),
size: size
};
Ok((painter, limits))
},
Err(msg) => {
warn!("Initial context creation failed, falling back to readback: {}", msg);
create_readback_painter(size, attrs, wr_api, gl_type)
}
}
}
fn handle_webgl_message(&self, message: webrender_api::WebGLCommand) {
debug!("WebGL message: {:?}", message);
match self.data {
WebGLPaintTaskData::WebRender(ref api, id) => {
api.send_webgl_command(id, message);
}
WebGLPaintTaskData::Readback { ref context, .. } => {
context.apply_command(message);
}
}
}
fn handle_webvr_message(&self, message: webrender_api::VRCompositorCommand) {
match self.data {
WebGLPaintTaskData::WebRender(ref api, id) => {
api.send_vr_compositor_command(id, message);
}
WebGLPaintTaskData::Readback { .. } => {
error!("Webrender is required for WebVR implementation");
}
}
}
/// Creates a new `WebGLPaintThread` and returns an `IpcSender` to
/// communicate with it.
pub fn start(size: Size2D<i32>,
attrs: GLContextAttributes,
webrender_api_sender: webrender_api::RenderApiSender)
-> Result<(IpcSender<CanvasMsg>, GLLimits), String> {
let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap();
let (result_chan, result_port) = channel();
thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || {
let gl_type = gl::GlType::default();
let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender, gl_type) {
Ok((thread, limits)) => {
result_chan.send(Ok(limits)).unwrap();
thread
},
Err(e) => {
result_chan.send(Err(e)).unwrap();
return
}
};
painter.init();
loop {
match receiver.recv().unwrap() {
CanvasMsg::WebGL(message) => painter.handle_webgl_message(message),
CanvasMsg::Common(message) => {
match message {
CanvasCommonMsg::Close => break,
// TODO(emilio): handle error nicely
CanvasCommonMsg::Recreate(size) => painter.recreate(size).unwrap(),
}
},
CanvasMsg::FromScript(message) => {
match message {
FromScriptMsg::SendPixels(chan) =>{
// Read the comment on
// HTMLCanvasElement::fetch_all_data.
chan.send(None).unwrap();
}
}
}
CanvasMsg::FromLayout(message) => {
match message {
FromLayoutMsg::SendData(chan) =>
painter.send_data(chan),
}
}
CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLThread"),
CanvasMsg::WebVR(message) => painter.handle_webvr_message(message)
}
}
}).expect("Thread spawning failed");
result_port.recv().unwrap().map(|limits| (sender, limits))
}
fn send_data(&mut self, chan: IpcSender<CanvasData>) {
match self.data {
WebGLPaintTaskData::Readback {
ref context,
ref webrender_api,
ref mut image_key,
ref mut old_image_key,
ref mut very_old_image_key,
} => {
let width = self.size.width as usize;
let height = self.size.height as usize;
let mut pixels = context.gl().read_pixels(0, 0,
self.size.width as gl::GLsizei,
self.size.height as gl::GLsizei,
gl::RGBA, gl::UNSIGNED_BYTE);
// flip image vertically (texture is upside down)
let orig_pixels = pixels.clone();
let stride = width * 4;
for y in 0..height {
let dst_start = y * stride;
let src_start = (height - y - 1) * stride;
let src_slice = &orig_pixels[src_start .. src_start + stride];
(&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
}
// rgba -> bgra
byte_swap(&mut pixels);
let descriptor = webrender_api::ImageDescriptor {
width: width as u32,
height: height as u32,
stride: None,
format: webrender_api::ImageFormat::BGRA8,
offset: 0,
is_opaque: false,
};
let data = webrender_api::ImageData::Raw(Arc::new(pixels));
let mut updates = webrender_api::ResourceUpdates::new();
match *image_key {
Some(image_key) => {
updates.update_image(image_key,
descriptor,
data,
None);
}
None => {
*image_key = Some(webrender_api.generate_image_key());
updates.add_image(image_key.unwrap(),
descriptor,
data,
None);
}
}
if let Some(image_key) = mem::replace(very_old_image_key, old_image_key.take()) {
updates.delete_image(image_key);
}
webrender_api.update_resources(updates);
let image_data = CanvasImageData {
image_key: image_key.unwrap(),
};
chan.send(CanvasData::Image(image_data)).unwrap();
}
WebGLPaintTaskData::WebRender(_, id) => {
chan.send(CanvasData::WebGL(id)).unwrap();
}
}
}
#[allow(unsafe_code)]
fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
match self.data {
WebGLPaintTaskData::Readback { ref mut context, ref mut image_key, ref mut old_image_key, .. } => {
if size.width > self.size.width ||
size.height > self.size.height {
self.size = context.resize(size)?;
} else {
self.size = size;
context.gl().scissor(0, 0, size.width, size.height);
}
// Webrender doesn't let images change size, so we clear the webrender image key.
if let Some(image_key) = 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!(old_image_key.is_none());
*old_image_key = Some(image_key);
}
}
WebGLPaintTaskData::WebRender(ref api, id) => {
let device_size = webrender_api::DeviceIntSize::from_untyped(&size);
api.resize_webgl_context(id, &device_size);
}
}
Ok(())
}
fn init(&mut self) {
if let WebGLPaintTaskData::Readback { ref context, .. } = self.data {
context.make_current();
}
}
}
impl Drop for WebGLPaintThread {
fn drop(&mut self) {
if let WebGLPaintTaskData::Readback {
ref mut webrender_api,
image_key,
old_image_key,
very_old_image_key,
..
} = self.data {
let mut updates = webrender_api::ResourceUpdates::new();
if let Some(image_key) = image_key {
updates.delete_image(image_key);
}
if let Some(image_key) = old_image_key {
updates.delete_image(image_key);
}
if let Some(image_key) = very_old_image_key {
updates.delete_image(image_key);
}
webrender_api.update_resources(updates);
}
}
}

File diff suppressed because it is too large Load diff