mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1370891 - Render blob images in webrender's thread pool. r=jrmuizel
This commit is contained in:
parent
3869f41093
commit
fa4995fa8f
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
122
gfx/webrender_bindings/src/moz2d_renderer.rs
Normal file
122
gfx/webrender_bindings/src/moz2d_renderer.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
toolkit/library/gtest/rust/Cargo.lock
generated
2
toolkit/library/gtest/rust/Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
2
toolkit/library/rust/Cargo.lock
generated
2
toolkit/library/rust/Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user