| author | Matt Woodrow <mwoodrow@mozilla.com> |
| Fri, 14 Aug 2020 00:56:22 +0000 | |
| changeset 544714 | 565097a8dd7db08d82151d40b7c3fcfdb6288c48 |
| parent 544713 | 9a94d0040d2f9b0bf93fa02a624d5805e563e920 |
| child 544715 | 33f1b6bf6b17cf0aaf020a5f3c3dede0a43a01f1 |
| push id | 37700 |
| push user | dluca@mozilla.com |
| push date | Sat, 15 Aug 2020 09:31:17 +0000 |
| treeherder | mozilla-central@7dcb2bda35c7 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | lsalzman |
| bugs | 1658858 |
| milestone | 81.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/webrender_bindings/src/swgl_bindings.rs +++ b/gfx/webrender_bindings/src/swgl_bindings.rs @@ -1,14 +1,14 @@ /* 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 bindings::{GeckoProfilerThreadListener, WrCompositor}; -use gleam::{gl, gl::Gl}; +use gleam::{gl, gl::Gl, gl::GLenum}; use std::cell::Cell; use std::collections::hash_map::HashMap; use std::os::raw::c_void; use std::ptr; use std::rc::Rc; use std::sync::{mpsc, Arc, Condvar, Mutex}; use std::thread; use webrender::{ @@ -290,16 +290,17 @@ impl DrawTileHelper { fn draw( &self, viewport: &DeviceIntRect, dest: &DeviceIntRect, src: &DeviceIntRect, surface: &SwSurface, tile: &SwTile, flip_y: bool, + filter: GLenum, ) { let dx = dest.origin.x as f32 / viewport.size.width as f32; let dy = dest.origin.y as f32 / viewport.size.height as f32; let dw = dest.size.width as f32 / viewport.size.width as f32; let dh = dest.size.height as f32 / viewport.size.height as f32; self.gl.uniform_matrix_3fv( self.dest_matrix_loc, false, @@ -318,16 +319,18 @@ impl DrawTileHelper { let sx = src.origin.x as f32 / surface.tile_size.width as f32; let sy = src.origin.y as f32 / surface.tile_size.height as f32; let sw = src.size.width as f32 / surface.tile_size.width as f32; let sh = src.size.height as f32 / surface.tile_size.height as f32; self.gl .uniform_matrix_3fv(self.tex_matrix_loc, false, &[sw, 0.0, 0.0, 0.0, sh, 0.0, sx, sy, 1.0]); self.gl.bind_texture(gl::TEXTURE_2D, tile.tex_id); + self.gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as gl::GLint); + self.gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as gl::GLint); self.gl.draw_arrays(gl::TRIANGLE_STRIP, 0, 4); } fn disable(&self) { self.gl.use_program(0); self.gl.bind_vertex_array(0); } } @@ -338,16 +341,17 @@ struct SwCompositeJob { /// Locked texture that will be unlocked immediately following the job locked_src: swgl::LockedResource, /// Locked framebuffer that may be shared among many jobs locked_dst: swgl::LockedResource, src_rect: DeviceIntRect, dst_rect: DeviceIntRect, opaque: bool, flip_y: bool, + filter: GLenum, } /// The SwComposite thread processes a queue of composite jobs, also signaling /// via a condition when all available jobs have been processed, as tracked by /// the job count. struct SwCompositeThread { /// Queue of available composite jobs job_queue: mpsc::Sender<SwCompositeJob>, @@ -389,16 +393,17 @@ impl SwCompositeThread { job.src_rect.size.width, job.src_rect.size.height, job.dst_rect.origin.x, job.dst_rect.origin.y, job.dst_rect.size.width, job.dst_rect.size.height, job.opaque, job.flip_y, + job.filter, ); // Release locked resources before modifying job count drop(job); // Decrement the job count. If applicable, signal that all jobs // have been completed. let mut count = info.job_count.lock().unwrap(); *count -= 1; if *count <= 0 { @@ -415,27 +420,29 @@ impl SwCompositeThread { fn queue_composite( &self, locked_src: swgl::LockedResource, locked_dst: swgl::LockedResource, src_rect: DeviceIntRect, dst_rect: DeviceIntRect, opaque: bool, flip_y: bool, + filter: GLenum, ) { // There are still tile updates happening, so send the job to the SwComposite thread. *self.job_count.lock().unwrap() += 1; self.job_queue .send(SwCompositeJob { locked_src, locked_dst, src_rect, dst_rect, opaque, flip_y, + filter, }) .expect("Failing queuing SwComposite job"); } /// Wait for all queued composition jobs to be processed by checking the done condition. fn wait_for_composites(&self) { let mut jobs = self.job_count.lock().unwrap(); while *jobs > 0 { @@ -444,17 +451,17 @@ impl SwCompositeThread { } } pub struct SwCompositor { gl: swgl::Context, native_gl: Option<Rc<dyn gl::Gl>>, compositor: Option<WrCompositor>, surfaces: HashMap<NativeSurfaceId, SwSurface>, - frame_surfaces: Vec<(NativeSurfaceId, CompositorSurfaceTransform, DeviceIntRect)>, + frame_surfaces: Vec<(NativeSurfaceId, CompositorSurfaceTransform, DeviceIntRect, GLenum)>, cur_tile: NativeTileId, draw_tile: Option<DrawTileHelper>, /// The maximum tile size required for any of the allocated surfaces. max_tile_size: DeviceIntSize, /// Reuse the same depth texture amongst all tiles in all surfaces. /// This depth texture must be big enough to accommodate the largest used /// tile size for any surface. The maximum requested tile size is tracked /// to ensure that this depth texture is at least that big. @@ -537,17 +544,17 @@ impl SwCompositor { /// the order the surfaces were queued, so it is safe to ignore other possible sources /// of composition ordering dependencies, as the later queued tile will still be drawn /// later than the blocking tiles within that stable order. We assume that the tile's /// surface hasn't yet been added to the current frame list of surfaces to composite /// so that we only process potential blockers from surfaces that would come earlier /// in composition. fn get_overlaps(&self, overlap_rect: &DeviceIntRect) -> u32 { let mut overlaps = 0; - for &(ref id, ref transform, ref clip_rect) in &self.frame_surfaces { + for &(ref id, ref transform, ref clip_rect, _) in &self.frame_surfaces { // If the surface's clip rect doesn't overlap the tile's rect, // then there is no need to check any tiles within the surface. if !overlap_rect.intersects(clip_rect) { continue; } if let Some(surface) = self.surfaces.get(id) { for tile in &surface.tiles { // If there is a deferred tile that might overlap the destination rectangle, @@ -563,49 +570,56 @@ impl SwCompositor { } /// Helper function that queues a composite job to the current locked framebuffer fn queue_composite( &self, surface: &SwSurface, transform: &CompositorSurfaceTransform, clip_rect: &DeviceIntRect, + filter: GLenum, tile: &SwTile, ) { if let Some(ref composite_thread) = self.composite_thread { if let Some((src_rect, dst_rect, flip_y)) = tile.composite_rects(surface, transform, clip_rect) { if let Some(texture) = self.gl.lock_texture(tile.color_id) { let framebuffer = self.locked_framebuffer.clone().unwrap(); - composite_thread.queue_composite(texture, framebuffer, src_rect, dst_rect, surface.is_opaque, flip_y); + composite_thread.queue_composite(texture, framebuffer, src_rect, dst_rect, surface.is_opaque, flip_y, filter); } } } } /// If using the SwComposite thread, we need to compute an overlap count for all tiles /// within the surface being queued for composition this frame. If the tile is immediately /// ready to composite, then queue that now. Otherwise, set its draw order index for later /// composition. - fn init_composites(&mut self, id: &NativeSurfaceId, transform: &CompositorSurfaceTransform, clip_rect: &DeviceIntRect) { + fn init_composites( + &mut self, + id: &NativeSurfaceId, + transform: &CompositorSurfaceTransform, + clip_rect: &DeviceIntRect, + filter: GLenum, + ) { if self.composite_thread.is_none() { return; } if let Some(surface) = self.surfaces.get(&id) { for tile in &surface.tiles { if let Some(overlap_rect) = tile.overlap_rect(surface, transform, clip_rect) { let mut overlaps = self.get_overlaps(&overlap_rect); // Record an extra overlap for an invalid tile to track the tile's dependency // on its own future update. if tile.invalid.get() { overlaps += 1; } if overlaps == 0 { // Not dependent on any tiles, so go ahead and composite now. - self.queue_composite(surface, transform, clip_rect, tile); + self.queue_composite(surface, transform, clip_rect, filter, tile); } else { // Has a dependency on some invalid tiles, so need to defer composition. tile.overlaps.set(overlaps); } } } } } @@ -616,45 +630,45 @@ impl SwCompositor { if self.composite_thread.is_none() { return; } // Look for the tile in the frame list and composite it if it has no dependencies. let mut frame_surfaces = self .frame_surfaces .iter() - .skip_while(|&(ref id, _, _)| *id != tile_id.surface_id); + .skip_while(|&(ref id, _, _, _)| *id != tile_id.surface_id); let overlap_rect = match frame_surfaces.next() { - Some(&(_, ref transform, ref clip_rect)) => { + Some(&(_, ref transform, ref clip_rect, filter)) => { // Remove invalid tile's update dependency. if tile.invalid.get() { tile.overlaps.set(tile.overlaps.get() - 1); } // If the tile still has overlaps, keep deferring it till later. if tile.overlaps.get() > 0 { return; } // Otherwise, the tile's dependencies are all resolved, so composite it. - self.queue_composite(surface, transform, clip_rect, tile); + self.queue_composite(surface, transform, clip_rect, filter, tile); // Finally, get the tile's overlap rect used for tracking dependencies match tile.overlap_rect(surface, transform, clip_rect) { Some(overlap_rect) => overlap_rect, None => return, } } None => return, }; // Accumulate rects whose dependencies have been satisfied from this update. // Store the union of all these bounds to quickly reject unaffected tiles. let mut flushed_bounds = overlap_rect; let mut flushed_rects = vec![overlap_rect]; // Check surfaces following the update in the frame list and see if they would overlap it. - for &(ref id, ref transform, ref clip_rect) in frame_surfaces { + for &(ref id, ref transform, ref clip_rect, filter) in frame_surfaces { // If the clip rect doesn't overlap the conservative bounds, we can skip the whole surface. if !flushed_bounds.intersects(clip_rect) { continue; } if let Some(surface) = self.surfaces.get(&id) { // Search through the surface's tiles for any blocked on this update and queue jobs for them. for tile in &surface.tiles { let mut overlaps = tile.overlaps.get(); @@ -677,17 +691,17 @@ impl SwCompositor { overlaps -= 1; } } if overlaps != tile.overlaps.get() { // If the overlap count changed, this tile had a dependency on some flush rects. // If the count hit zero, it is ready to composite. tile.overlaps.set(overlaps); if overlaps == 0 { - self.queue_composite(surface, transform, clip_rect, tile); + self.queue_composite(surface, transform, clip_rect, filter, tile); // Record that the tile got flushed to update any downwind dependencies. flushed_bounds = flushed_bounds.union(&overlap_rect); flushed_rects.push(overlap_rect); } } } } } @@ -988,17 +1002,17 @@ impl Compositor for SwCompositor { if let Some(compositor) = &mut self.compositor { let info = compositor.bind(id, tile.dirty_rect, tile.valid_rect); native_gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, info.fbo_id); let viewport = dirty.translate(info.origin.to_vector()); let draw_tile = self.draw_tile.as_ref().unwrap(); draw_tile.enable(&viewport); - draw_tile.draw(&viewport, &viewport, &dirty, &surface, &tile, false); + draw_tile.draw(&viewport, &viewport, &dirty, &surface, &tile, false, gl::LINEAR); draw_tile.disable(); native_gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, 0); compositor.unbind(); } native_gl.bind_texture(gl::TEXTURE_2D, 0); @@ -1024,46 +1038,55 @@ impl Compositor for SwCompositor { transform: CompositorSurfaceTransform, clip_rect: DeviceIntRect, image_rendering: ImageRendering ) { if let Some(compositor) = &mut self.compositor { compositor.add_surface(id, transform, clip_rect, image_rendering); } + let filter = match image_rendering { + ImageRendering::Pixelated => { + gl::NEAREST + } + ImageRendering::Auto | ImageRendering::CrispEdges => { + gl::LINEAR + } + }; + // Compute overlap dependencies and issue any initial composite jobs for the SwComposite thread. - self.init_composites(&id, &transform, &clip_rect); + self.init_composites(&id, &transform, &clip_rect, filter); - self.frame_surfaces.push((id, transform, clip_rect)); + self.frame_surfaces.push((id, transform, clip_rect, filter)); } fn end_frame(&mut self) { if let Some(compositor) = &mut self.compositor { compositor.end_frame(); } else if let Some(native_gl) = &self.native_gl { let (_, fw, fh, _) = self.gl.get_color_buffer(0, false); let viewport = DeviceIntRect::from_size(DeviceIntSize::new(fw, fh)); let draw_tile = self.draw_tile.as_ref().unwrap(); draw_tile.enable(&viewport); let mut blend = false; native_gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA); - for &(ref id, ref transform, ref clip_rect) in &self.frame_surfaces { + for &(ref id, ref transform, ref clip_rect, filter) in &self.frame_surfaces { if let Some(surface) = self.surfaces.get(id) { if surface.is_opaque { if blend { native_gl.disable(gl::BLEND); blend = false; } } else if !blend { native_gl.enable(gl::BLEND); blend = true; } for tile in &surface.tiles { if let Some((src_rect, dst_rect, flip_y)) = tile.composite_rects(surface, transform, clip_rect) { - draw_tile.draw(&viewport, &dst_rect, &src_rect, surface, tile, flip_y); + draw_tile.draw(&viewport, &dst_rect, &src_rect, surface, tile, flip_y, filter); } } } } if blend { native_gl.disable(gl::BLEND); } draw_tile.disable();
--- a/gfx/wr/swgl/src/gl.cc +++ b/gfx/wr/swgl/src/gl.cc @@ -4185,17 +4185,17 @@ void UnlockResource(LockedTexture* resou // Extension for optimized compositing of textures or framebuffers that may be // safely used across threads. The source and destination must be locked to // ensure that they can be safely accessed while the SWGL context might be used // by another thread. void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX, GLint srcY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX, GLint dstY, GLsizei dstWidth, GLsizei dstHeight, - GLboolean opaque, GLboolean flip) { + GLboolean opaque, GLboolean flip, GLenum filter) { if (!lockedDst || !lockedSrc) { return; } Texture& srctex = *lockedSrc; Texture& dsttex = *lockedDst; assert(srctex.bpp() == 4); const int bpp = 4; size_t src_stride = srctex.stride(); @@ -4219,17 +4219,16 @@ void Composite(LockedTexture* lockedDst, char* dest = dsttex.sample_ptr(dstX, flip ? dsttex.height - 1 - dstY : dstY); char* src = srctex.sample_ptr(srcX, srcY); if (flip) { dest_stride = -dest_stride; } IntRect srcReq = {srcX, srcY, srcX + srcWidth, srcY + srcHeight}; IntRect dstReq = {dstX, dstY, dstX + dstWidth, dstY + dstHeight}; - GLenum filter = GL_LINEAR; // TODO if (opaque) { if (!srcReq.same_size(dstReq) && filter == GL_LINEAR) { linear_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip); } else { scale_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip); } } else {
--- a/gfx/wr/swgl/src/swgl_fns.rs +++ b/gfx/wr/swgl/src/swgl_fns.rs @@ -294,16 +294,17 @@ extern "C" { src_width: GLsizei, src_height: GLsizei, dst_x: GLint, dst_y: GLint, dst_width: GLsizei, dst_height: GLsizei, opaque: GLboolean, flip: GLboolean, + filter: GLenum, ); fn CreateContext() -> *mut c_void; fn ReferenceContext(ctx: *mut c_void); fn DestroyContext(ctx: *mut c_void); fn MakeCurrent(ctx: *mut c_void); } #[derive(Clone)] @@ -2296,31 +2297,33 @@ impl LockedResource { src_width: GLsizei, src_height: GLsizei, dst_x: GLint, dst_y: GLint, dst_width: GLsizei, dst_height: GLsizei, opaque: bool, flip: bool, + filter: GLenum, ) { unsafe { Composite( self.0, locked_src.0, src_x, src_y, src_width, src_height, dst_x, dst_y, dst_width, dst_height, opaque as GLboolean, flip as GLboolean, + filter, ); } } } impl Clone for LockedResource { fn clone(&self) -> Self { unsafe { LockResource(self.0); }