tor-browser

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

debug.rs (13785B)


      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 use api::{ColorU, ImageFormat, ImageBufferKind};
      6 use api::units::*;
      7 use crate::debug_font_data;
      8 use crate::device::{Device, Program, Texture, TextureSlot, VertexDescriptor, ShaderError, VAO};
      9 use crate::device::{TextureFilter, VertexAttribute, VertexAttributeKind, VertexUsageHint};
     10 use euclid::{Point2D, Rect, Size2D, Transform3D, default};
     11 use crate::internal_types::Swizzle;
     12 use std::f32;
     13 
     14 #[derive(Debug, Copy, Clone)]
     15 enum DebugSampler {
     16    Font,
     17 }
     18 
     19 impl Into<TextureSlot> for DebugSampler {
     20    fn into(self) -> TextureSlot {
     21        match self {
     22            DebugSampler::Font => TextureSlot(0),
     23        }
     24    }
     25 }
     26 
     27 const DESC_FONT: VertexDescriptor = VertexDescriptor {
     28    vertex_attributes: &[
     29        VertexAttribute {
     30            name: "aPosition",
     31            count: 2,
     32            kind: VertexAttributeKind::F32,
     33        },
     34        VertexAttribute {
     35            name: "aColor",
     36            count: 4,
     37            kind: VertexAttributeKind::U8Norm,
     38        },
     39        VertexAttribute {
     40            name: "aColorTexCoord",
     41            count: 2,
     42            kind: VertexAttributeKind::F32,
     43        },
     44    ],
     45    instance_attributes: &[],
     46 };
     47 
     48 const DESC_COLOR: VertexDescriptor = VertexDescriptor {
     49    vertex_attributes: &[
     50        VertexAttribute {
     51            name: "aPosition",
     52            count: 2,
     53            kind: VertexAttributeKind::F32,
     54        },
     55        VertexAttribute {
     56            name: "aColor",
     57            count: 4,
     58            kind: VertexAttributeKind::U8Norm,
     59        },
     60    ],
     61    instance_attributes: &[],
     62 };
     63 
     64 #[repr(C)]
     65 pub struct DebugFontVertex {
     66    pub x: f32,
     67    pub y: f32,
     68    pub color: ColorU,
     69    pub u: f32,
     70    pub v: f32,
     71 }
     72 
     73 impl DebugFontVertex {
     74    pub fn new(x: f32, y: f32, u: f32, v: f32, color: ColorU) -> DebugFontVertex {
     75        DebugFontVertex { x, y, color, u, v }
     76    }
     77 }
     78 
     79 #[repr(C)]
     80 pub struct DebugColorVertex {
     81    pub x: f32,
     82    pub y: f32,
     83    pub color: ColorU,
     84 }
     85 
     86 impl DebugColorVertex {
     87    pub fn new(x: f32, y: f32, color: ColorU) -> DebugColorVertex {
     88        DebugColorVertex { x, y, color }
     89    }
     90 }
     91 
     92 pub struct DebugRenderer {
     93    font_vertices: Vec<DebugFontVertex>,
     94    font_indices: Vec<u32>,
     95    font_program: Program,
     96    font_vao: VAO,
     97    font_texture: Texture,
     98 
     99    tri_vertices: Vec<DebugColorVertex>,
    100    tri_indices: Vec<u32>,
    101    tri_vao: VAO,
    102    line_vertices: Vec<DebugColorVertex>,
    103    line_vao: VAO,
    104    color_program: Program,
    105 }
    106 
    107 impl DebugRenderer {
    108    pub fn new(device: &mut Device) -> Result<Self, ShaderError> {
    109        let font_program = device.create_program_linked(
    110            "debug_font",
    111            &[],
    112            &DESC_FONT,
    113        )?;
    114        device.bind_program(&font_program);
    115        device.bind_shader_samplers(&font_program, &[("sColor0", DebugSampler::Font)]);
    116 
    117        let color_program = device.create_program_linked(
    118            "debug_color",
    119            &[],
    120            &DESC_COLOR,
    121        )?;
    122 
    123        let font_vao = device.create_vao(&DESC_FONT, 1);
    124        let line_vao = device.create_vao(&DESC_COLOR, 1);
    125        let tri_vao = device.create_vao(&DESC_COLOR, 1);
    126 
    127        let font_texture = device.create_texture(
    128            ImageBufferKind::Texture2D,
    129            ImageFormat::R8,
    130            debug_font_data::BMP_WIDTH,
    131            debug_font_data::BMP_HEIGHT,
    132            TextureFilter::Linear,
    133            None,
    134        );
    135        device.upload_texture_immediate(
    136            &font_texture,
    137            &debug_font_data::FONT_BITMAP
    138        );
    139 
    140        Ok(DebugRenderer {
    141            font_vertices: Vec::new(),
    142            font_indices: Vec::new(),
    143            line_vertices: Vec::new(),
    144            tri_vao,
    145            tri_vertices: Vec::new(),
    146            tri_indices: Vec::new(),
    147            font_program,
    148            color_program,
    149            font_vao,
    150            line_vao,
    151            font_texture,
    152        })
    153    }
    154 
    155    pub fn deinit(self, device: &mut Device) {
    156        device.delete_texture(self.font_texture);
    157        device.delete_program(self.font_program);
    158        device.delete_program(self.color_program);
    159        device.delete_vao(self.tri_vao);
    160        device.delete_vao(self.line_vao);
    161        device.delete_vao(self.font_vao);
    162    }
    163 
    164    pub fn line_height(&self) -> f32 {
    165        debug_font_data::FONT_SIZE as f32 * 1.1
    166    }
    167 
    168    /// Draws a line of text at the provided starting coordinates.
    169    ///
    170    /// If |bounds| is specified, glyphs outside the bounds are discarded.
    171    ///
    172    /// Y-coordinates is relative to screen top, along with everything else in
    173    /// this file.
    174    pub fn add_text(
    175        &mut self,
    176        x: f32,
    177        y: f32,
    178        text: &str,
    179        color: ColorU,
    180        bounds: Option<DeviceRect>,
    181    ) -> default::Rect<f32> {
    182        let mut x_start = x;
    183        let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
    184        let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;
    185 
    186        let mut min_x = f32::MAX;
    187        let mut max_x = -f32::MAX;
    188        let mut min_y = f32::MAX;
    189        let mut max_y = -f32::MAX;
    190 
    191        for c in text.chars() {
    192            let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
    193            if c < debug_font_data::GLYPHS.len() {
    194                let glyph = &debug_font_data::GLYPHS[c];
    195 
    196                let x0 = (x_start + glyph.xo + 0.5).floor();
    197                let y0 = (y + glyph.yo + 0.5).floor();
    198 
    199                let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
    200                let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;
    201 
    202                // If either corner of the glyph will end up out of bounds, drop it.
    203                if let Some(b) = bounds {
    204                    let rect = DeviceRect {
    205                        min: DevicePoint::new(x0, y0),
    206                        max: DevicePoint::new(x1, y1),
    207                    };
    208                    if !b.contains_box(&rect) {
    209                        continue;
    210                    }
    211                }
    212 
    213                let s0 = glyph.x0 as f32 * ipw;
    214                let t0 = glyph.y0 as f32 * iph;
    215                let s1 = glyph.x1 as f32 * ipw;
    216                let t1 = glyph.y1 as f32 * iph;
    217 
    218                x_start += glyph.xa;
    219 
    220                let vertex_count = self.font_vertices.len() as u32;
    221 
    222                self.font_vertices
    223                    .push(DebugFontVertex::new(x0, y0, s0, t0, color));
    224                self.font_vertices
    225                    .push(DebugFontVertex::new(x1, y0, s1, t0, color));
    226                self.font_vertices
    227                    .push(DebugFontVertex::new(x0, y1, s0, t1, color));
    228                self.font_vertices
    229                    .push(DebugFontVertex::new(x1, y1, s1, t1, color));
    230 
    231                self.font_indices.push(vertex_count + 0);
    232                self.font_indices.push(vertex_count + 1);
    233                self.font_indices.push(vertex_count + 2);
    234                self.font_indices.push(vertex_count + 2);
    235                self.font_indices.push(vertex_count + 1);
    236                self.font_indices.push(vertex_count + 3);
    237 
    238                min_x = min_x.min(x0);
    239                max_x = max_x.max(x1);
    240                min_y = min_y.min(y0);
    241                max_y = max_y.max(y1);
    242            }
    243        }
    244 
    245        Rect::new(
    246            Point2D::new(min_x, min_y),
    247            Size2D::new(max_x - min_x, max_y - min_y),
    248        )
    249    }
    250 
    251    pub fn add_quad(
    252        &mut self,
    253        x0: f32,
    254        y0: f32,
    255        x1: f32,
    256        y1: f32,
    257        color_top: ColorU,
    258        color_bottom: ColorU,
    259    ) {
    260        let vertex_count = self.tri_vertices.len() as u32;
    261 
    262        self.tri_vertices
    263            .push(DebugColorVertex::new(x0, y0, color_top));
    264        self.tri_vertices
    265            .push(DebugColorVertex::new(x1, y0, color_top));
    266        self.tri_vertices
    267            .push(DebugColorVertex::new(x0, y1, color_bottom));
    268        self.tri_vertices
    269            .push(DebugColorVertex::new(x1, y1, color_bottom));
    270 
    271        self.tri_indices.push(vertex_count + 0);
    272        self.tri_indices.push(vertex_count + 1);
    273        self.tri_indices.push(vertex_count + 2);
    274        self.tri_indices.push(vertex_count + 2);
    275        self.tri_indices.push(vertex_count + 1);
    276        self.tri_indices.push(vertex_count + 3);
    277    }
    278 
    279    #[allow(dead_code)]
    280    pub fn add_line(&mut self, x0: i32, y0: i32, color0: ColorU, x1: i32, y1: i32, color1: ColorU) {
    281        self.line_vertices
    282            .push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
    283        self.line_vertices
    284            .push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
    285    }
    286 
    287 
    288    pub fn add_rect(&mut self, rect: &DeviceIntRect, thickness: i32, color: ColorU) {
    289        let p0 = rect.min;
    290        let p1 = rect.max;
    291        if thickness > 1 && rect.width() > thickness * 2 && rect.height() > thickness * 2 {
    292            let w = thickness as f32;
    293            let p0 = p0.to_f32();
    294            let p1 = p1.to_f32();
    295            self.add_quad(p0.x, p0.y, p1.x, p0.y + w, color, color);
    296            self.add_quad(p1.x - w, p0.y + w, p1.x, p1.y - w, color, color);
    297            self.add_quad(p0.x, p1.y - w, p1.x, p1.y, color, color);
    298            self.add_quad(p0.x, p0.y + w, p0.x + w, p1.y - w, color, color);
    299        } else {
    300            self.add_line(p0.x, p0.y, color, p1.x, p0.y, color);
    301            self.add_line(p1.x, p0.y, color, p1.x, p1.y, color);
    302            self.add_line(p1.x, p1.y, color, p0.x, p1.y, color);
    303            self.add_line(p0.x, p1.y, color, p0.x, p0.y, color);    
    304        }
    305    }
    306 
    307    pub fn render(
    308        &mut self,
    309        device: &mut Device,
    310        viewport_size: Option<DeviceIntSize>,
    311        scale: f32,
    312        surface_origin_is_top_left: bool,
    313    ) {
    314        if let Some(viewport_size) = viewport_size {
    315            device.disable_depth();
    316            device.set_blend(true);
    317            device.set_blend_mode_premultiplied_alpha();
    318 
    319            let (bottom, top) = if surface_origin_is_top_left {
    320                (0.0, viewport_size.height as f32 * scale)
    321            } else {
    322                (viewport_size.height as f32 * scale, 0.0)
    323            };
    324 
    325            let projection = Transform3D::ortho(
    326                0.0,
    327                viewport_size.width as f32 * scale,
    328                bottom,
    329                top,
    330                device.ortho_near_plane(),
    331                device.ortho_far_plane(),
    332            );
    333 
    334            // Triangles
    335            if !self.tri_vertices.is_empty() {
    336                device.bind_program(&self.color_program);
    337                device.set_uniforms(&self.color_program, &projection);
    338                device.bind_vao(&self.tri_vao);
    339                device.update_vao_indices(&self.tri_vao, &self.tri_indices, VertexUsageHint::Dynamic);
    340                device.update_vao_main_vertices(
    341                    &self.tri_vao,
    342                    &self.tri_vertices,
    343                    VertexUsageHint::Dynamic,
    344                );
    345                device.draw_triangles_u32(0, self.tri_indices.len() as i32);
    346            }
    347 
    348            // Lines
    349            if !self.line_vertices.is_empty() {
    350                device.bind_program(&self.color_program);
    351                device.set_uniforms(&self.color_program, &projection);
    352                device.bind_vao(&self.line_vao);
    353                device.update_vao_main_vertices(
    354                    &self.line_vao,
    355                    &self.line_vertices,
    356                    VertexUsageHint::Dynamic,
    357                );
    358                device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
    359            }
    360 
    361            // Glyph
    362            if !self.font_indices.is_empty() {
    363                device.bind_program(&self.font_program);
    364                device.set_uniforms(&self.font_program, &projection);
    365                device.bind_texture(DebugSampler::Font, &self.font_texture, Swizzle::default());
    366                device.bind_vao(&self.font_vao);
    367                device.update_vao_indices(&self.font_vao, &self.font_indices, VertexUsageHint::Dynamic);
    368                device.update_vao_main_vertices(
    369                    &self.font_vao,
    370                    &self.font_vertices,
    371                    VertexUsageHint::Dynamic,
    372                );
    373                device.draw_triangles_u32(0, self.font_indices.len() as i32);
    374            }
    375        }
    376 
    377        self.font_indices.clear();
    378        self.font_vertices.clear();
    379        self.line_vertices.clear();
    380        self.tri_vertices.clear();
    381        self.tri_indices.clear();
    382    }
    383 }
    384 
    385 pub struct LazyInitializedDebugRenderer {
    386    debug_renderer: Option<DebugRenderer>,
    387    failed: bool,
    388 }
    389 
    390 impl LazyInitializedDebugRenderer {
    391    pub fn new() -> Self {
    392        Self {
    393            debug_renderer: None,
    394            failed: false,
    395        }
    396    }
    397 
    398    pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> {
    399        if self.failed {
    400            return None;
    401        }
    402        if self.debug_renderer.is_none() {
    403            match DebugRenderer::new(device) {
    404                Ok(renderer) => { self.debug_renderer = Some(renderer); }
    405                Err(_) => {
    406                    // The shader compilation code already logs errors.
    407                    self.failed = true;
    408                }
    409            }
    410        }
    411 
    412        self.debug_renderer.as_mut()
    413    }
    414 
    415    /// Returns mut ref to `debug::DebugRenderer` if one already exists, otherwise returns `None`.
    416    pub fn try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer> {
    417        self.debug_renderer.as_mut()
    418    }
    419 
    420    pub fn deinit(self, device: &mut Device) {
    421        if let Some(debug_renderer) = self.debug_renderer {
    422            debug_renderer.deinit(device);
    423        }
    424    }
    425 }