Backed out changeset b99610a6833f (bug 1661427) for Talos perma failures.

This commit is contained in:
Razvan Maries 2020-08-30 21:13:42 +03:00
Родитель 7144bdce89
Коммит b16f595134
6 изменённых файлов: 152 добавлений и 374 удалений

Просмотреть файл

@ -4,18 +4,16 @@
use bindings::{GeckoProfilerThreadListener, WrCompositor}; use bindings::{GeckoProfilerThreadListener, WrCompositor};
use gleam::{gl, gl::GLenum, gl::Gl}; use gleam::{gl, gl::GLenum, gl::Gl};
use std::cell::{Cell, RefCell}; use std::cell::Cell;
use std::collections::hash_map::HashMap; use std::collections::hash_map::HashMap;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::{AtomicU32, AtomicU8, AtomicUsize, Ordering}; use std::sync::{mpsc, Arc, Condvar, Mutex};
use std::sync::Arc;
use std::thread; use std::thread;
use webrender::{ use webrender::{
api::channel, api::units::*, api::ExternalImageId, api::ImageRendering, api::YuvColorSpace, Compositor, api::units::*, api::ExternalImageId, api::ImageRendering, api::YuvColorSpace, Compositor, CompositorCapabilities,
CompositorCapabilities, CompositorSurfaceTransform, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, CompositorSurfaceTransform, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, ThreadListener,
ThreadListener,
}; };
#[no_mangle] #[no_mangle]
@ -129,8 +127,6 @@ pub struct SwTile {
overlaps: Cell<u32>, overlaps: Cell<u32>,
/// Whether the tile's contents has been invalidated /// Whether the tile's contents has been invalidated
invalid: Cell<bool>, invalid: Cell<bool>,
/// Graph node for job dependencies of this tile
graph_node: Arc<SwCompositeGraphNode>,
} }
impl SwTile { impl SwTile {
@ -146,7 +142,6 @@ impl SwTile {
valid_rect: DeviceIntRect::zero(), valid_rect: DeviceIntRect::zero(),
overlaps: Cell::new(0), overlaps: Cell::new(0),
invalid: Cell::new(false), invalid: Cell::new(false),
graph_node: SwCompositeGraphNode::new(),
} }
} }
@ -415,7 +410,6 @@ impl DrawTileHelper {
/// A source for a composite job which can either be a single BGRA locked SWGL /// A source for a composite job which can either be a single BGRA locked SWGL
/// resource or a collection of SWGL resources representing a YUV surface. /// resource or a collection of SWGL resources representing a YUV surface.
#[derive(Clone)]
enum SwCompositeSource { enum SwCompositeSource {
BGRA(swgl::LockedResource), BGRA(swgl::LockedResource),
YUV( YUV(
@ -431,7 +425,6 @@ unsafe impl Send for SwCompositeSource {}
/// A tile composition job to be processed by the SwComposite thread. /// A tile composition job to be processed by the SwComposite thread.
/// Stores relevant details about the tile and where to composite it. /// Stores relevant details about the tile and where to composite it.
#[derive(Clone)]
struct SwCompositeJob { struct SwCompositeJob {
/// Locked texture that will be unlocked immediately following the job /// Locked texture that will be unlocked immediately following the job
locked_src: SwCompositeSource, locked_src: SwCompositeSource,
@ -442,152 +435,6 @@ struct SwCompositeJob {
opaque: bool, opaque: bool,
flip_y: bool, flip_y: bool,
filter: ImageRendering, filter: ImageRendering,
/// The total number of bands for this job
num_bands: u8,
}
impl SwCompositeJob {
/// Process a composite job
fn process(&self, band_index: u8) {
// Calculate the Y extents for the job's band, starting at the current index and spanning to
// the following index.
let band_index = band_index as i32;
let num_bands = self.num_bands as i32;
let band_offset = (self.dst_rect.size.height * band_index) / num_bands;
let band_height = (self.dst_rect.size.height * (band_index + 1)) / num_bands - band_offset;
match self.locked_src {
SwCompositeSource::BGRA(ref resource) => {
self.locked_dst.composite(
resource,
self.src_rect.origin.x,
self.src_rect.origin.y,
self.src_rect.size.width,
self.src_rect.size.height,
self.dst_rect.origin.x,
self.dst_rect.origin.y,
self.dst_rect.size.width,
self.dst_rect.size.height,
self.opaque,
self.flip_y,
image_rendering_to_gl_filter(self.filter),
band_offset,
band_height,
);
},
SwCompositeSource::YUV(ref y, ref u, ref v, color_space) => {
let swgl_color_space = match color_space {
YuvColorSpace::Rec601 => swgl::YUVColorSpace::Rec601,
YuvColorSpace::Rec709 => swgl::YUVColorSpace::Rec709,
YuvColorSpace::Rec2020 => swgl::YUVColorSpace::Rec2020,
YuvColorSpace::Identity => swgl::YUVColorSpace::Identity,
};
self.locked_dst.composite_yuv(
y,
u,
v,
swgl_color_space,
self.src_rect.origin.x,
self.src_rect.origin.y,
self.src_rect.size.width,
self.src_rect.size.height,
self.dst_rect.origin.x,
self.dst_rect.origin.y,
self.dst_rect.size.width,
self.dst_rect.size.height,
self.flip_y,
band_offset,
band_height,
);
},
}
}
}
/// Dependency graph of composite jobs to be completed. Keeps a list of child jobs that are dependent on the completion of this job.
/// Also keeps track of the number of parent jobs that this job is dependent upon before it can be processed. Once there are no more
/// in-flight parent jobs that it depends on, the graph node is finally added to the job queue for processing.
struct SwCompositeGraphNode {
/// Job to be queued for this graph node once ready.
job: RefCell<Option<SwCompositeJob>>,
/// The number of remaining bands associated with this job.
num_bands: AtomicU8,
/// The number of bands that have been taken for processing.
band_index: AtomicU8,
/// Count of parents this graph node depends on.
parents: AtomicU32,
/// Graph nodes of child jobs that are dependent on this job
children: RefCell<Vec<Arc<SwCompositeGraphNode>>>,
}
unsafe impl Sync for SwCompositeGraphNode {}
impl SwCompositeGraphNode {
fn new() -> Arc<SwCompositeGraphNode> {
Arc::new(SwCompositeGraphNode {
job: RefCell::new(None),
num_bands: AtomicU8::new(0),
band_index: AtomicU8::new(0),
parents: AtomicU32::new(0),
children: RefCell::new(Vec::new()),
})
}
/// Reset the node's state for a new frame
fn reset(&self) {
self.job.replace(None);
self.num_bands.store(0, Ordering::SeqCst);
self.band_index.store(0, Ordering::SeqCst);
self.parents.store(0, Ordering::SeqCst);
self.children.borrow_mut().clear();
}
/// Add a dependent child node to dependency list. Update its parent count.
fn add_child(&self, child: Arc<SwCompositeGraphNode>) {
child.parents.fetch_add(1, Ordering::SeqCst);
self.children.borrow_mut().push(child);
}
/// Install a job for this node. Return whether or not the job has any unprocessed parents
/// that would block immediate composition.
fn set_job(&self, job: SwCompositeJob, num_bands: u8) -> bool {
self.job.replace(Some(job));
// Only set bands after job has been stored to ensure we access it atomically later.
self.num_bands.store(num_bands, Ordering::SeqCst);
// Check whether there are any remaining parent dependencies to see if this job is ready
self.parents.load(Ordering::SeqCst) == 0
}
/// Try to take the job from this node for processing and then process it within the current band.
fn process_job(&self) {
unsafe {
// Borrow the job unguarded so that we don't update the borrow count which would be unsafe.
// The job itself will never be modified while it is in use, so this is actually safe.
if let Ok(Some(ref job)) = self.job.try_borrow_unguarded() {
let band_index = self.band_index.fetch_add(1, Ordering::SeqCst);
job.process(band_index);
}
}
}
/// After processing a band, check all child dependencies and remove this parent from
/// their dependency counts. If applicable, queue the new child bands for composition.
fn unblock_children(&self, sender: &channel::Sender<Arc<SwCompositeGraphNode>>) {
if self.num_bands.fetch_sub(1, Ordering::SeqCst) > 1 {
return;
}
// Clear the job to release any locked resources.
self.job.replace(None);
for child in self.children.borrow().iter() {
// Remove the child's parent dependency on this node. If there are no more
// parent dependencies left, send all the bands for composition.
if child.parents.fetch_sub(1, Ordering::SeqCst) <= 1 {
let num_bands = child.num_bands.load(Ordering::SeqCst);
for _ in 0..num_bands {
sender.send(child.clone()).expect("Failed sending SwComposite job");
}
}
}
}
} }
/// The SwComposite thread processes a queue of composite jobs, also signaling /// The SwComposite thread processes a queue of composite jobs, also signaling
@ -595,12 +442,11 @@ impl SwCompositeGraphNode {
/// the job count. /// the job count.
struct SwCompositeThread { struct SwCompositeThread {
/// Queue of available composite jobs /// Queue of available composite jobs
job_sender: channel::Sender<Arc<SwCompositeGraphNode>>, job_queue: mpsc::Sender<SwCompositeJob>,
job_receiver: channel::Receiver<Arc<SwCompositeGraphNode>>,
/// Count of unprocessed jobs still in the queue /// Count of unprocessed jobs still in the queue
job_count: AtomicUsize, job_count: Mutex<usize>,
/// Condition signaled when there are no more jobs left to process. /// Condition signaled when there are no more jobs left to process
jobs_completed: channel::Receiver<()>, done_cond: Condvar,
} }
/// The SwCompositeThread struct is shared between the SwComposite thread /// The SwCompositeThread struct is shared between the SwComposite thread
@ -611,13 +457,11 @@ impl SwCompositeThread {
/// Create the SwComposite thread. Requires a SWGL context in which /// Create the SwComposite thread. Requires a SWGL context in which
/// to do the composition. /// to do the composition.
fn new() -> Arc<SwCompositeThread> { fn new() -> Arc<SwCompositeThread> {
let (job_sender, job_receiver) = channel::unbounded_channel(); let (job_queue, job_rx) = mpsc::channel();
let (notify_completed, jobs_completed) = channel::fast_channel(1);
let info = Arc::new(SwCompositeThread { let info = Arc::new(SwCompositeThread {
job_sender, job_queue,
job_receiver, job_count: Mutex::new(0),
job_count: AtomicUsize::new(0), done_cond: Condvar::new(),
jobs_completed,
}); });
let result = info.clone(); let result = info.clone();
let thread_name = "SwComposite"; let thread_name = "SwComposite";
@ -629,10 +473,56 @@ impl SwCompositeThread {
// Process any available jobs. This will return a non-Ok // Process any available jobs. This will return a non-Ok
// result when the job queue is dropped, causing the thread // result when the job queue is dropped, causing the thread
// to eventually exit. // to eventually exit.
while let Ok(graph_node) = info.job_receiver.recv() { while let Ok(job) = job_rx.recv() {
if info.process_job(graph_node) { match job.locked_src {
// If this was the final job, signal completion. SwCompositeSource::BGRA(ref resource) => {
let _ = notify_completed.try_send(()); job.locked_dst.composite(
resource,
job.src_rect.origin.x,
job.src_rect.origin.y,
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,
image_rendering_to_gl_filter(job.filter),
);
},
SwCompositeSource::YUV(ref y, ref u, ref v, color_space) => {
let swgl_color_space = match color_space {
YuvColorSpace::Rec601 => swgl::YUVColorSpace::Rec601,
YuvColorSpace::Rec709 => swgl::YUVColorSpace::Rec709,
YuvColorSpace::Rec2020 => swgl::YUVColorSpace::Rec2020,
YuvColorSpace::Identity => swgl::YUVColorSpace::Identity,
};
job.locked_dst.composite_yuv(
y,
u,
v,
swgl_color_space,
job.src_rect.origin.x,
job.src_rect.origin.y,
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.flip_y,
);
},
}
// 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 {
info.done_cond.notify_all();
} }
} }
thread_listener.thread_stopped(thread_name); thread_listener.thread_stopped(thread_name);
@ -641,19 +531,6 @@ impl SwCompositeThread {
result result
} }
/// Process a job contained in a dependency graph node received from the job queue.
/// Any child dependencies will be unblocked as appropriate after processing. The
/// job count will be updated to reflect this. Returns whether or not this was the
/// final job to be processed.
fn process_job(&self, graph_node: Arc<SwCompositeGraphNode>) -> bool {
// Do the actual processing of the job contained in this node.
graph_node.process_job();
// Unblock any child dependencies now that this job has been processed.
graph_node.unblock_children(&self.job_sender);
// Decrement the job count. If applicable, signal that all jobs have been completed.
self.job_count.fetch_sub(1, Ordering::SeqCst) <= 1
}
/// Queue a tile for composition by adding to the queue and increasing the job count. /// Queue a tile for composition by adding to the queue and increasing the job count.
fn queue_composite( fn queue_composite(
&self, &self,
@ -664,74 +541,31 @@ impl SwCompositeThread {
opaque: bool, opaque: bool,
flip_y: bool, flip_y: bool,
filter: ImageRendering, filter: ImageRendering,
graph_node: &Arc<SwCompositeGraphNode>,
) { ) {
// For jobs that would span a sufficiently large destination rectangle, split // There are still tile updates happening, so send the job to the SwComposite thread.
// it into multiple horizontal bands so that multiple threads can process them. *self.job_count.lock().unwrap() += 1;
let num_bands = if dst_rect.size.width >= 64 && dst_rect.size.height >= 64 { self.job_queue
(dst_rect.size.height / 64).min(4) as u8 .send(SwCompositeJob {
} else { locked_src,
1 locked_dst,
}; src_rect,
let job = SwCompositeJob { dst_rect,
locked_src, opaque,
locked_dst, flip_y,
src_rect, filter,
dst_rect, })
opaque, .expect("Failing queuing SwComposite job");
flip_y,
filter,
num_bands,
};
self.job_count.fetch_add(num_bands as usize, Ordering::SeqCst);
if graph_node.set_job(job, num_bands) {
for _ in 0..num_bands {
self.job_sender
.send(graph_node.clone())
.expect("Failed sending SwComposite job");
}
}
} }
fn start_compositing(&self) { /// Wait for all queued composition jobs to be processed by checking the done condition.
// Initialize the job count to 1 to prevent spurious signaling of job completion
// in the middle of queuing compositing jobs until we're actually waiting for
// composition.
self.job_count.store(1, Ordering::SeqCst);
// Drain any erroneous completion signals.
while self.jobs_completed.try_recv().is_ok() {}
}
/// Wait for all queued composition jobs to be processed.
/// Instead of blocking on the SwComposite thread to complete all jobs,
/// this may steal some jobs and attempt to process them while waiting.
fn wait_for_composites(&self) { fn wait_for_composites(&self) {
// Subtract off the bias to signal we're now waiting on composition and let mut jobs = self.job_count.lock().unwrap();
// need to know if jobs are completed. If the job count hits zero here, while *jobs > 0 {
// then we know the SwComposite thread is already done since all queued jobs = self.done_cond.wait(jobs).unwrap();
// jobs have been processed.
if self.job_count.fetch_sub(1, Ordering::SeqCst) <= 1 {
return;
}
// Otherwise, there are remaining jobs that we need to wait for.
loop {
channel::select! {
// Steal jobs from the SwComposite thread if it is busy.
recv(self.job_receiver) -> graph_node => if let Ok(graph_node) = graph_node {
if self.process_job(graph_node) {
// If this was the final job, then just exit.
break;
}
},
// If all jobs have been completed, it is safe to exit.
recv(self.jobs_completed) -> _ => break,
}
} }
} }
} }
/// Adapter for RenderCompositors to work with SWGL that shuttles between
/// WebRender and the RenderCompositr via the Compositor API.
pub struct SwCompositor { pub struct SwCompositor {
gl: swgl::Context, gl: swgl::Context,
native_gl: Option<Rc<dyn gl::Gl>>, native_gl: Option<Rc<dyn gl::Gl>>,
@ -817,7 +651,6 @@ impl SwCompositor {
for tile in &mut surface.tiles { for tile in &mut surface.tiles {
tile.overlaps.set(0); tile.overlaps.set(0);
tile.invalid.set(false); tile.invalid.set(false);
tile.graph_node.reset();
} }
} }
} }
@ -834,20 +667,8 @@ impl SwCompositor {
/// surface hasn't yet been added to the current frame list of surfaces to composite /// 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 /// so that we only process potential blockers from surfaces that would come earlier
/// in composition. /// in composition.
fn init_overlaps( fn get_overlaps(&self, overlap_rect: &DeviceIntRect) -> u32 {
&self, let mut overlaps = 0;
overlap_surface: &SwSurface,
overlap_tile: &SwTile,
overlap_transform: &CompositorSurfaceTransform,
overlap_clip_rect: &DeviceIntRect,
) {
let overlap_rect = match overlap_tile.overlap_rect(overlap_surface, overlap_transform, overlap_clip_rect) {
Some(overlap_rect) => overlap_rect,
None => return,
};
// Record an extra overlap for an invalid tile to track the tile's dependency
// on its own future update.
let mut overlaps = if overlap_tile.invalid.get() { 1 } else { 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, // 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. // then there is no need to check any tiles within the surface.
@ -858,21 +679,13 @@ impl SwCompositor {
for tile in &surface.tiles { for tile in &surface.tiles {
// If there is a deferred tile that might overlap the destination rectangle, // If there is a deferred tile that might overlap the destination rectangle,
// record the overlap. // record the overlap.
if tile.may_overlap(surface, transform, clip_rect, &overlap_rect) { if tile.overlaps.get() > 0 && tile.may_overlap(surface, transform, clip_rect, overlap_rect) {
if tile.overlaps.get() > 0 { overlaps += 1;
overlaps += 1;
}
// Regardless of whether this tile is deferred, if it has dependency
// overlaps, then record that it is potentially a dependency parent.
tile.graph_node.add_child(overlap_tile.graph_node.clone());
} }
} }
} }
} }
if overlaps > 0 { overlaps
// Has a dependency on some invalid tiles, so need to defer composition.
overlap_tile.overlaps.set(overlaps);
}
} }
/// Helper function that queues a composite job to the current locked framebuffer /// Helper function that queues a composite job to the current locked framebuffer
@ -923,15 +736,27 @@ impl SwCompositor {
surface.is_opaque, surface.is_opaque,
flip_y, flip_y,
filter, filter,
&tile.graph_node,
); );
} }
} }
} }
/// Lock a surface with an attached external image for compositing. /// If using the SwComposite thread, we need to compute an overlap count for all tiles
fn try_lock_composite_surface(&mut self, id: &NativeSurfaceId) { /// within the surface being queued for composition this frame. If the tile is immediately
if let Some(surface) = self.surfaces.get_mut(id) { /// 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,
filter: ImageRendering,
) {
if self.composite_thread.is_none() {
return;
}
if let Some(surface) = self.surfaces.get_mut(&id) {
if let Some(external_image) = surface.external_image { if let Some(external_image) = surface.external_image {
// If the surface has an attached external image, attempt to lock the external image // If the surface has an attached external image, attempt to lock the external image
// for compositing. Yields a descriptor of textures and data necessary for their // for compositing. Yields a descriptor of textures and data necessary for their
@ -953,16 +778,22 @@ impl SwCompositor {
} }
} }
} }
}
/// Look for any attached external images that have been locked and then unlock them. if let Some(surface) = self.surfaces.get(&id) {
fn unlock_composite_surfaces(&mut self) { for tile in &surface.tiles {
for &(ref id, _, _, _) in &self.frame_surfaces { if let Some(overlap_rect) = tile.overlap_rect(surface, transform, clip_rect) {
if let Some(surface) = self.surfaces.get_mut(id) { let mut overlaps = self.get_overlaps(&overlap_rect);
if let Some(external_image) = surface.external_image { // Record an extra overlap for an invalid tile to track the tile's dependency
if surface.composite_surface.is_some() { // on its own future update.
unsafe { wr_swgl_unlock_composite_surface(self.gl.into(), external_image) }; if tile.invalid.get() {
surface.composite_surface = None; overlaps += 1;
}
if overlaps == 0 {
// Not dependent on any tiles, so go ahead and composite now.
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);
} }
} }
} }
@ -1383,40 +1214,12 @@ impl Compositor for SwCompositor {
compositor.add_surface(id, transform, clip_rect, filter); compositor.add_surface(id, transform, clip_rect, filter);
} }
if self.composite_thread.is_some() { // Compute overlap dependencies and issue any initial composite jobs for the SwComposite thread.
// If the surface has an attached external image, try to lock that now. self.init_composites(&id, &transform, &clip_rect, filter);
self.try_lock_composite_surface(&id);
// Compute overlap dependencies for the surface.
if let Some(surface) = self.surfaces.get(&id) {
for tile in &surface.tiles {
self.init_overlaps(surface, tile, &transform, &clip_rect);
}
}
}
self.frame_surfaces.push((id, transform, clip_rect, filter)); self.frame_surfaces.push((id, transform, clip_rect, filter));
} }
/// Now that all the dependency graph nodes have been built, start queuing
/// composition jobs.
fn start_compositing(&mut self) {
if let Some(ref composite_thread) = self.composite_thread {
composite_thread.start_compositing();
// Issue any initial composite jobs for the SwComposite thread.
for &(ref id, ref transform, ref clip_rect, filter) in &self.frame_surfaces {
if let Some(surface) = self.surfaces.get(id) {
for tile in &surface.tiles {
if tile.overlaps.get() == 0 {
// Not dependent on any tiles, so go ahead and composite now.
self.queue_composite(surface, transform, clip_rect, filter, tile);
}
}
}
}
}
}
fn end_frame(&mut self) { fn end_frame(&mut self) {
if let Some(compositor) = &mut self.compositor { if let Some(compositor) = &mut self.compositor {
compositor.end_frame(); compositor.end_frame();
@ -1463,7 +1266,17 @@ impl Compositor for SwCompositor {
composite_thread.wait_for_composites(); composite_thread.wait_for_composites();
self.locked_framebuffer = None; self.locked_framebuffer = None;
self.unlock_composite_surfaces(); // Look for any attached external images that have been locked and then unlock them.
for &(ref id, _, _, _) in &self.frame_surfaces {
if let Some(surface) = self.surfaces.get_mut(id) {
if let Some(external_image) = surface.external_image {
if surface.composite_surface.is_some() {
unsafe { wr_swgl_unlock_composite_surface(self.gl.into(), external_image) };
surface.composite_surface = None;
}
}
}
}
} }
} }

Просмотреть файл

@ -17,7 +17,7 @@ static inline void scale_row(P* dst, int dstWidth, const P* src, int srcWidth,
static void scale_blit(Texture& srctex, const IntRect& srcReq, int srcZ, static void scale_blit(Texture& srctex, const IntRect& srcReq, int srcZ,
Texture& dsttex, const IntRect& dstReq, int dstZ, Texture& dsttex, const IntRect& dstReq, int dstZ,
bool invertY, int bandOffset, int bandHeight) { bool invertY) {
// Cache scaling ratios // Cache scaling ratios
int srcWidth = srcReq.width(); int srcWidth = srcReq.width();
int srcHeight = srcReq.height(); int srcHeight = srcReq.height();
@ -49,11 +49,8 @@ static void scale_blit(Texture& srctex, const IntRect& srcReq, int srcZ,
destStride = -destStride; destStride = -destStride;
} }
int span = dstBounds.width(); int span = dstBounds.width();
int frac = srcHeight * bandOffset; int frac = 0;
dest += destStride * bandOffset; for (int rows = dstBounds.height(); rows > 0; rows--) {
src += srcStride * (frac / dstHeight);
frac %= dstHeight;
for (int rows = min(dstBounds.height(), bandHeight); rows > 0; rows--) {
if (srcWidth == dstWidth) { if (srcWidth == dstWidth) {
// No scaling, so just do a fast copy. // No scaling, so just do a fast copy.
memcpy(dest, src, span * bpp); memcpy(dest, src, span * bpp);
@ -138,7 +135,7 @@ static void linear_row_blit(uint16_t* dest, int span, const vec2_scalar& srcUV,
static void linear_blit(Texture& srctex, const IntRect& srcReq, int srcZ, static void linear_blit(Texture& srctex, const IntRect& srcReq, int srcZ,
Texture& dsttex, const IntRect& dstReq, int dstZ, Texture& dsttex, const IntRect& dstReq, int dstZ,
bool invertY, int bandOffset, int bandHeight) { bool invertY) {
assert(srctex.internal_format == GL_RGBA8 || assert(srctex.internal_format == GL_RGBA8 ||
srctex.internal_format == GL_R8 || srctex.internal_format == GL_RG8); srctex.internal_format == GL_R8 || srctex.internal_format == GL_RG8);
// Compute valid dest bounds // Compute valid dest bounds
@ -170,10 +167,8 @@ static void linear_blit(Texture& srctex, const IntRect& srcReq, int srcZ,
if (invertY) { if (invertY) {
destStride = -destStride; destStride = -destStride;
} }
dest += destStride * bandOffset;
srcUV.y += srcDUV.y * bandOffset;
int span = dstBounds.width(); int span = dstBounds.width();
for (int rows = min(dstBounds.height(), bandHeight); rows > 0; rows--) { for (int rows = dstBounds.height(); rows > 0; rows--) {
switch (bpp) { switch (bpp) {
case 1: case 1:
linear_row_blit((uint8_t*)dest, span, srcUV, srcDUV.x, srcZOffset, linear_row_blit((uint8_t*)dest, span, srcUV, srcDUV.x, srcZOffset,
@ -222,7 +217,7 @@ static void linear_row_composite(uint32_t* dest, int span,
static void linear_composite(Texture& srctex, const IntRect& srcReq, static void linear_composite(Texture& srctex, const IntRect& srcReq,
Texture& dsttex, const IntRect& dstReq, Texture& dsttex, const IntRect& dstReq,
bool invertY, int bandOffset, int bandHeight) { bool invertY) {
assert(srctex.bpp() == 4); assert(srctex.bpp() == 4);
assert(dsttex.bpp() == 4); assert(dsttex.bpp() == 4);
// Compute valid dest bounds // Compute valid dest bounds
@ -251,10 +246,8 @@ static void linear_composite(Texture& srctex, const IntRect& srcReq,
if (invertY) { if (invertY) {
destStride = -destStride; destStride = -destStride;
} }
dest += destStride * bandOffset;
srcUV.y += srcDUV.y * bandOffset;
int span = dstBounds.width(); int span = dstBounds.width();
for (int rows = min(dstBounds.height(), bandHeight); rows > 0; rows--) { for (int rows = dstBounds.height(); rows > 0; rows--) {
linear_row_composite((uint32_t*)dest, span, srcUV, srcDUV.x, &sampler); linear_row_composite((uint32_t*)dest, span, srcUV, srcDUV.x, &sampler);
dest += destStride; dest += destStride;
srcUV.y += srcDUV.y; srcUV.y += srcDUV.y;
@ -300,10 +293,10 @@ void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
(srctex.internal_format == GL_RGBA8 || srctex.internal_format == GL_R8 || (srctex.internal_format == GL_RGBA8 || srctex.internal_format == GL_R8 ||
srctex.internal_format == GL_RG8)) { srctex.internal_format == GL_RG8)) {
linear_blit(srctex, srcReq, srcfb->layer, dsttex, dstReq, dstfb->layer, linear_blit(srctex, srcReq, srcfb->layer, dsttex, dstReq, dstfb->layer,
invertY, 0, dstReq.height()); invertY);
} else { } else {
scale_blit(srctex, srcReq, srcfb->layer, dsttex, dstReq, dstfb->layer, scale_blit(srctex, srcReq, srcfb->layer, dsttex, dstReq, dstfb->layer,
invertY, 0, dstReq.height()); invertY);
} }
} }
@ -364,13 +357,11 @@ void* GetResourceBuffer(LockedTexture* resource, int32_t* width,
// Extension for optimized compositing of textures or framebuffers that may be // Extension for optimized compositing of textures or framebuffers that may be
// safely used across threads. The source and destination must be locked to // 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 // ensure that they can be safely accessed while the SWGL context might be used
// by another thread. Band extents along the Y axis may be used to clip the // by another thread.
// destination rectangle without effecting the integer scaling ratios.
void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX, void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
GLint srcY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX, GLint srcY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX,
GLint dstY, GLsizei dstWidth, GLsizei dstHeight, GLint dstY, GLsizei dstWidth, GLsizei dstHeight,
GLboolean opaque, GLboolean flip, GLenum filter, GLboolean opaque, GLboolean flip, GLenum filter) {
GLint bandOffset, GLsizei bandHeight) {
if (!lockedDst || !lockedSrc) { if (!lockedDst || !lockedSrc) {
return; return;
} }
@ -384,27 +375,25 @@ void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
if (opaque) { if (opaque) {
if (!srcReq.same_size(dstReq) && filter == GL_LINEAR) { if (!srcReq.same_size(dstReq) && filter == GL_LINEAR) {
linear_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip, bandOffset, bandHeight); linear_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip);
} else { } else {
scale_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip, bandOffset, bandHeight); scale_blit(srctex, srcReq, 0, dsttex, dstReq, 0, flip);
} }
} else { } else {
if (!srcReq.same_size(dstReq) || filter == GL_LINEAR) { if (!srcReq.same_size(dstReq) || filter == GL_LINEAR) {
linear_composite(srctex, srcReq, dsttex, dstReq, flip, bandOffset, bandHeight); linear_composite(srctex, srcReq, dsttex, dstReq, flip);
} else { } else {
const int bpp = 4; const int bpp = 4;
IntRect bounds = dsttex.sample_bounds(dstReq, flip); IntRect bounds = dsttex.sample_bounds(dstReq, flip);
bounds.intersect(srctex.sample_bounds(srcReq)); bounds.intersect(srctex.sample_bounds(srcReq));
char* dest = dsttex.sample_ptr(dstReq, bounds, 0, flip); char* dest = dsttex.sample_ptr(dstReq, bounds, 0, flip);
char* src = srctex.sample_ptr(srcReq, bounds, 0); char* src = srctex.sample_ptr(srcReq, bounds, 0);
int srcStride = srctex.stride(); size_t destStride = dsttex.stride();
int destStride = dsttex.stride();
if (flip) { if (flip) {
destStride = -destStride; destStride = -destStride;
} }
dest += destStride * bandOffset;
src += srcStride * bandOffset; for (int y = 0; y < bounds.height(); y++) {
for (int rows = min(bounds.height(), bandHeight); rows > 0; rows--) {
char* end = src + bounds.width() * bpp; char* end = src + bounds.width() * bpp;
while (src + 4 * bpp <= end) { while (src + 4 * bpp <= end) {
WideRGBA8 srcpx = unpack(unaligned_load<PackedRGBA8>(src)); WideRGBA8 srcpx = unpack(unaligned_load<PackedRGBA8>(src));
@ -430,7 +419,7 @@ void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
src = end; src = end;
} }
dest += destStride - bounds.width() * bpp; dest += destStride - bounds.width() * bpp;
src += srcStride - bounds.width() * bpp; src += srctex.stride() - bounds.width() * bpp;
} }
} }
} }
@ -710,7 +699,7 @@ static void linear_row_yuv(uint32_t* dest, int span, const vec2_scalar& srcUV,
static void linear_convert_yuv(Texture& ytex, Texture& utex, Texture& vtex, static void linear_convert_yuv(Texture& ytex, Texture& utex, Texture& vtex,
YUVColorSpace colorSpace, const IntRect& srcReq, YUVColorSpace colorSpace, const IntRect& srcReq,
Texture& dsttex, const IntRect& dstReq, Texture& dsttex, const IntRect& dstReq,
bool invertY, int bandOffset, int bandHeight) { bool invertY) {
// Compute valid dest bounds // Compute valid dest bounds
IntRect dstBounds = dsttex.sample_bounds(dstReq, invertY); IntRect dstBounds = dsttex.sample_bounds(dstReq, invertY);
// Check if sampling bounds are empty // Check if sampling bounds are empty
@ -746,11 +735,8 @@ static void linear_convert_yuv(Texture& ytex, Texture& utex, Texture& vtex,
if (invertY) { if (invertY) {
destStride = -destStride; destStride = -destStride;
} }
dest += destStride * bandOffset;
srcUV.y += srcDUV.y * bandOffset;
chromaUV.y += chromaDUV.y * bandOffset;
int span = dstBounds.width(); int span = dstBounds.width();
for (int rows = min(dstBounds.height(), bandHeight); rows > 0; rows--) { for (int rows = dstBounds.height(); rows > 0; rows--) {
switch (colorSpace) { switch (colorSpace) {
case REC_601: case REC_601:
linear_row_yuv<REC_601>((uint32_t*)dest, span, srcUV, srcDUV.x, linear_row_yuv<REC_601>((uint32_t*)dest, span, srcUV, srcDUV.x,
@ -788,8 +774,7 @@ void CompositeYUV(LockedTexture* lockedDst, LockedTexture* lockedY,
LockedTexture* lockedU, LockedTexture* lockedV, LockedTexture* lockedU, LockedTexture* lockedV,
YUVColorSpace colorSpace, GLint srcX, GLint srcY, YUVColorSpace colorSpace, GLint srcX, GLint srcY,
GLsizei srcWidth, GLsizei srcHeight, GLint dstX, GLint dstY, GLsizei srcWidth, GLsizei srcHeight, GLint dstX, GLint dstY,
GLsizei dstWidth, GLsizei dstHeight, GLboolean flip, GLsizei dstWidth, GLsizei dstHeight, GLboolean flip) {
GLint bandOffset, GLsizei bandHeight) {
if (!lockedDst || !lockedY || !lockedU || !lockedV) { if (!lockedDst || !lockedY || !lockedU || !lockedV) {
return; return;
} }
@ -810,7 +795,7 @@ void CompositeYUV(LockedTexture* lockedDst, LockedTexture* lockedY,
// scaling. Further fast-paths for non-scaled video might be desirable in the // scaling. Further fast-paths for non-scaled video might be desirable in the
// future. // future.
linear_convert_yuv(ytex, utex, vtex, colorSpace, srcReq, dsttex, dstReq, linear_convert_yuv(ytex, utex, vtex, colorSpace, srcReq, dsttex, dstReq,
flip, bandOffset, bandHeight); flip);
} }
} // extern "C" } // extern "C"

Просмотреть файл

@ -306,8 +306,6 @@ extern "C" {
opaque: GLboolean, opaque: GLboolean,
flip: GLboolean, flip: GLboolean,
filter: GLenum, filter: GLenum,
band_offset: GLint,
band_height: GLsizei,
); );
fn CompositeYUV( fn CompositeYUV(
locked_dst: *mut LockedTexture, locked_dst: *mut LockedTexture,
@ -324,8 +322,6 @@ extern "C" {
dst_width: GLsizei, dst_width: GLsizei,
dst_height: GLsizei, dst_height: GLsizei,
flip: GLboolean, flip: GLboolean,
band_offset: GLint,
band_height: GLsizei,
); );
fn CreateContext() -> *mut c_void; fn CreateContext() -> *mut c_void;
fn ReferenceContext(ctx: *mut c_void); fn ReferenceContext(ctx: *mut c_void);
@ -2322,9 +2318,7 @@ pub enum YUVColorSpace {
} }
impl LockedResource { impl LockedResource {
/// Composites from a locked resource to another locked resource. The band /// Composites from a locked resource to another locked resource
/// offset and height are relative to the destination rectangle and specify
/// how to clip the composition into appropriate range for this band.
pub fn composite( pub fn composite(
&self, &self,
locked_src: &LockedResource, locked_src: &LockedResource,
@ -2339,8 +2333,6 @@ impl LockedResource {
opaque: bool, opaque: bool,
flip: bool, flip: bool,
filter: GLenum, filter: GLenum,
band_offset: GLint,
band_height: GLsizei,
) { ) {
unsafe { unsafe {
Composite( Composite(
@ -2357,8 +2349,6 @@ impl LockedResource {
opaque as GLboolean, opaque as GLboolean,
flip as GLboolean, flip as GLboolean,
filter, filter,
band_offset,
band_height,
); );
} }
} }
@ -2379,8 +2369,6 @@ impl LockedResource {
dst_width: GLsizei, dst_width: GLsizei,
dst_height: GLsizei, dst_height: GLsizei,
flip: bool, flip: bool,
band_offset: GLint,
band_height: GLsizei,
) { ) {
unsafe { unsafe {
CompositeYUV( CompositeYUV(
@ -2398,8 +2386,6 @@ impl LockedResource {
dst_width, dst_width,
dst_height, dst_height,
flip as GLboolean, flip as GLboolean,
band_offset,
band_height,
); );
} }
} }

Просмотреть файл

@ -964,11 +964,6 @@ pub trait Compositor {
image_rendering: ImageRendering, image_rendering: ImageRendering,
); );
/// Notify the compositor that all tiles have been invalidated and all
/// native surfaces have been added, thus it is safe to start compositing
/// valid surfaces.
fn start_compositing(&mut self) {}
/// Commit any changes in the compositor tree for this frame. WR calls /// Commit any changes in the compositor tree for this frame. WR calls
/// this once when all surface and visual updates are complete, to signal /// this once when all surface and visual updates are complete, to signal
/// that the OS composite transaction should be applied. /// that the OS composite transaction should be applied.

Просмотреть файл

@ -7827,6 +7827,5 @@ impl CompositeState {
surface.image_rendering, surface.image_rendering,
); );
} }
compositor.start_compositing();
} }
} }

Просмотреть файл

@ -7,7 +7,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::io::{self, Cursor, Error, ErrorKind, Read}; use std::io::{self, Cursor, Error, ErrorKind, Read};
use std::mem; use std::mem;
pub use crossbeam_channel::{select, Sender, Receiver}; pub use crossbeam_channel::{Sender, Receiver};
#[derive(Clone)] #[derive(Clone)]
pub struct Payload { pub struct Payload {