Skip to main content

webrender_api/
image.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#![deny(missing_docs)]
6
7use euclid::{size2, Box2D, num::Zero};
8use peek_poke::PeekPoke;
9use std::ops::{Add, Sub};
10use std::sync::Arc;
11// local imports
12use crate::{IdNamespace, TileSize};
13use crate::font::{FontInstanceKey, FontInstanceData, FontKey, FontTemplate};
14use crate::units::*;
15
16/// The default tile size for blob images and regular images larger than
17/// the maximum texture size.
18pub const DEFAULT_TILE_SIZE: TileSize = 512;
19
20/// An opaque identifier describing an image registered with WebRender.
21/// This is used as a handle to reference images, and is used as the
22/// hash map key for the actual image storage in the `ResourceCache`.
23#[repr(C)]
24#[derive(Clone, Copy, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
25pub struct ImageKey(pub IdNamespace, pub u32);
26
27impl Default for ImageKey {
28    fn default() -> Self {
29        ImageKey::DUMMY
30    }
31}
32
33impl ImageKey {
34    /// Placeholder Image key, used to represent None.
35    pub const DUMMY: Self = ImageKey(IdNamespace(0), 0);
36
37    /// Mints a new ImageKey. The given ID must be unique.
38    pub fn new(namespace: IdNamespace, key: u32) -> Self {
39        ImageKey(namespace, key)
40    }
41}
42
43impl std::fmt::Debug for ImageKey {
44    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
45        if *self == Self::DUMMY {
46            write!(f, "<none>")
47        } else {
48            write!(f, "#{}:{}", self.0.0, self.1)
49        }
50    }
51}
52
53
54/// An opaque identifier describing a blob image registered with WebRender.
55/// This is used as a handle to reference blob images, and can be used as an
56/// image in display items.
57#[repr(C)]
58#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
59pub struct BlobImageKey(pub ImageKey);
60
61impl BlobImageKey {
62    /// Interpret this blob image as an image for a display item.
63    pub fn as_image(self) -> ImageKey {
64        self.0
65    }
66}
67
68/// An opaque identifier describing a snapshot image registered with WebRender.
69/// This is used as a handle to reference snapshot images, and can be used as an
70/// image in display items.
71#[repr(C)]
72#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
73pub struct SnapshotImageKey(pub ImageKey);
74
75impl SnapshotImageKey {
76    /// Interpret this snapshot image as an image for a display item.
77    pub fn as_image(self) -> ImageKey {
78        self.0
79    }
80}
81
82impl Default for SnapshotImageKey {
83    fn default() -> Self {
84        SnapshotImageKey(ImageKey::DUMMY)
85    }
86}
87
88/// An arbitrary identifier for an external image provided by the
89/// application. It must be a unique identifier for each external
90/// image.
91#[repr(C)]
92#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
93pub struct ExternalImageId(pub u64);
94
95/// The source for an external image.
96pub enum ExternalImageSource<'a> {
97    /// A raw pixel buffer.
98    RawData(&'a [u8]),
99    /// A gl::GLuint texture handle.
100    NativeTexture(u32),
101    /// An invalid source.
102    Invalid,
103}
104
105/// The data that an external client should provide about
106/// an external image. For instance, if providing video frames,
107/// the application could call wr.render() whenever a new
108/// video frame is ready. Note that the UV coords are either normalized or
109/// unnormalized depending on the value of normalized_uvs in the corresponding
110/// ExternalImageData.
111pub struct ExternalImage<'a> {
112    /// UV coordinates for the image.
113    pub uv: TexelRect,
114    /// The source for this image's contents.
115    pub source: ExternalImageSource<'a>,
116}
117
118/// The interfaces that an application can implement to support providing
119/// external image buffers.
120/// When the application passes an external image to WR, it should keep that
121/// external image life time. People could check the epoch id in RenderNotifier
122/// at the client side to make sure that the external image is not used by WR.
123/// Then, do the clean up for that external image.
124pub trait ExternalImageHandler {
125    /// Lock the external image. Then, WR could start to read the image content.
126    /// The WR client should not change the image content until the unlock()
127    /// call.
128    fn lock(&mut self, key: ExternalImageId, channel_index: u8, is_composited: bool) -> ExternalImage;
129    /// Unlock the external image. WR should not read the image content
130    /// after this call.
131    fn unlock(&mut self, key: ExternalImageId, channel_index: u8);
132}
133
134/// Specifies the type of texture target in driver terms.
135#[repr(u8)]
136#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
137pub enum ImageBufferKind {
138    /// Standard texture. This maps to GL_TEXTURE_2D in OpenGL.
139    Texture2D = 0,
140    /// Rectangle texture. This maps to GL_TEXTURE_RECTANGLE in OpenGL. This
141    /// is similar to a standard texture, with a few subtle differences
142    /// (no mipmaps, non-power-of-two dimensions, different coordinate space)
143    /// that make it useful for representing the kinds of textures we use
144    /// in WebRender. See https://www.khronos.org/opengl/wiki/Rectangle_Texture
145    /// for background on Rectangle textures.
146    TextureRect = 1,
147    /// External texture. This maps to GL_TEXTURE_EXTERNAL_OES in OpenGL, which
148    /// is an extension. This is used for image formats that OpenGL doesn't
149    /// understand, particularly YUV. See
150    /// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
151    TextureExternal = 2,
152    /// External texture which is forced to be converted from YUV to RGB using BT709 colorspace.
153    /// This maps to GL_TEXTURE_EXTERNAL_OES in OpenGL, using the EXT_YUV_TARGET extension.
154    /// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_YUV_target.txt
155    TextureExternalBT709 = 3,
156}
157
158/// Storage format identifier for externally-managed images.
159#[repr(u8)]
160#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
161pub enum ExternalImageType {
162    /// The image is texture-backed.
163    TextureHandle(ImageBufferKind),
164    /// The image is heap-allocated by the embedding.
165    Buffer,
166}
167
168/// Descriptor for external image resources. See `ImageData`.
169#[repr(C)]
170#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
171pub struct ExternalImageData {
172    /// The identifier of this external image, provided by the embedding.
173    pub id: ExternalImageId,
174    /// For multi-plane images (i.e. YUV), indicates the plane of the
175    /// original image that this struct represents. 0 for single-plane images.
176    pub channel_index: u8,
177    /// Storage format identifier.
178    pub image_type: ExternalImageType,
179    /// Whether UV coordinates used with this image are normalized.
180    pub normalized_uvs: bool,
181}
182
183/// Specifies the format of a series of pixels, in driver terms.
184#[repr(u8)]
185#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
186pub enum ImageFormat {
187    /// One-channel, byte storage. The "red" doesn't map to the color
188    /// red per se, and is just the way that OpenGL has historically referred
189    /// to single-channel buffers.
190    R8 = 1,
191    /// One-channel, short storage
192    R16 = 2,
193    /// Four channels, byte storage.
194    BGRA8 = 3,
195    /// Four channels, float storage.
196    RGBAF32 = 4,
197    /// Two-channels, byte storage. Similar to `R8`, this just means
198    /// "two channels" rather than "red and green".
199    RG8 = 5,
200    /// Two-channels, short storage. Similar to `R16`, this just means
201    /// "two channels" rather than "red and green".
202    RG16 = 6,
203
204    /// Four channels, signed integer storage.
205    RGBAI32 = 7,
206    /// Four channels, byte storage.
207    RGBA8 = 8,
208}
209
210impl ImageFormat {
211    /// Returns the number of bytes per pixel for the given format.
212    pub fn bytes_per_pixel(self) -> i32 {
213        match self {
214            ImageFormat::R8 => 1,
215            ImageFormat::R16 => 2,
216            ImageFormat::BGRA8 => 4,
217            ImageFormat::RGBAF32 => 16,
218            ImageFormat::RG8 => 2,
219            ImageFormat::RG16 => 4,
220            ImageFormat::RGBAI32 => 16,
221            ImageFormat::RGBA8 => 4,
222        }
223    }
224}
225
226/// Specifies the color depth of an image. Currently only used for YUV images.
227#[repr(u8)]
228#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
229pub enum ColorDepth {
230    /// 8 bits image (most common)
231    #[default]
232    Color8,
233    /// 10 bits image
234    Color10,
235    /// 12 bits image
236    Color12,
237    /// 16 bits image
238    Color16,
239}
240
241impl ColorDepth {
242    /// Return the numerical bit depth value for the type.
243    pub fn bit_depth(self) -> u32 {
244        match self {
245            ColorDepth::Color8 => 8,
246            ColorDepth::Color10 => 10,
247            ColorDepth::Color12 => 12,
248            ColorDepth::Color16 => 16,
249        }
250    }
251    /// 10 and 12 bits images are encoded using 16 bits integer, we need to
252    /// rescale the 10 or 12 bits value to extend to 16 bits.
253    pub fn rescaling_factor(self) -> f32 {
254        match self {
255            ColorDepth::Color8 => 1.0,
256            ColorDepth::Color10 => 64.0,
257            ColorDepth::Color12 => 16.0,
258            ColorDepth::Color16 => 1.0,
259        }
260    }
261}
262
263bitflags! {
264    /// Various flags that are part of an image descriptor.
265    #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, Serialize)]
266    pub struct ImageDescriptorFlags: u32 {
267        /// Whether this image is opaque, or has an alpha channel. Avoiding blending
268        /// for opaque surfaces is an important optimization.
269        const IS_OPAQUE = 1;
270        /// Whether to allow the driver to automatically generate mipmaps. If images
271        /// are already downscaled appropriately, mipmap generation can be wasted
272        /// work, and cause performance problems on some cards/drivers.
273        ///
274        /// See https://github.com/servo/webrender/pull/2555/
275        const ALLOW_MIPMAPS = 2;
276    }
277}
278
279/// Metadata (but not storage) describing an image In WebRender.
280#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
281pub struct ImageDescriptor {
282    /// Format of the image data.
283    pub format: ImageFormat,
284    /// Width and length of the image data, in pixels.
285    pub size: DeviceIntSize,
286    /// The number of bytes from the start of one row to the next. If non-None,
287    /// `compute_stride` will return this value, otherwise it returns
288    /// `width * bpp`. Different source of images have different alignment
289    /// constraints for rows, so the stride isn't always equal to width * bpp.
290    pub stride: Option<i32>,
291    /// Offset in bytes of the first pixel of this image in its backing buffer.
292    /// This is used for tiling, wherein WebRender extracts chunks of input images
293    /// in order to cache, manipulate, and render them individually. This offset
294    /// tells the texture upload machinery where to find the bytes to upload for
295    /// this tile. Non-tiled images generally set this to zero.
296    pub offset: i32,
297    /// Various bool flags related to this descriptor.
298    pub flags: ImageDescriptorFlags,
299}
300
301impl ImageDescriptor {
302    /// Mints a new ImageDescriptor.
303    pub fn new(
304        width: i32,
305        height: i32,
306        format: ImageFormat,
307        flags: ImageDescriptorFlags,
308    ) -> Self {
309        ImageDescriptor {
310            size: size2(width, height),
311            format,
312            stride: None,
313            offset: 0,
314            flags,
315        }
316    }
317
318    /// Returns the stride, either via an explicit stride stashed on the object
319    /// or by the default computation.
320    pub fn compute_stride(&self) -> i32 {
321        self.stride.unwrap_or(self.size.width * self.format.bytes_per_pixel())
322    }
323
324    /// Computes the total size of the image, in bytes.
325    pub fn compute_total_size(&self) -> i32 {
326        self.compute_stride() * self.size.height
327    }
328
329    /// Computes the bounding rectangle for the image, rooted at (0, 0).
330    pub fn full_rect(&self) -> DeviceIntRect {
331        DeviceIntRect::from_origin_and_size(
332            DeviceIntPoint::zero(),
333            self.size,
334        )
335    }
336
337    /// Returns true if this descriptor is opaque
338    pub fn is_opaque(&self) -> bool {
339        self.flags.contains(ImageDescriptorFlags::IS_OPAQUE)
340    }
341
342    /// Returns true if this descriptor allows mipmaps
343    pub fn allow_mipmaps(&self) -> bool {
344        self.flags.contains(ImageDescriptorFlags::ALLOW_MIPMAPS)
345    }
346}
347
348/// Represents the backing store of an arbitrary series of pixels for display by
349/// WebRender. This storage can take several forms.
350#[derive(Clone, Debug, Serialize, Deserialize)]
351pub enum ImageData {
352    /// A simple series of bytes, provided by the embedding and owned by WebRender.
353    /// The format is stored out-of-band, currently in ImageDescriptor.
354    Raw(#[serde(with = "serde_image_data_raw")] Arc<Vec<u8>>),
355    /// An image owned by the embedding, and referenced by WebRender. This may
356    /// take the form of a texture or a heap-allocated buffer.
357    External(ExternalImageData),
358}
359
360mod serde_image_data_raw {
361    extern crate serde_bytes;
362
363    use std::sync::Arc;
364    use serde::{Deserializer, Serializer};
365
366    pub fn serialize<S: Serializer>(bytes: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error> {
367        serde_bytes::serialize(bytes.as_slice(), serializer)
368    }
369
370    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error> {
371        serde_bytes::deserialize(deserializer).map(Arc::new)
372    }
373}
374
375impl ImageData {
376    /// Mints a new raw ImageData, taking ownership of the bytes.
377    pub fn new(bytes: Vec<u8>) -> Self {
378        ImageData::Raw(Arc::new(bytes))
379    }
380
381    /// Mints a new raw ImageData from Arc-ed bytes.
382    pub fn new_shared(bytes: Arc<Vec<u8>>) -> Self {
383        ImageData::Raw(bytes)
384    }
385}
386
387/// The resources exposed by the resource cache available for use by the blob rasterizer.
388pub trait BlobImageResources {
389    /// Returns the `FontTemplate` for the given key.
390    fn get_font_data(&self, key: FontKey) -> Option<FontTemplate>;
391    /// Returns the `FontInstanceData` for the given key, if found.
392    fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData>;
393}
394
395/// A handler on the render backend that can create rasterizer objects which will
396/// be sent to the scene builder thread to execute the rasterization.
397///
398/// The handler is responsible for collecting resources, managing/updating blob commands
399/// and creating the rasterizer objects, but isn't expected to do any rasterization itself.
400pub trait BlobImageHandler: Send {
401    /// Creates a snapshot of the current state of blob images in the handler.
402    fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer>;
403
404    /// Creates an empty blob handler of the same type.
405    ///
406    /// This is used to allow creating new API endpoints with blob handlers installed on them.
407    fn create_similar(&self) -> Box<dyn BlobImageHandler>;
408
409    /// A hook to let the blob image handler update any state related to resources that
410    /// are not bundled in the blob recording itself.
411    fn prepare_resources(
412        &mut self,
413        services: &dyn BlobImageResources,
414        requests: &[BlobImageParams],
415    );
416
417    /// Register a blob image.
418    fn add(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, visible_rect: &DeviceIntRect,
419           tile_size: TileSize);
420
421    /// Update an already registered blob image.
422    fn update(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, visible_rect: &DeviceIntRect,
423              dirty_rect: &BlobDirtyRect);
424
425    /// Delete an already registered blob image.
426    fn delete(&mut self, key: BlobImageKey);
427
428    /// A hook to let the handler clean up any state related to a font which the resource
429    /// cache is about to delete.
430    fn delete_font(&mut self, key: FontKey);
431
432    /// A hook to let the handler clean up any state related to a font instance which the
433    /// resource cache is about to delete.
434    fn delete_font_instance(&mut self, key: FontInstanceKey);
435
436    /// A hook to let the handler clean up any state related a given namespace before the
437    /// resource cache deletes them.
438    fn clear_namespace(&mut self, namespace: IdNamespace);
439
440    /// Whether to allow rendering blobs on multiple threads.
441    fn enable_multithreading(&mut self, enable: bool);
442}
443
444/// A group of rasterization requests to execute synchronously on the scene builder thread.
445pub trait AsyncBlobImageRasterizer : Send {
446    /// Rasterize the requests.
447    ///
448    /// Gecko uses te priority hint to schedule work in a way that minimizes the risk
449    /// of high priority work being blocked by (or enqued behind) low priority work.
450    fn rasterize(
451        &mut self,
452        requests: &[BlobImageParams],
453        low_priority: bool,
454        tile_pool: &mut crate::BlobTilePool,
455    ) -> Vec<(BlobImageRequest, BlobImageResult)>;
456}
457
458
459/// Input parameters for the BlobImageRasterizer.
460#[derive(Copy, Clone, Debug)]
461pub struct BlobImageParams {
462    /// A key that identifies the blob image rasterization request.
463    pub request: BlobImageRequest,
464    /// Description of the format of the blob's output image.
465    pub descriptor: BlobImageDescriptor,
466    /// An optional sub-rectangle of the image to avoid re-rasterizing
467    /// the entire image when only a portion is updated.
468    ///
469    /// If set to None the entire image is rasterized.
470    pub dirty_rect: BlobDirtyRect,
471}
472
473/// The possible states of a Dirty rect.
474///
475/// This exists because people kept getting confused with `Option<Box2D>`.
476#[derive(Debug, Serialize, Deserialize)]
477pub enum DirtyRect<T: Copy, U> {
478    /// Everything is Dirty, equivalent to Partial(image_bounds)
479    All,
480    /// Some specific amount is dirty
481    Partial(Box2D<T, U>)
482}
483
484impl<T, U> DirtyRect<T, U>
485where
486    T: Copy + Clone
487        + PartialOrd + PartialEq
488        + Add<T, Output = T>
489        + Sub<T, Output = T>
490        + Zero
491{
492    /// Creates an empty DirtyRect (indicating nothing is invalid)
493    pub fn empty() -> Self {
494        DirtyRect::Partial(Box2D::zero())
495    }
496
497    /// Returns whether the dirty rect is empty
498    pub fn is_empty(&self) -> bool {
499        match self {
500            DirtyRect::All => false,
501            DirtyRect::Partial(rect) => rect.is_empty(),
502        }
503    }
504
505    /// Replaces self with the empty rect and returns the old value.
506    pub fn replace_with_empty(&mut self) -> Self {
507        ::std::mem::replace(self, DirtyRect::empty())
508    }
509
510    /// Maps over the contents of Partial.
511    pub fn map<F>(self, func: F) -> Self
512        where F: FnOnce(Box2D<T, U>) -> Box2D<T, U>,
513    {
514        use crate::DirtyRect::*;
515
516        match self {
517            All        => All,
518            Partial(rect) => Partial(func(rect)),
519        }
520    }
521
522    /// Unions the dirty rects.
523    pub fn union(&self, other: &Self) -> Self {
524        use crate::DirtyRect::*;
525
526        match (*self, *other) {
527            (All, _) | (_, All)        => All,
528            (Partial(rect1), Partial(rect2)) => Partial(rect1.union(&rect2)),
529        }
530    }
531
532    /// Intersects the dirty rects.
533    pub fn intersection(&self, other: &Self) -> Self {
534        use crate::DirtyRect::*;
535
536        match (*self, *other) {
537            (All, rect) | (rect, All)  => rect,
538            (Partial(rect1), Partial(rect2)) => {
539                Partial(rect1.intersection(&rect2).unwrap_or_else(Box2D::zero))
540            }
541        }
542    }
543
544    /// Converts the dirty rect into a subrect of the given one via intersection.
545    pub fn to_subrect_of(&self, rect: &Box2D<T, U>) -> Box2D<T, U> {
546        use crate::DirtyRect::*;
547
548        match *self {
549            All => *rect,
550            Partial(dirty_rect) => {
551                dirty_rect.intersection(rect).unwrap_or_else(Box2D::zero)
552            }
553        }
554    }
555}
556
557impl<T: Copy, U> Copy for DirtyRect<T, U> {}
558impl<T: Copy, U> Clone for DirtyRect<T, U> {
559    fn clone(&self) -> Self { *self }
560}
561
562impl<T: Copy, U> From<Box2D<T, U>> for DirtyRect<T, U> {
563    fn from(rect: Box2D<T, U>) -> Self {
564        DirtyRect::Partial(rect)
565    }
566}
567
568/// Backing store for blob image command streams.
569pub type BlobImageData = Vec<u8>;
570
571/// Result type for blob raserization.
572pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;
573
574/// Metadata (but not storage) for a blob image.
575#[repr(C)]
576#[derive(Copy, Clone, Debug)]
577pub struct BlobImageDescriptor {
578    /// Surface of the image or tile to render in the same coordinate space as
579    /// the drawing commands.
580    pub rect: LayoutIntRect,
581    /// Format for the data in the backing store.
582    pub format: ImageFormat,
583}
584
585/// Representation of a rasterized blob image. This is obtained by passing
586/// `BlobImageData` to the embedding via the rasterization callback.
587pub struct RasterizedBlobImage {
588    /// The rectangle that was rasterized in device pixels, relative to the
589    /// image or tile.
590    pub rasterized_rect: DeviceIntRect,
591    /// Backing store. The format is stored out of band in `BlobImageDescriptor`.
592    pub data: Arc<Vec<u8>>,
593}
594
595/// Error code for when blob rasterization failed.
596#[derive(Clone, Debug)]
597pub enum BlobImageError {
598    /// Out of memory.
599    Oom,
600    /// Other failure, embedding-specified.
601    Other(String),
602}
603
604
605
606/// A key identifying blob image rasterization work requested from the blob
607/// image rasterizer.
608#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
609pub struct BlobImageRequest {
610    /// Unique handle to the image.
611    pub key: BlobImageKey,
612    /// Tiling offset in number of tiles.
613    pub tile: TileOffset,
614}