tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vertex.rs (22469B)


      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 //! Rendering logic related to the vertex shaders and their states, uncluding
      6 //!  - Vertex Array Objects
      7 //!  - vertex layout descriptors
      8 //!  - textures bound at vertex stage
      9 
     10 use std::{marker::PhantomData, mem, num::NonZeroUsize, ops};
     11 use api::units::*;
     12 use crate::{
     13    device::{
     14        Device, Texture, TextureFilter, TextureUploader, UploadPBOPool, VertexUsageHint, VAO,
     15    },
     16    frame_builder::Frame,
     17    gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF, TransformData},
     18    internal_types::Swizzle,
     19    render_task::RenderTaskData,
     20 };
     21 
     22 use crate::internal_types::FrameVec;
     23 
     24 pub const VERTEX_TEXTURE_EXTRA_ROWS: i32 = 10;
     25 
     26 pub const MAX_VERTEX_TEXTURE_WIDTH: usize = webrender_build::MAX_VERTEX_TEXTURE_WIDTH;
     27 
     28 pub mod desc {
     29    use crate::device::{VertexAttribute, VertexAttributeKind, VertexDescriptor};
     30 
     31    pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor {
     32        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     33        instance_attributes: &[VertexAttribute {
     34            name: "aData",
     35            count: 4,
     36            kind: VertexAttributeKind::I32,
     37        }],
     38    };
     39 
     40    pub const BLUR: VertexDescriptor = VertexDescriptor {
     41        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     42        instance_attributes: &[
     43            VertexAttribute::gpu_buffer_address("aBlurRenderTaskAddress"),
     44            VertexAttribute::gpu_buffer_address("aBlurSourceTaskAddress"),
     45            VertexAttribute::i32("aBlurDirection"),
     46            VertexAttribute::i32("aBlurEdgeMode"),
     47            VertexAttribute::f32x3("aBlurParams"),
     48        ],
     49    };
     50 
     51    pub const LINE: VertexDescriptor = VertexDescriptor {
     52        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     53        instance_attributes: &[
     54            VertexAttribute::f32x4("aTaskRect"),
     55            VertexAttribute::f32x2("aLocalSize"),
     56            VertexAttribute::f32("aWavyLineThickness"),
     57            VertexAttribute::i32("aStyle"),
     58            VertexAttribute::f32("aAxisSelect"),
     59        ],
     60    };
     61 
     62    pub const FAST_LINEAR_GRADIENT: VertexDescriptor = VertexDescriptor {
     63        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     64        instance_attributes: &[
     65            VertexAttribute::f32x4("aTaskRect"),
     66            VertexAttribute::f32x4("aColor0"),
     67            VertexAttribute::f32x4("aColor1"),
     68            VertexAttribute::f32("aAxisSelect"),
     69        ],
     70    };
     71 
     72    pub const LINEAR_GRADIENT: VertexDescriptor = VertexDescriptor {
     73        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     74        instance_attributes: &[
     75            VertexAttribute::f32x4("aTaskRect"),
     76            VertexAttribute::f32x2("aStartPoint"),
     77            VertexAttribute::f32x2("aEndPoint"),
     78            VertexAttribute::f32x2("aScale"),
     79            VertexAttribute::i32("aExtendMode"),
     80            VertexAttribute::gpu_buffer_address("aGradientStopsAddress"),
     81        ],
     82    };
     83 
     84    pub const RADIAL_GRADIENT: VertexDescriptor = VertexDescriptor {
     85        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
     86        instance_attributes: &[
     87            VertexAttribute::f32x4("aTaskRect"),
     88            VertexAttribute::f32x2("aCenter"),
     89            VertexAttribute::f32x2("aScale"),
     90            VertexAttribute::f32("aStartRadius"),
     91            VertexAttribute::f32("aEndRadius"),
     92            VertexAttribute::f32("aXYRatio"),
     93            VertexAttribute::i32("aExtendMode"),
     94            VertexAttribute::i32("aGradientStopsAddress"),
     95        ],
     96    };
     97 
     98    pub const CONIC_GRADIENT: VertexDescriptor = VertexDescriptor {
     99        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    100        instance_attributes: &[
    101            VertexAttribute::f32x4("aTaskRect"),
    102            VertexAttribute::f32x2("aCenter"),
    103            VertexAttribute::f32x2("aScale"),
    104            VertexAttribute::f32("aStartOffset"),
    105            VertexAttribute::f32("aEndOffset"),
    106            VertexAttribute::f32("aAngle"),
    107            VertexAttribute::i32("aExtendMode"),
    108            VertexAttribute::gpu_buffer_address("aGradientStopsAddress"),
    109        ],
    110    };
    111 
    112    pub const BORDER: VertexDescriptor = VertexDescriptor {
    113        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    114        instance_attributes: &[
    115            VertexAttribute::f32x2("aTaskOrigin"),
    116            VertexAttribute::f32x4("aRect"),
    117            VertexAttribute::f32x4("aColor0"),
    118            VertexAttribute::f32x4("aColor1"),
    119            VertexAttribute::i32("aFlags"),
    120            VertexAttribute::f32x2("aWidths"),
    121            VertexAttribute::f32x2("aRadii"),
    122            VertexAttribute::f32x4("aClipParams1"),
    123            VertexAttribute::f32x4("aClipParams2"),
    124        ],
    125    };
    126 
    127    pub const SCALE: VertexDescriptor = VertexDescriptor {
    128        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    129        instance_attributes: &[
    130            VertexAttribute::f32x4("aScaleTargetRect"),
    131            VertexAttribute::f32x4("aScaleSourceRect"),
    132            VertexAttribute::f32("aSourceRectType"),
    133        ],
    134    };
    135 
    136    pub const CLIP_RECT: VertexDescriptor = VertexDescriptor {
    137        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    138        instance_attributes: &[
    139            // common clip attributes
    140            VertexAttribute::f32x4("aClipDeviceArea"),
    141            VertexAttribute::f32x4("aClipOrigins"),
    142            VertexAttribute::f32("aDevicePixelScale"),
    143            VertexAttribute::i32x2("aTransformIds"),
    144            // specific clip attributes
    145            VertexAttribute::f32x2("aClipLocalPos"),
    146            VertexAttribute::f32x4("aClipLocalRect"),
    147            VertexAttribute::f32("aClipMode"),
    148            VertexAttribute::f32x4("aClipRect_TL"),
    149            VertexAttribute::f32x4("aClipRadii_TL"),
    150            VertexAttribute::f32x4("aClipRect_TR"),
    151            VertexAttribute::f32x4("aClipRadii_TR"),
    152            VertexAttribute::f32x4("aClipRect_BL"),
    153            VertexAttribute::f32x4("aClipRadii_BL"),
    154            VertexAttribute::f32x4("aClipRect_BR"),
    155            VertexAttribute::f32x4("aClipRadii_BR"),
    156        ],
    157    };
    158 
    159    pub const CLIP_BOX_SHADOW: VertexDescriptor = VertexDescriptor {
    160        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    161        instance_attributes: &[
    162            // common clip attributes
    163            VertexAttribute::f32x4("aClipDeviceArea"),
    164            VertexAttribute::f32x4("aClipOrigins"),
    165            VertexAttribute::f32("aDevicePixelScale"),
    166            VertexAttribute::i32x2("aTransformIds"),
    167            // specific clip attributes
    168            VertexAttribute::gpu_buffer_address("aClipDataResourceAddress"),
    169            VertexAttribute::f32x2("aClipSrcRectSize"),
    170            VertexAttribute::i32("aClipMode"),
    171            VertexAttribute::i32x2("aStretchMode"),
    172            VertexAttribute::f32x4("aClipDestRect"),
    173        ],
    174    };
    175 
    176    pub const SVG_FILTER_NODE: VertexDescriptor = VertexDescriptor {
    177        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    178        instance_attributes: &[
    179            VertexAttribute::f32x4("aFilterTargetRect"),
    180            VertexAttribute::f32x4("aFilterInput1ContentScaleAndOffset"),
    181            VertexAttribute::f32x4("aFilterInput2ContentScaleAndOffset"),
    182            VertexAttribute::gpu_buffer_address("aFilterInput1TaskAddress"),
    183            VertexAttribute::gpu_buffer_address("aFilterInput2TaskAddress"),
    184            VertexAttribute::u16("aFilterKind"),
    185            VertexAttribute::u16("aFilterInputCount"),
    186            VertexAttribute::gpu_buffer_address("aFilterExtraDataAddress"),
    187        ],
    188    };
    189 
    190    pub const MASK: VertexDescriptor = VertexDescriptor {
    191        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    192        instance_attributes: &[
    193            VertexAttribute::i32x4("aData"),
    194            VertexAttribute::i32x4("aClipData"),
    195        ],
    196    };
    197 
    198    pub const COMPOSITE: VertexDescriptor = VertexDescriptor {
    199        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    200        instance_attributes: &[
    201            VertexAttribute::f32x4("aDeviceRect"),
    202            VertexAttribute::f32x4("aDeviceClipRect"),
    203            VertexAttribute::f32x4("aColor"),
    204            VertexAttribute::f32x4("aParams"),
    205            VertexAttribute::f32x4("aUvRect0"),
    206            VertexAttribute::f32x4("aUvRect1"),
    207            VertexAttribute::f32x4("aUvRect2"),
    208            VertexAttribute::f32x2("aFlip"),
    209            VertexAttribute::f32x4("aDeviceRoundedClipRect"),
    210            VertexAttribute::f32x4("aDeviceRoundedClipRadii"),
    211        ],
    212    };
    213 
    214    pub const CLEAR: VertexDescriptor = VertexDescriptor {
    215        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    216        instance_attributes: &[
    217            VertexAttribute::f32x4("aRect"),
    218            VertexAttribute::f32x4("aColor"),
    219        ],
    220    };
    221 
    222    pub const COPY: VertexDescriptor = VertexDescriptor {
    223        vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
    224        instance_attributes: &[
    225            VertexAttribute::f32x4("a_src_rect"),
    226            VertexAttribute::f32x4("a_dst_rect"),
    227            VertexAttribute::f32x2("a_dst_texture_size"),
    228        ],
    229    };
    230 }
    231 
    232 #[derive(Debug, Copy, Clone, PartialEq)]
    233 pub enum VertexArrayKind {
    234    Primitive,
    235    Blur,
    236    ClipRect,
    237    ClipBoxShadow,
    238    Border,
    239    Scale,
    240    LineDecoration,
    241    FastLinearGradient,
    242    LinearGradient,
    243    RadialGradient,
    244    ConicGradient,
    245    SvgFilterNode,
    246    Composite,
    247    Clear,
    248    Copy,
    249    Mask,
    250 }
    251 
    252 pub struct VertexDataTexture<T> {
    253    texture: Option<Texture>,
    254    format: api::ImageFormat,
    255    _marker: PhantomData<T>,
    256 }
    257 
    258 impl<T> VertexDataTexture<T> {
    259    pub fn new(format: api::ImageFormat) -> Self {
    260        Self {
    261            texture: None,
    262            format,
    263            _marker: PhantomData,
    264        }
    265    }
    266 
    267    /// Returns a borrow of the GPU texture. Panics if it hasn't been initialized.
    268    pub fn texture(&self) -> &Texture {
    269        self.texture.as_ref().unwrap()
    270    }
    271 
    272    /// Returns an estimate of the GPU memory consumed by this VertexDataTexture.
    273    pub fn size_in_bytes(&self) -> usize {
    274        self.texture.as_ref().map_or(0, |t| t.size_in_bytes())
    275    }
    276 
    277    pub fn update<'a>(
    278        &'a mut self,
    279        device: &mut Device,
    280        texture_uploader: &mut TextureUploader<'a>,
    281        data: &mut FrameVec<T>,
    282    ) {
    283        debug_assert!(mem::size_of::<T>() % 16 == 0);
    284        let texels_per_item = mem::size_of::<T>() / 16;
    285        let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item;
    286        debug_assert_ne!(items_per_row, 0);
    287 
    288        // Ensure we always end up with a texture when leaving this method.
    289        let mut len = data.len();
    290        if len == 0 {
    291            if self.texture.is_some() {
    292                return;
    293            }
    294            data.reserve(items_per_row);
    295            len = items_per_row;
    296        } else {
    297            // Extend the data array to have enough capacity to upload at least
    298            // a multiple of the row size.  This ensures memory safety when the
    299            // array is passed to OpenGL to upload to the GPU.
    300            let extra = len % items_per_row;
    301            if extra != 0 {
    302                let padding = items_per_row - extra;
    303                data.reserve(padding);
    304                len += padding;
    305            }
    306        }
    307 
    308        let needed_height = (len / items_per_row) as i32;
    309        let existing_height = self
    310            .texture
    311            .as_ref()
    312            .map_or(0, |t| t.get_dimensions().height);
    313 
    314        // Create a new texture if needed.
    315        //
    316        // These textures are generally very small, which is why we don't bother
    317        // with incremental updates and just re-upload every frame. For most pages
    318        // they're one row each, and on stress tests like css-francine they end up
    319        // in the 6-14 range. So we size the texture tightly to what we need (usually
    320        // 1), and shrink it if the waste would be more than `VERTEX_TEXTURE_EXTRA_ROWS`
    321        // rows. This helps with memory overhead, especially because there are several
    322        // instances of these textures per Renderer.
    323        if needed_height > existing_height
    324            || needed_height + VERTEX_TEXTURE_EXTRA_ROWS < existing_height
    325        {
    326            // Drop the existing texture, if any.
    327            if let Some(t) = self.texture.take() {
    328                device.delete_texture(t);
    329            }
    330 
    331            let texture = device.create_texture(
    332                api::ImageBufferKind::Texture2D,
    333                self.format,
    334                MAX_VERTEX_TEXTURE_WIDTH as i32,
    335                // Ensure height is at least two to work around
    336                // https://bugs.chromium.org/p/angleproject/issues/detail?id=3039
    337                needed_height.max(2),
    338                TextureFilter::Nearest,
    339                None,
    340            );
    341            self.texture = Some(texture);
    342        }
    343 
    344        // Note: the actual width can be larger than the logical one, with a few texels
    345        // of each row unused at the tail. This is needed because there is still hardware
    346        // (like Intel iGPUs) that prefers power-of-two sizes of textures ([1]).
    347        //
    348        // [1] https://software.intel.com/en-us/articles/opengl-performance-tips-power-of-two-textures-have-better-performance
    349        let logical_width = if needed_height == 1 {
    350            data.len() * texels_per_item
    351        } else {
    352            MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)
    353        };
    354 
    355        let rect = DeviceIntRect::from_size(
    356            DeviceIntSize::new(logical_width as i32, needed_height),
    357        );
    358 
    359        debug_assert!(len <= data.capacity(), "CPU copy will read out of bounds");
    360        texture_uploader.upload(
    361            device,
    362            self.texture(),
    363            rect,
    364            None,
    365            None,
    366            data.as_ptr(),
    367            len,
    368        );
    369    }
    370 
    371    pub fn deinit(mut self, device: &mut Device) {
    372        if let Some(t) = self.texture.take() {
    373            device.delete_texture(t);
    374        }
    375    }
    376 }
    377 
    378 pub struct VertexDataTextures {
    379    prim_header_f_texture: VertexDataTexture<PrimitiveHeaderF>,
    380    prim_header_i_texture: VertexDataTexture<PrimitiveHeaderI>,
    381    transforms_texture: VertexDataTexture<TransformData>,
    382    render_task_texture: VertexDataTexture<RenderTaskData>,
    383 }
    384 
    385 impl VertexDataTextures {
    386    pub fn new() -> Self {
    387        VertexDataTextures {
    388            prim_header_f_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
    389            prim_header_i_texture: VertexDataTexture::new(api::ImageFormat::RGBAI32),
    390            transforms_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
    391            render_task_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
    392        }
    393    }
    394 
    395    pub fn update(&mut self, device: &mut Device, pbo_pool: &mut UploadPBOPool, frame: &mut Frame) {
    396        let mut texture_uploader = device.upload_texture(pbo_pool);
    397        self.prim_header_f_texture.update(
    398            device,
    399            &mut texture_uploader,
    400            &mut frame.prim_headers.headers_float,
    401        );
    402        self.prim_header_i_texture.update(
    403            device,
    404            &mut texture_uploader,
    405            &mut frame.prim_headers.headers_int,
    406        );
    407        self.transforms_texture
    408            .update(device, &mut texture_uploader, &mut frame.transform_palette);
    409        self.render_task_texture.update(
    410            device,
    411            &mut texture_uploader,
    412            &mut frame.render_tasks.task_data,
    413        );
    414 
    415        // Flush and drop the texture uploader now, so that
    416        // we can borrow the textures to bind them.
    417        texture_uploader.flush(device);
    418 
    419        device.bind_texture(
    420            super::TextureSampler::PrimitiveHeadersF,
    421            &self.prim_header_f_texture.texture(),
    422            Swizzle::default(),
    423        );
    424        device.bind_texture(
    425            super::TextureSampler::PrimitiveHeadersI,
    426            &self.prim_header_i_texture.texture(),
    427            Swizzle::default(),
    428        );
    429        device.bind_texture(
    430            super::TextureSampler::TransformPalette,
    431            &self.transforms_texture.texture(),
    432            Swizzle::default(),
    433        );
    434        device.bind_texture(
    435            super::TextureSampler::RenderTasks,
    436            &self.render_task_texture.texture(),
    437            Swizzle::default(),
    438        );
    439    }
    440 
    441    pub fn size_in_bytes(&self) -> usize {
    442        self.prim_header_f_texture.size_in_bytes()
    443            + self.prim_header_i_texture.size_in_bytes()
    444            + self.transforms_texture.size_in_bytes()
    445            + self.render_task_texture.size_in_bytes()
    446    }
    447 
    448    pub fn deinit(self, device: &mut Device) {
    449        self.transforms_texture.deinit(device);
    450        self.prim_header_f_texture.deinit(device);
    451        self.prim_header_i_texture.deinit(device);
    452        self.render_task_texture.deinit(device);
    453    }
    454 }
    455 
    456 pub struct RendererVAOs {
    457    prim_vao: VAO,
    458    blur_vao: VAO,
    459    clip_rect_vao: VAO,
    460    clip_box_shadow_vao: VAO,
    461    border_vao: VAO,
    462    line_vao: VAO,
    463    scale_vao: VAO,
    464    fast_linear_gradient_vao: VAO,
    465    linear_gradient_vao: VAO,
    466    radial_gradient_vao: VAO,
    467    conic_gradient_vao: VAO,
    468    svg_filter_node_vao: VAO,
    469    composite_vao: VAO,
    470    clear_vao: VAO,
    471    copy_vao: VAO,
    472    mask_vao: VAO,
    473 }
    474 
    475 impl RendererVAOs {
    476    pub fn new(device: &mut Device, indexed_quads: Option<NonZeroUsize>) -> Self {
    477        const QUAD_INDICES: [u16; 6] = [0, 1, 2, 2, 1, 3];
    478        const QUAD_VERTICES: [[u8; 2]; 4] = [[0, 0], [0xFF, 0], [0, 0xFF], [0xFF, 0xFF]];
    479 
    480        let instance_divisor = if indexed_quads.is_some() { 0 } else { 1 };
    481        let prim_vao = device.create_vao(&desc::PRIM_INSTANCES, instance_divisor);
    482 
    483        device.bind_vao(&prim_vao);
    484        match indexed_quads {
    485            Some(count) => {
    486                assert!(count.get() < u16::MAX as usize);
    487                let quad_indices = (0 .. count.get() as u16)
    488                    .flat_map(|instance| QUAD_INDICES.iter().map(move |&index| instance * 4 + index))
    489                    .collect::<Vec<_>>();
    490                device.update_vao_indices(&prim_vao, &quad_indices, VertexUsageHint::Static);
    491                let quad_vertices = (0 .. count.get() as u16)
    492                    .flat_map(|_| QUAD_VERTICES.iter().cloned())
    493                    .collect::<Vec<_>>();
    494                device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static);
    495            }
    496            None => {
    497                device.update_vao_indices(&prim_vao, &QUAD_INDICES, VertexUsageHint::Static);
    498                device.update_vao_main_vertices(&prim_vao, &QUAD_VERTICES, VertexUsageHint::Static);
    499            }
    500        }
    501 
    502        RendererVAOs {
    503            blur_vao: device.create_vao_with_new_instances(&desc::BLUR, &prim_vao),
    504            clip_rect_vao: device.create_vao_with_new_instances(&desc::CLIP_RECT, &prim_vao),
    505            clip_box_shadow_vao: device
    506                .create_vao_with_new_instances(&desc::CLIP_BOX_SHADOW, &prim_vao),
    507            border_vao: device.create_vao_with_new_instances(&desc::BORDER, &prim_vao),
    508            scale_vao: device.create_vao_with_new_instances(&desc::SCALE, &prim_vao),
    509            line_vao: device.create_vao_with_new_instances(&desc::LINE, &prim_vao),
    510            fast_linear_gradient_vao: device.create_vao_with_new_instances(&desc::FAST_LINEAR_GRADIENT, &prim_vao),
    511            linear_gradient_vao: device.create_vao_with_new_instances(&desc::LINEAR_GRADIENT, &prim_vao),
    512            radial_gradient_vao: device.create_vao_with_new_instances(&desc::RADIAL_GRADIENT, &prim_vao),
    513            conic_gradient_vao: device.create_vao_with_new_instances(&desc::CONIC_GRADIENT, &prim_vao),
    514            svg_filter_node_vao: device.create_vao_with_new_instances(&desc::SVG_FILTER_NODE, &prim_vao),
    515            composite_vao: device.create_vao_with_new_instances(&desc::COMPOSITE, &prim_vao),
    516            clear_vao: device.create_vao_with_new_instances(&desc::CLEAR, &prim_vao),
    517            copy_vao: device.create_vao_with_new_instances(&desc::COPY, &prim_vao),
    518            mask_vao: device.create_vao_with_new_instances(&desc::MASK, &prim_vao),
    519            prim_vao,
    520        }
    521    }
    522 
    523    pub fn deinit(self, device: &mut Device) {
    524        device.delete_vao(self.prim_vao);
    525        device.delete_vao(self.clip_rect_vao);
    526        device.delete_vao(self.clip_box_shadow_vao);
    527        device.delete_vao(self.fast_linear_gradient_vao);
    528        device.delete_vao(self.linear_gradient_vao);
    529        device.delete_vao(self.radial_gradient_vao);
    530        device.delete_vao(self.conic_gradient_vao);
    531        device.delete_vao(self.blur_vao);
    532        device.delete_vao(self.line_vao);
    533        device.delete_vao(self.border_vao);
    534        device.delete_vao(self.scale_vao);
    535        device.delete_vao(self.svg_filter_node_vao);
    536        device.delete_vao(self.composite_vao);
    537        device.delete_vao(self.clear_vao);
    538        device.delete_vao(self.copy_vao);
    539        device.delete_vao(self.mask_vao);
    540    }
    541 }
    542 
    543 impl ops::Index<VertexArrayKind> for RendererVAOs {
    544    type Output = VAO;
    545    fn index(&self, kind: VertexArrayKind) -> &VAO {
    546        match kind {
    547            VertexArrayKind::Primitive => &self.prim_vao,
    548            VertexArrayKind::ClipRect => &self.clip_rect_vao,
    549            VertexArrayKind::ClipBoxShadow => &self.clip_box_shadow_vao,
    550            VertexArrayKind::Blur => &self.blur_vao,
    551            VertexArrayKind::Border => &self.border_vao,
    552            VertexArrayKind::Scale => &self.scale_vao,
    553            VertexArrayKind::LineDecoration => &self.line_vao,
    554            VertexArrayKind::FastLinearGradient => &self.fast_linear_gradient_vao,
    555            VertexArrayKind::LinearGradient => &self.linear_gradient_vao,
    556            VertexArrayKind::RadialGradient => &self.radial_gradient_vao,
    557            VertexArrayKind::ConicGradient => &self.conic_gradient_vao,
    558            VertexArrayKind::SvgFilterNode => &self.svg_filter_node_vao,
    559            VertexArrayKind::Composite => &self.composite_vao,
    560            VertexArrayKind::Clear => &self.clear_vao,
    561            VertexArrayKind::Copy => &self.copy_vao,
    562            VertexArrayKind::Mask => &self.mask_vao,
    563        }
    564    }
    565 }