Blame gfx/wrench/src/blob.rs

Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
// A very basic BlobImageRenderer that can only render a checkerboard pattern.
Packit f0b94e
Packit f0b94e
use std::collections::HashMap;
Packit f0b94e
use std::sync::Arc;
Packit f0b94e
use std::sync::Mutex;
Packit f0b94e
use webrender::api::*;
Packit f0b94e
Packit f0b94e
// Serialize/deserialze the blob.
Packit f0b94e
Packit f0b94e
pub fn serialize_blob(color: ColorU) -> Vec<u8> {
Packit f0b94e
    vec![color.r, color.g, color.b, color.a]
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
fn deserialize_blob(blob: &[u8]) -> Result<ColorU, ()> {
Packit f0b94e
    let mut iter = blob.iter();
Packit f0b94e
    return match (iter.next(), iter.next(), iter.next(), iter.next()) {
Packit f0b94e
        (Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(ColorU::new(r, g, b, a)),
Packit f0b94e
        (Some(&a), None, None, None) => Ok(ColorU::new(a, a, a, a)),
Packit f0b94e
        _ => Err(()),
Packit f0b94e
    };
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// This is the function that applies the deserialized drawing commands and generates
Packit f0b94e
// actual image data.
Packit f0b94e
fn render_blob(
Packit f0b94e
    color: ColorU,
Packit f0b94e
    descriptor: &BlobImageDescriptor,
Packit f0b94e
    tile: Option<TileOffset>,
Packit f0b94e
) -> BlobImageResult {
Packit f0b94e
    // Allocate storage for the result. Right now the resource cache expects the
Packit f0b94e
    // tiles to have have no stride or offset.
Packit f0b94e
    let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);
Packit f0b94e
Packit f0b94e
    // Generate a per-tile pattern to see it in the demo. For a real use case it would not
Packit f0b94e
    // make sense for the rendered content to depend on its tile.
Packit f0b94e
    let tile_checker = match tile {
Packit f0b94e
        Some(tile) => (tile.x % 2 == 0) != (tile.y % 2 == 0),
Packit f0b94e
        None => true,
Packit f0b94e
    };
Packit f0b94e
Packit f0b94e
    for y in 0 .. descriptor.height {
Packit f0b94e
        for x in 0 .. descriptor.width {
Packit f0b94e
            // Apply the tile's offset. This is important: all drawing commands should be
Packit f0b94e
            // translated by this offset to give correct results with tiled blob images.
Packit f0b94e
            let x2 = x + descriptor.offset.x as u32;
Packit f0b94e
            let y2 = y + descriptor.offset.y as u32;
Packit f0b94e
Packit f0b94e
            // Render a simple checkerboard pattern
Packit f0b94e
            let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) {
Packit f0b94e
                1
Packit f0b94e
            } else {
Packit f0b94e
                0
Packit f0b94e
            };
Packit f0b94e
            // ..nested in the per-tile cherkerboard pattern
Packit f0b94e
            let tc = if tile_checker { 0 } else { (1 - checker) * 40 };
Packit f0b94e
Packit f0b94e
            match descriptor.format {
Packit f0b94e
                ImageFormat::BGRA8 => {
Packit f0b94e
                    texels.push(color.b * checker + tc);
Packit f0b94e
                    texels.push(color.g * checker + tc);
Packit f0b94e
                    texels.push(color.r * checker + tc);
Packit f0b94e
                    texels.push(color.a * checker + tc);
Packit f0b94e
                }
Packit f0b94e
                ImageFormat::R8 => {
Packit f0b94e
                    texels.push(color.a * checker + tc);
Packit f0b94e
                }
Packit f0b94e
                _ => {
Packit f0b94e
                    return Err(BlobImageError::Other(
Packit f0b94e
                        format!("Usupported image format {:?}", descriptor.format),
Packit f0b94e
                    ));
Packit f0b94e
                }
Packit f0b94e
            }
Packit f0b94e
        }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    Ok(RasterizedBlobImage {
Packit f0b94e
        data: texels,
Packit f0b94e
        width: descriptor.width,
Packit f0b94e
        height: descriptor.height,
Packit f0b94e
    })
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
pub struct BlobCallbacks {
Packit f0b94e
    pub request: Box<Fn(&BlobImageRequest) + Send + 'static>,
Packit f0b94e
    pub resolve: Box<Fn() + Send + 'static>,
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
impl BlobCallbacks {
Packit f0b94e
    pub fn new() -> Self {
Packit f0b94e
        BlobCallbacks { request: Box::new(|_|()), resolve: Box::new(|| (())) }
Packit f0b94e
    }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
pub struct CheckerboardRenderer {
Packit f0b94e
    image_cmds: HashMap<ImageKey, ColorU>,
Packit f0b94e
    callbacks: Arc<Mutex<BlobCallbacks>>,
Packit f0b94e
Packit f0b94e
    // The images rendered in the current frame (not kept here between frames).
Packit f0b94e
    rendered_images: HashMap<BlobImageRequest, BlobImageResult>,
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
impl CheckerboardRenderer {
Packit f0b94e
    pub fn new(callbacks: Arc<Mutex<BlobCallbacks>>) -> Self {
Packit f0b94e
        CheckerboardRenderer {
Packit f0b94e
            callbacks,
Packit f0b94e
            image_cmds: HashMap::new(),
Packit f0b94e
            rendered_images: HashMap::new(),
Packit f0b94e
        }
Packit f0b94e
    }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
impl BlobImageRenderer for CheckerboardRenderer {
Packit f0b94e
    fn add(&mut self, key: ImageKey, cmds: BlobImageData, _: Option<TileSize>) {
Packit f0b94e
        self.image_cmds
Packit f0b94e
            .insert(key, deserialize_blob(&cmds[..]).unwrap());
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    fn update(&mut self, key: ImageKey, cmds: BlobImageData, _dirty_rect: Option<DeviceUintRect>) {
Packit f0b94e
        // Here, updating is just replacing the current version of the commands with
Packit f0b94e
        // the new one (no incremental updates).
Packit f0b94e
        self.image_cmds
Packit f0b94e
            .insert(key, deserialize_blob(&cmds[..]).unwrap());
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    fn delete(&mut self, key: ImageKey) {
Packit f0b94e
        self.image_cmds.remove(&key);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    fn request(
Packit f0b94e
        &mut self,
Packit f0b94e
        _resources: &BlobImageResources,
Packit f0b94e
        request: BlobImageRequest,
Packit f0b94e
        descriptor: &BlobImageDescriptor,
Packit f0b94e
        _dirty_rect: Option<DeviceUintRect>,
Packit f0b94e
    ) {
Packit f0b94e
        (self.callbacks.lock().unwrap().request)(&request);
Packit f0b94e
        assert!(!self.rendered_images.contains_key(&request));
Packit f0b94e
        // This method is where we kick off our rendering jobs.
Packit f0b94e
        // It should avoid doing work on the calling thread as much as possible.
Packit f0b94e
        // In this example we will use the thread pool to render individual tiles.
Packit f0b94e
Packit f0b94e
        // Gather the input data to send to a worker thread.
Packit f0b94e
        let cmds = self.image_cmds.get(&request.key).unwrap();
Packit f0b94e
Packit f0b94e
        let result = render_blob(*cmds, descriptor, request.tile);
Packit f0b94e
Packit f0b94e
        self.rendered_images.insert(request, result);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
Packit f0b94e
        (self.callbacks.lock().unwrap().resolve)();
Packit f0b94e
        self.rendered_images.remove(&request).unwrap()
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    fn delete_font(&mut self, _key: FontKey) {}
Packit f0b94e
Packit f0b94e
    fn delete_font_instance(&mut self, _key: FontInstanceKey) {}
Packit f0b94e
}