diff options
Diffstat (limited to 'third_party/webrender/examples/blob.rs')
-rw-r--r-- | third_party/webrender/examples/blob.rs | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/third_party/webrender/examples/blob.rs b/third_party/webrender/examples/blob.rs deleted file mode 100644 index 65c048c87be..00000000000 --- a/third_party/webrender/examples/blob.rs +++ /dev/null @@ -1,290 +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/. */ - -extern crate gleam; -extern crate glutin; -extern crate rayon; -extern crate webrender; -extern crate winit; - -#[path = "common/boilerplate.rs"] -mod boilerplate; - -use crate::boilerplate::{Example, HandyDandyRectBuilder}; -use rayon::{ThreadPool, ThreadPoolBuilder}; -use rayon::prelude::*; -use std::collections::HashMap; -use std::sync::Arc; -use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, PrimitiveFlags}; -use webrender::api::{ColorF, CommonItemProperties, SpaceAndClipInfo, ImageDescriptorFlags}; -use webrender::api::units::*; -use webrender::render_api::*; -use webrender::euclid::size2; - -// This example shows how to implement a very basic BlobImageHandler that can only render -// a checkerboard pattern. - -// The deserialized command list internally used by this example is just a color. -type ImageRenderingCommands = api::ColorU; - -// Serialize/deserialize the blob. -// For real usecases you should probably use serde rather than doing it by hand. - -fn serialize_blob(color: api::ColorU) -> Arc<Vec<u8>> { - Arc::new(vec![color.r, color.g, color.b, color.a]) -} - -fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> { - let mut iter = blob.iter(); - return match (iter.next(), iter.next(), iter.next(), iter.next()) { - (Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(api::ColorU::new(r, g, b, a)), - (Some(&a), None, None, None) => Ok(api::ColorU::new(a, a, a, a)), - _ => Err(()), - }; -} - -// This is the function that applies the deserialized drawing commands and generates -// actual image data. -fn render_blob( - commands: Arc<ImageRenderingCommands>, - descriptor: &api::BlobImageDescriptor, - tile: TileOffset, -) -> api::BlobImageResult { - let color = *commands; - - // Note: This implementation ignores the dirty rect which isn't incorrect - // but is a missed optimization. - - // Allocate storage for the result. Right now the resource cache expects the - // tiles to have have no stride or offset. - let bpp = 4; - let mut texels = Vec::with_capacity((descriptor.rect.size.area() * bpp) as usize); - - // Generate a per-tile pattern to see it in the demo. For a real use case it would not - // make sense for the rendered content to depend on its tile. - let tile_checker = (tile.x % 2 == 0) != (tile.y % 2 == 0); - - let [w, h] = descriptor.rect.size.to_array(); - let offset = descriptor.rect.origin; - - for y in 0..h { - for x in 0..w { - // Apply the tile's offset. This is important: all drawing commands should be - // translated by this offset to give correct results with tiled blob images. - let x2 = x + offset.x; - let y2 = y + offset.y; - - // Render a simple checkerboard pattern - let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) { - 1 - } else { - 0 - }; - // ..nested in the per-tile checkerboard pattern - let tc = if tile_checker { 0 } else { (1 - checker) * 40 }; - - match descriptor.format { - api::ImageFormat::BGRA8 => { - texels.push(color.b * checker + tc); - texels.push(color.g * checker + tc); - texels.push(color.r * checker + tc); - texels.push(color.a * checker + tc); - } - api::ImageFormat::R8 => { - texels.push(color.a * checker + tc); - } - _ => { - return Err(api::BlobImageError::Other( - format!("Unsupported image format"), - )); - } - } - } - } - - Ok(api::RasterizedBlobImage { - data: Arc::new(texels), - rasterized_rect: size2(w, h).into(), - }) -} - -struct CheckerboardRenderer { - // We are going to defer the rendering work to worker threads. - // Using a pre-built Arc<ThreadPool> rather than creating our own threads - // makes it possible to share the same thread pool as the glyph renderer (if we - // want to). - workers: Arc<ThreadPool>, - - // The deserialized drawing commands. - // In this example we store them in Arcs. This isn't necessary since in this simplified - // case the command list is a simple 32 bits value and would be cheap to clone before sending - // to the workers. But in a more realistic scenario the commands would typically be bigger - // and more expensive to clone, so let's pretend it is also the case here. - image_cmds: HashMap<api::BlobImageKey, Arc<ImageRenderingCommands>>, -} - -impl CheckerboardRenderer { - fn new(workers: Arc<ThreadPool>) -> Self { - CheckerboardRenderer { - image_cmds: HashMap::new(), - workers, - } - } -} - -impl api::BlobImageHandler for CheckerboardRenderer { - fn create_similar(&self) -> Box<dyn api::BlobImageHandler> { - Box::new(CheckerboardRenderer::new(Arc::clone(&self.workers))) - } - - fn add(&mut self, key: api::BlobImageKey, cmds: Arc<api::BlobImageData>, - _visible_rect: &DeviceIntRect, _: api::TileSize) { - self.image_cmds - .insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap())); - } - - fn update(&mut self, key: api::BlobImageKey, cmds: Arc<api::BlobImageData>, - _visible_rect: &DeviceIntRect, _dirty_rect: &BlobDirtyRect) { - // Here, updating is just replacing the current version of the commands with - // the new one (no incremental updates). - self.image_cmds - .insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap())); - } - - fn delete(&mut self, key: api::BlobImageKey) { - self.image_cmds.remove(&key); - } - - fn prepare_resources( - &mut self, - _services: &dyn api::BlobImageResources, - _requests: &[api::BlobImageParams], - ) {} - - fn enable_multithreading(&mut self, _: bool) {} - fn delete_font(&mut self, _font: api::FontKey) {} - fn delete_font_instance(&mut self, _instance: api::FontInstanceKey) {} - fn clear_namespace(&mut self, _namespace: api::IdNamespace) {} - fn create_blob_rasterizer(&mut self) -> Box<dyn api::AsyncBlobImageRasterizer> { - Box::new(Rasterizer { - workers: Arc::clone(&self.workers), - image_cmds: self.image_cmds.clone(), - }) - } -} - -struct Rasterizer { - workers: Arc<ThreadPool>, - image_cmds: HashMap<api::BlobImageKey, Arc<ImageRenderingCommands>>, -} - -impl api::AsyncBlobImageRasterizer for Rasterizer { - fn rasterize( - &mut self, - requests: &[api::BlobImageParams], - _low_priority: bool - ) -> Vec<(api::BlobImageRequest, api::BlobImageResult)> { - let requests: Vec<(&api::BlobImageParams, Arc<ImageRenderingCommands>)> = requests.into_iter().map(|params| { - (params, Arc::clone(&self.image_cmds[¶ms.request.key])) - }).collect(); - - self.workers.install(|| { - requests.into_par_iter().map(|(params, commands)| { - (params.request, render_blob(commands, ¶ms.descriptor, params.request.tile)) - }).collect() - }) - } -} - -struct App {} - -impl Example for App { - fn render( - &mut self, - api: &mut RenderApi, - builder: &mut DisplayListBuilder, - txn: &mut Transaction, - _device_size: DeviceIntSize, - pipeline_id: PipelineId, - _document_id: DocumentId, - ) { - let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); - - builder.push_simple_stacking_context( - LayoutPoint::zero(), - space_and_clip.spatial_id, - PrimitiveFlags::IS_BACKFACE_VISIBLE, - ); - - let size1 = DeviceIntSize::new(500, 500); - let blob_img1 = api.generate_blob_image_key(); - txn.add_blob_image( - blob_img1, - api::ImageDescriptor::new( - size1.width, - size1.height, - api::ImageFormat::BGRA8, - ImageDescriptorFlags::IS_OPAQUE, - ), - serialize_blob(api::ColorU::new(50, 50, 150, 255)), - size1.into(), - Some(128), - ); - let bounds = (30, 30).by(size1.width, size1.height); - builder.push_image( - &CommonItemProperties::new(bounds, space_and_clip), - bounds, - api::ImageRendering::Auto, - api::AlphaType::PremultipliedAlpha, - blob_img1.as_image(), - ColorF::WHITE, - ); - - let size2 = DeviceIntSize::new(256, 256); - let blob_img2 = api.generate_blob_image_key(); - txn.add_blob_image( - blob_img2, - api::ImageDescriptor::new( - size2.width, - size2.height, - api::ImageFormat::BGRA8, - ImageDescriptorFlags::IS_OPAQUE, - ), - serialize_blob(api::ColorU::new(50, 150, 50, 255)), - size2.into(), - None, - ); - let bounds = (600, 600).by(size2.width, size2.height); - builder.push_image( - &CommonItemProperties::new(bounds, space_and_clip), - bounds, - api::ImageRendering::Auto, - api::AlphaType::PremultipliedAlpha, - blob_img2.as_image(), - ColorF::WHITE, - ); - - builder.pop_stacking_context(); - } -} - -fn main() { - let workers = - ThreadPoolBuilder::new().thread_name(|idx| format!("WebRender:Worker#{}", idx)) - .build(); - - let workers = Arc::new(workers.unwrap()); - - let opts = webrender::RendererOptions { - workers: Some(Arc::clone(&workers)), - // Register our blob renderer, so that WebRender integrates it in the resource cache.. - // Share the same pool of worker threads between WebRender and our blob renderer. - blob_image_handler: Some(Box::new(CheckerboardRenderer::new(Arc::clone(&workers)))), - ..Default::default() - }; - - let mut app = App {}; - - boilerplate::main_wrapper(&mut app, Some(opts)); -} |