Bug 1370891 - Render blob images in webrender's thread pool. r=jrmuizel

This commit is contained in:
Nicolas Silva 2017-06-13 17:57:11 +02:00
parent 3869f41093
commit fa4995fa8f
6 changed files with 151 additions and 66 deletions

View File

@ -6,6 +6,8 @@ license = "MPL-2.0"
[dependencies]
webrender_traits = {path = "../webrender_traits", version = "0.40.0"}
rayon = {version = "0.7", features = ["unstable"]}
thread_profiler = "0.1.1"
euclid = "0.13"
app_units = "0.4"
gleam = "0.4"

View File

@ -2,16 +2,19 @@ use std::collections::HashSet;
use std::ffi::CString;
use std::{mem, slice};
use std::path::PathBuf;
use std::sync::Arc;
use std::os::raw::{c_void, c_char, c_float};
use std::collections::HashMap;
use gleam::gl;
use webrender_traits::*;
use webrender::renderer::{ReadPixelsFormat, Renderer, RendererOptions};
use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
use webrender::{ApiRecordingReceiver, BinaryRecorder};
use thread_profiler::register_thread_with_profiler;
use moz2d_renderer::Moz2dImageRenderer;
use app_units::Au;
use euclid::{TypedPoint2D, TypedSize2D, TypedRect, TypedMatrix4D, SideOffsets2D};
use rayon;
extern crate webrender_traits;
@ -896,12 +899,21 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
println!("WebRender - OpenGL version new {}", version);
let worker_config = rayon::Configuration::new()
.thread_name(|idx|{ format!("WebRender:Worker#{}", idx) })
.start_handler(|idx| {
register_thread_with_profiler(format!("WebRender:Worker#{}", idx));
});
let workers = Arc::new(rayon::ThreadPool::new(worker_config).unwrap());
let opts = RendererOptions {
enable_aa: true,
enable_subpixel_aa: true,
enable_profiler: enable_profiler,
recorder: recorder,
blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new())),
blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new(workers.clone()))),
workers: Some(workers.clone()),
cache_expiry_frames: 60, // see https://github.com/servo/webrender/pull/1294#issuecomment-304318800
..Default::default()
};
@ -1759,73 +1771,15 @@ pub unsafe extern "C" fn wr_dp_push_built_display_list(state: &mut WrState,
state.frame_builder.dl_builder.push_built_display_list(dl);
}
struct Moz2dImageRenderer {
images: HashMap<ImageKey, BlobImageData>,
// The images rendered in the current frame (not kept here between frames)
rendered_images: HashMap<BlobImageRequest, BlobImageResult>,
}
impl BlobImageRenderer for Moz2dImageRenderer {
fn add(&mut self, key: ImageKey, data: BlobImageData, _tiling: Option<TileSize>) {
self.images.insert(key, data);
}
fn update(&mut self, key: ImageKey, data: BlobImageData) {
self.images.insert(key, data);
}
fn delete(&mut self, key: ImageKey) {
self.images.remove(&key);
}
fn request(&mut self,
request: BlobImageRequest,
descriptor: &BlobImageDescriptor,
_dirty_rect: Option<DeviceUintRect>,
_images: &ImageStore) {
let data = self.images.get(&request.key).unwrap();
let buf_size = (descriptor.width * descriptor.height * descriptor.format.bytes_per_pixel().unwrap()) as usize;
let mut output = vec![255u8; buf_size];
unsafe {
if wr_moz2d_render_cb(WrByteSlice::new(&data[..]),
descriptor.width,
descriptor.height,
descriptor.format,
MutByteSlice::new(output.as_mut_slice())) {
self.rendered_images.insert(request,
Ok(RasterizedBlobImage {
width: descriptor.width,
height: descriptor.height,
data: output,
}));
}
}
}
fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
self.rendered_images.remove(&request).unwrap_or(Err(BlobImageError::InvalidKey))
}
}
impl Moz2dImageRenderer {
fn new() -> Self {
Moz2dImageRenderer {
images: HashMap::new(),
rendered_images: HashMap::new()
}
}
}
// TODO: nical
// Update for the new blob image interface changes.
//
extern "C" {
// TODO: figure out the API for tiled blob images.
fn wr_moz2d_render_cb(blob: WrByteSlice,
width: u32,
height: u32,
format: WrImageFormat,
output: MutByteSlice)
-> bool;
pub fn wr_moz2d_render_cb(blob: WrByteSlice,
width: u32,
height: u32,
format: WrImageFormat,
output: MutByteSlice)
-> bool;
}

View File

@ -9,6 +9,9 @@ extern crate webrender_traits;
extern crate euclid;
extern crate app_units;
extern crate gleam;
extern crate rayon;
extern crate thread_profiler;
#[allow(non_snake_case)]
pub mod bindings;
pub mod moz2d_renderer;

View File

@ -0,0 +1,122 @@
use webrender_traits::*;
use bindings::{WrByteSlice, MutByteSlice, wr_moz2d_render_cb};
use rayon::ThreadPool;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::Arc;
pub struct Moz2dImageRenderer {
blob_commands: HashMap<ImageKey, Arc<BlobImageData>>,
// The images rendered in the current frame (not kept here between frames)
rendered_images: HashMap<BlobImageRequest, Option<BlobImageResult>>,
tx: Sender<(BlobImageRequest, BlobImageResult)>,
rx: Receiver<(BlobImageRequest, BlobImageResult)>,
workers: Arc<ThreadPool>,
}
impl BlobImageRenderer for Moz2dImageRenderer {
fn add(&mut self, key: ImageKey, data: BlobImageData, _tiling: Option<TileSize>) {
self.blob_commands.insert(key, Arc::new(data));
}
fn update(&mut self, key: ImageKey, data: BlobImageData) {
self.blob_commands.insert(key, Arc::new(data));
}
fn delete(&mut self, key: ImageKey) {
self.blob_commands.remove(&key);
}
fn request(&mut self,
request: BlobImageRequest,
descriptor: &BlobImageDescriptor,
_dirty_rect: Option<DeviceUintRect>,
_images: &ImageStore) {
debug_assert!(!self.rendered_images.contains_key(&request));
// TODO: implement tiling.
assert!(request.tile.is_none());
// Add None in the map of rendered images. This makes it possible to differentiate
// between commands that aren't finished yet (entry in the map is equal to None) and
// keys that have never been requested (entry not in the map), which would cause deadlocks
// if we were to block upon receving their result in resolve!
self.rendered_images.insert(request, None);
let tx = self.tx.clone();
let descriptor = descriptor.clone();
let commands = Arc::clone(self.blob_commands.get(&request.key).unwrap());
self.workers.spawn_async(move || {
let buf_size = (descriptor.width
* descriptor.height
* descriptor.format.bytes_per_pixel().unwrap()) as usize;
let mut output = vec![255u8; buf_size];
let result = unsafe {
if wr_moz2d_render_cb(
WrByteSlice::new(&commands[..]),
descriptor.width,
descriptor.height,
descriptor.format,
MutByteSlice::new(output.as_mut_slice())
) {
Ok(RasterizedBlobImage {
width: descriptor.width,
height: descriptor.height,
data: output,
})
} else {
Err(BlobImageError::Other("Unknown error".to_string()))
}
};
tx.send((request, result)).unwrap();
});
}
fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
match self.rendered_images.entry(request) {
Entry::Vacant(_) => {
return Err(BlobImageError::InvalidKey);
}
Entry::Occupied(entry) => {
// None means we haven't yet received the result.
if entry.get().is_some() {
let result = entry.remove();
return result.unwrap();
}
}
}
// We haven't received it yet, pull from the channel until we receive it.
while let Ok((req, result)) = self.rx.recv() {
if req == request {
// There it is!
return result
}
self.rendered_images.insert(req, Some(result));
}
// If we break out of the loop above it means the channel closed unexpectedly.
Err(BlobImageError::Other("Channel closed".into()))
}
}
impl Moz2dImageRenderer {
pub fn new(workers: Arc<ThreadPool>) -> Self {
let (tx, rx) = channel();
Moz2dImageRenderer {
blob_commands: HashMap::new(),
rendered_images: HashMap::new(),
workers: workers,
tx: tx,
rx: rx,
}
}
}

View File

@ -1171,6 +1171,8 @@ dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.40.0",
"webrender_traits 0.40.0",
]

View File

@ -1158,6 +1158,8 @@ dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.40.0",
"webrender_traits 0.40.0",
]