tor-browser

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

init.rs (32906B)


      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::{BlobImageHandler, ColorF, CrashAnnotator, DocumentId, IdNamespace};
      6 use api::{VoidPtrToSizeFn, FontRenderMode, ImageFormat};
      7 use api::{RenderNotifier, ImageBufferKind};
      8 use api::units::*;
      9 use api::channel::unbounded_channel;
     10 pub use api::DebugFlags;
     11 
     12 use crate::bump_allocator::ChunkPool;
     13 use crate::render_api::{RenderApiSender, FrameMsg};
     14 use crate::composite::{CompositorKind, CompositorConfig};
     15 use crate::device::{
     16    UploadMethod, UploadPBOPool, VertexUsageHint, Device, ProgramCache, TextureFilter
     17 };
     18 use crate::frame_builder::FrameBuilderConfig;
     19 use crate::glyph_cache::GlyphCache;
     20 use glyph_rasterizer::{GlyphRasterThread, GlyphRasterizer, SharedFontResources};
     21 use crate::gpu_types::PrimitiveInstanceData;
     22 use crate::internal_types::{FastHashMap, FastHashSet};
     23 use crate::profiler::{self, Profiler, TransactionProfile};
     24 use crate::device::query::{GpuProfiler, GpuDebugMethod};
     25 use crate::render_backend::RenderBackend;
     26 use crate::resource_cache::ResourceCache;
     27 use crate::scene_builder_thread::{SceneBuilderThread, SceneBuilderThreadChannels, LowPrioritySceneBuilderThread};
     28 use crate::texture_cache::{TextureCache, TextureCacheConfig};
     29 use crate::picture_textures::PictureTextures;
     30 use crate::renderer::{
     31    debug, vertex, gl,
     32    Renderer, DebugOverlayState, BufferDamageTracker, PipelineInfo, TextureResolver,
     33    RendererError, ShaderPrecacheFlags, VERTEX_DATA_TEXTURE_COUNT,
     34    upload::UploadTexturePool,
     35    shade::{Shaders, SharedShaders},
     36 };
     37 #[cfg(feature = "debugger")]
     38 use crate::debugger::Debugger;
     39 
     40 use std::{
     41    mem,
     42    thread,
     43    cell::RefCell,
     44    collections::VecDeque,
     45    rc::Rc,
     46    sync::{Arc, atomic::{AtomicBool, Ordering}},
     47    num::NonZeroUsize,
     48    path::PathBuf,
     49 };
     50 
     51 use tracy_rs::register_thread_with_profiler;
     52 use rayon::{ThreadPool, ThreadPoolBuilder};
     53 use malloc_size_of::MallocSizeOfOps;
     54 
     55 /// Use this hint for all vertex data re-initialization. This allows
     56 /// the driver to better re-use RBOs internally.
     57 pub const ONE_TIME_USAGE_HINT: VertexUsageHint = VertexUsageHint::Stream;
     58 
     59 /// Is only false if no WR instances have ever been created.
     60 static HAS_BEEN_INITIALIZED: AtomicBool = AtomicBool::new(false);
     61 
     62 /// Returns true if a WR instance has ever been initialized in this process.
     63 pub fn wr_has_been_initialized() -> bool {
     64    HAS_BEEN_INITIALIZED.load(Ordering::SeqCst)
     65 }
     66 
     67 /// Allows callers to hook in at certain points of the async scene build. These
     68 /// functions are all called from the scene builder thread.
     69 pub trait SceneBuilderHooks {
     70    /// This is called exactly once, when the scene builder thread is started
     71    /// and before it processes anything.
     72    fn register(&self);
     73    /// This is called before each scene build starts.
     74    fn pre_scene_build(&self);
     75    /// This is called before each scene swap occurs.
     76    fn pre_scene_swap(&self);
     77    /// This is called after each scene swap occurs. The PipelineInfo contains
     78    /// the updated epochs and pipelines removed in the new scene compared to
     79    /// the old scene.
     80    fn post_scene_swap(&self, document_id: &Vec<DocumentId>, info: PipelineInfo, schedule_frame: bool);
     81    /// This is called after a resource update operation on the scene builder
     82    /// thread, in the case where resource updates were applied without a scene
     83    /// build.
     84    fn post_resource_update(&self, document_ids: &Vec<DocumentId>);
     85    /// This is called after a scene build completes without any changes being
     86    /// made. We guarantee that each pre_scene_build call will be matched with
     87    /// exactly one of post_scene_swap, post_resource_update or
     88    /// post_empty_scene_build.
     89    fn post_empty_scene_build(&self);
     90    /// This is a generic callback which provides an opportunity to run code
     91    /// on the scene builder thread. This is called as part of the main message
     92    /// loop of the scene builder thread, but outside of any specific message
     93    /// handler.
     94    fn poke(&self);
     95    /// This is called exactly once, when the scene builder thread is about to
     96    /// terminate.
     97    fn deregister(&self);
     98 }
     99 
    100 /// Allows callers to hook into the main render_backend loop and provide
    101 /// additional frame ops for generate_frame transactions. These functions
    102 /// are all called from the render backend thread.
    103 pub trait AsyncPropertySampler {
    104    /// This is called exactly once, when the render backend thread is started
    105    /// and before it processes anything.
    106    fn register(&self);
    107    /// This is called for each transaction with the generate_frame flag set
    108    /// (i.e. that will trigger a render). The list of frame messages returned
    109    /// are processed as though they were part of the original transaction.
    110    fn sample(&self, document_id: DocumentId, generated_frame_id: Option<u64>) -> Vec<FrameMsg>;
    111    /// This is called exactly once, when the render backend thread is about to
    112    /// terminate.
    113    fn deregister(&self);
    114 }
    115 
    116 pub trait RenderBackendHooks {
    117    fn init_thread(&self);
    118 }
    119 
    120 pub struct WebRenderOptions {
    121    pub resource_override_path: Option<PathBuf>,
    122    /// Whether to use shaders that have been optimized at build time.
    123    pub use_optimized_shaders: bool,
    124    pub enable_aa: bool,
    125    pub enable_dithering: bool,
    126    pub max_recorded_profiles: usize,
    127    pub precache_flags: ShaderPrecacheFlags,
    128    /// Enable sub-pixel anti-aliasing if a fast implementation is available.
    129    pub enable_subpixel_aa: bool,
    130    pub clear_color: ColorF,
    131    pub enable_clear_scissor: Option<bool>,
    132    pub max_internal_texture_size: Option<i32>,
    133    pub image_tiling_threshold: i32,
    134    pub upload_method: UploadMethod,
    135    /// The default size in bytes for PBOs used to upload texture data.
    136    pub upload_pbo_default_size: usize,
    137    pub batched_upload_threshold: i32,
    138    pub workers: Option<Arc<ThreadPool>>,
    139    /// A pool of large memory chunks used by the per-frame allocators.
    140    /// Providing the pool here makes it possible to share a single pool for
    141    /// all WebRender instances.
    142    pub chunk_pool: Option<Arc<ChunkPool>>,
    143    pub dedicated_glyph_raster_thread: Option<GlyphRasterThread>,
    144    pub enable_multithreading: bool,
    145    pub blob_image_handler: Option<Box<dyn BlobImageHandler>>,
    146    pub crash_annotator: Option<Box<dyn CrashAnnotator>>,
    147    pub size_of_op: Option<VoidPtrToSizeFn>,
    148    pub enclosing_size_of_op: Option<VoidPtrToSizeFn>,
    149    pub cached_programs: Option<Rc<ProgramCache>>,
    150    pub debug_flags: DebugFlags,
    151    pub renderer_id: Option<u64>,
    152    pub scene_builder_hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
    153    pub render_backend_hooks: Option<Box<dyn RenderBackendHooks + Send>>,
    154    pub sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
    155    pub support_low_priority_transactions: bool,
    156    pub namespace_alloc_by_client: bool,
    157    /// If namespaces are allocated by the client, then the namespace for fonts
    158    /// must also be allocated by the client to avoid namespace collisions with
    159    /// the backend.
    160    pub shared_font_namespace: Option<IdNamespace>,
    161    pub testing: bool,
    162    /// Set to true if this GPU supports hardware fast clears as a performance
    163    /// optimization. Likely requires benchmarking on various GPUs to see if
    164    /// it is a performance win. The default is false, which tends to be best
    165    /// performance on lower end / integrated GPUs.
    166    pub gpu_supports_fast_clears: bool,
    167    pub allow_dual_source_blending: bool,
    168    pub allow_advanced_blend_equation: bool,
    169    /// If true, allow textures to be initialized with glTexStorage.
    170    /// This affects VRAM consumption and data upload paths.
    171    pub allow_texture_storage_support: bool,
    172    /// If true, we allow the data uploaded in a different format from the
    173    /// one expected by the driver, pretending the format is matching, and
    174    /// swizzling the components on all the shader sampling.
    175    pub allow_texture_swizzling: bool,
    176    /// Use `ps_clear` shader with batched quad rendering to clear the rects
    177    /// in texture cache and picture cache tasks.
    178    /// This helps to work around some Intel drivers
    179    /// that incorrectly synchronize clears to following draws.
    180    pub clear_caches_with_quads: bool,
    181    /// Output the source of the shader with the given name.
    182    pub dump_shader_source: Option<String>,
    183    pub surface_origin_is_top_left: bool,
    184    /// The configuration options defining how WR composites the final scene.
    185    pub compositor_config: CompositorConfig,
    186    pub enable_gpu_markers: bool,
    187    /// If true, panic whenever a GL error occurs. This has a significant
    188    /// performance impact, so only use when debugging specific problems!
    189    pub panic_on_gl_error: bool,
    190    pub picture_tile_size: Option<DeviceIntSize>,
    191    pub texture_cache_config: TextureCacheConfig,
    192    /// If true, we'll use instanced vertex attributes. Each instace is a quad.
    193    /// If false, we'll duplicate the instance attributes per vertex and issue
    194    /// regular indexed draws instead.
    195    pub enable_instancing: bool,
    196    /// If true, we'll reject contexts backed by a software rasterizer, except
    197    /// Software WebRender.
    198    pub reject_software_rasterizer: bool,
    199    /// If enabled, pinch-zoom will apply the zoom factor during compositing
    200    /// of picture cache tiles. This is higher performance (tiles are not
    201    /// re-rasterized during zoom) but lower quality result. For most display
    202    /// items, if the zoom factor is relatively small, bilinear filtering should
    203    /// make the result look quite close to the high-quality zoom, except for glyphs.
    204    pub low_quality_pinch_zoom: bool,
    205    pub max_shared_surface_size: i32,
    206    /// If true, open a debug socket to listen for remote debugger.
    207    /// Relies on `debugger` cargo feature being enabled.
    208    pub enable_debugger: bool,
    209 
    210    /// Use a more precise method for sampling gradients.
    211    pub precise_linear_gradients: bool,
    212    pub precise_radial_gradients: bool,
    213    pub precise_conic_gradients: bool,
    214 }
    215 
    216 impl WebRenderOptions {
    217    /// Number of batches to look back in history for adding the current
    218    /// transparent instance into.
    219    const BATCH_LOOKBACK_COUNT: usize = 10;
    220 
    221    /// Since we are re-initializing the instance buffers on every draw call,
    222    /// the driver has to internally manage PBOs in flight.
    223    /// It's typically done by bucketing up to a specific limit, and then
    224    /// just individually managing the largest buffers.
    225    /// Having a limit here allows the drivers to more easily manage
    226    /// the PBOs for us.
    227    const MAX_INSTANCE_BUFFER_SIZE: usize = 0x20000; // actual threshold in macOS GL drivers
    228 }
    229 
    230 impl Default for WebRenderOptions {
    231    fn default() -> Self {
    232        WebRenderOptions {
    233            resource_override_path: None,
    234            use_optimized_shaders: false,
    235            enable_aa: true,
    236            enable_dithering: false,
    237            debug_flags: DebugFlags::empty(),
    238            max_recorded_profiles: 0,
    239            precache_flags: ShaderPrecacheFlags::empty(),
    240            enable_subpixel_aa: false,
    241            clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0),
    242            enable_clear_scissor: None,
    243            max_internal_texture_size: None,
    244            image_tiling_threshold: 4096,
    245            // This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL,
    246            // but we are unable to make this decision here, so picking the reasonable medium.
    247            upload_method: UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT),
    248            upload_pbo_default_size: 512 * 512 * 4,
    249            batched_upload_threshold: 512 * 512,
    250            workers: None,
    251            chunk_pool: None,
    252            dedicated_glyph_raster_thread: None,
    253            enable_multithreading: true,
    254            blob_image_handler: None,
    255            crash_annotator: None,
    256            size_of_op: None,
    257            enclosing_size_of_op: None,
    258            renderer_id: None,
    259            cached_programs: None,
    260            scene_builder_hooks: None,
    261            render_backend_hooks: None,
    262            sampler: None,
    263            support_low_priority_transactions: false,
    264            namespace_alloc_by_client: false,
    265            shared_font_namespace: None,
    266            testing: false,
    267            gpu_supports_fast_clears: false,
    268            allow_dual_source_blending: true,
    269            allow_advanced_blend_equation: false,
    270            allow_texture_storage_support: true,
    271            allow_texture_swizzling: true,
    272            clear_caches_with_quads: true,
    273            dump_shader_source: None,
    274            surface_origin_is_top_left: false,
    275            compositor_config: CompositorConfig::default(),
    276            enable_gpu_markers: true,
    277            panic_on_gl_error: false,
    278            picture_tile_size: None,
    279            texture_cache_config: TextureCacheConfig::DEFAULT,
    280            // Disabling instancing means more vertex data to upload and potentially
    281            // process by the vertex shaders.
    282            enable_instancing: true,
    283            reject_software_rasterizer: false,
    284            low_quality_pinch_zoom: false,
    285            max_shared_surface_size: 2048,
    286            enable_debugger: true,
    287            precise_linear_gradients: false,
    288            precise_radial_gradients: false,
    289            precise_conic_gradients: false,
    290        }
    291    }
    292 }
    293 
    294 /// Initializes WebRender and creates a `Renderer` and `RenderApiSender`.
    295 ///
    296 /// # Examples
    297 /// Initializes a `Renderer` with some reasonable values. For more information see
    298 /// [`WebRenderOptions`][WebRenderOptions].
    299 ///
    300 /// ```rust,ignore
    301 /// # use webrender::renderer::Renderer;
    302 /// # use std::path::PathBuf;
    303 /// let opts = webrender::WebRenderOptions {
    304 ///    device_pixel_ratio: 1.0,
    305 ///    resource_override_path: None,
    306 ///    enable_aa: false,
    307 /// };
    308 /// let (renderer, sender) = Renderer::new(opts);
    309 /// ```
    310 /// [WebRenderOptions]: struct.WebRenderOptions.html
    311 pub fn create_webrender_instance(
    312    gl: Rc<dyn gl::Gl>,
    313    notifier: Box<dyn RenderNotifier>,
    314    mut options: WebRenderOptions,
    315    shaders: Option<&SharedShaders>,
    316 ) -> Result<(Renderer, RenderApiSender), RendererError> {
    317    if !wr_has_been_initialized() {
    318        // If the profiler feature is enabled, try to load the profiler shared library
    319        // if the path was provided.
    320        #[cfg(feature = "profiler")]
    321        unsafe {
    322            if let Ok(ref tracy_path) = std::env::var("WR_TRACY_PATH") {
    323                let ok = tracy_rs::load(tracy_path);
    324                info!("Load tracy from {} -> {}", tracy_path, ok);
    325            }
    326        }
    327 
    328        register_thread_with_profiler("Compositor".to_owned());
    329    }
    330 
    331    HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
    332 
    333    // For now, we assume that native OS compositors are top-left origin. If that doesn't
    334    // turn out to be the case, we can add a query method on `LayerCompositor`.
    335    match options.compositor_config {
    336        CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => {}
    337        CompositorConfig::Layer { .. } => {
    338            options.surface_origin_is_top_left = true;
    339        }
    340    }
    341 
    342    let (api_tx, api_rx) = unbounded_channel();
    343    let (result_tx, result_rx) = unbounded_channel();
    344    let gl_type = gl.get_type();
    345 
    346    let mut device = Device::new(
    347        gl,
    348        options.crash_annotator.clone(),
    349        options.resource_override_path.clone(),
    350        options.use_optimized_shaders,
    351        options.upload_method.clone(),
    352        options.batched_upload_threshold,
    353        options.cached_programs.take(),
    354        options.allow_texture_storage_support,
    355        options.allow_texture_swizzling,
    356        options.dump_shader_source.take(),
    357        options.surface_origin_is_top_left,
    358        options.panic_on_gl_error,
    359    );
    360 
    361    let color_cache_formats = device.preferred_color_formats();
    362    let swizzle_settings = device.swizzle_settings();
    363    let use_dual_source_blending =
    364        device.get_capabilities().supports_dual_source_blending &&
    365        options.allow_dual_source_blending;
    366    let ext_blend_equation_advanced =
    367        options.allow_advanced_blend_equation &&
    368        device.get_capabilities().supports_advanced_blend_equation;
    369    let ext_blend_equation_advanced_coherent =
    370        device.supports_extension("GL_KHR_blend_equation_advanced_coherent");
    371 
    372    let enable_clear_scissor = options
    373        .enable_clear_scissor
    374        .unwrap_or(device.get_capabilities().prefers_clear_scissor);
    375 
    376    // 2048 is the minimum that the texture cache can work with.
    377    const MIN_TEXTURE_SIZE: i32 = 2048;
    378    let mut max_internal_texture_size = device.max_texture_size();
    379    if max_internal_texture_size < MIN_TEXTURE_SIZE {
    380        // Broken GL contexts can return a max texture size of zero (See #1260).
    381        // Better to gracefully fail now than panic as soon as a texture is allocated.
    382        error!(
    383            "Device reporting insufficient max texture size ({})",
    384            max_internal_texture_size
    385        );
    386        return Err(RendererError::MaxTextureSize);
    387    }
    388    if let Some(internal_limit) = options.max_internal_texture_size {
    389        assert!(internal_limit >= MIN_TEXTURE_SIZE);
    390        max_internal_texture_size = max_internal_texture_size.min(internal_limit);
    391    }
    392 
    393    if options.reject_software_rasterizer {
    394        let renderer_name_lc = device.get_capabilities().renderer_name.to_lowercase();
    395        if renderer_name_lc.contains("llvmpipe") || renderer_name_lc.contains("softpipe") || renderer_name_lc.contains("software rasterizer") {
    396        return Err(RendererError::SoftwareRasterizer);
    397        }
    398    }
    399 
    400    let image_tiling_threshold = options.image_tiling_threshold
    401        .min(max_internal_texture_size);
    402 
    403    device.begin_frame();
    404 
    405    let shaders = match shaders {
    406        Some(shaders) => Rc::clone(shaders),
    407        None => {
    408            let mut shaders = Shaders::new(&mut device, gl_type, &options)?;
    409            if options.precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
    410                let mut pending_shaders = shaders.precache_all(options.precache_flags);
    411                while shaders.resume_precache(&mut device, &mut pending_shaders)? {}
    412            }
    413            Rc::new(RefCell::new(shaders))
    414        }
    415    };
    416 
    417    let dither_matrix_texture = if options.enable_dithering {
    418        let dither_matrix: [u8; 64] = [
    419            0,
    420            48,
    421            12,
    422            60,
    423            3,
    424            51,
    425            15,
    426            63,
    427            32,
    428            16,
    429            44,
    430            28,
    431            35,
    432            19,
    433            47,
    434            31,
    435            8,
    436            56,
    437            4,
    438            52,
    439            11,
    440            59,
    441            7,
    442            55,
    443            40,
    444            24,
    445            36,
    446            20,
    447            43,
    448            27,
    449            39,
    450            23,
    451            2,
    452            50,
    453            14,
    454            62,
    455            1,
    456            49,
    457            13,
    458            61,
    459            34,
    460            18,
    461            46,
    462            30,
    463            33,
    464            17,
    465            45,
    466            29,
    467            10,
    468            58,
    469            6,
    470            54,
    471            9,
    472            57,
    473            5,
    474            53,
    475            42,
    476            26,
    477            38,
    478            22,
    479            41,
    480            25,
    481            37,
    482            21,
    483        ];
    484 
    485        let texture = device.create_texture(
    486            ImageBufferKind::Texture2D,
    487            ImageFormat::R8,
    488            8,
    489            8,
    490            TextureFilter::Nearest,
    491            None,
    492        );
    493        device.upload_texture_immediate(&texture, &dither_matrix);
    494 
    495        Some(texture)
    496    } else {
    497        None
    498    };
    499 
    500    let max_primitive_instance_count =
    501        WebRenderOptions::MAX_INSTANCE_BUFFER_SIZE / mem::size_of::<PrimitiveInstanceData>();
    502    let vaos = vertex::RendererVAOs::new(
    503        &mut device,
    504        if options.enable_instancing { None } else { NonZeroUsize::new(max_primitive_instance_count) },
    505    );
    506 
    507    let texture_upload_pbo_pool = UploadPBOPool::new(&mut device, options.upload_pbo_default_size);
    508    let staging_texture_pool = UploadTexturePool::new();
    509    let texture_resolver = TextureResolver::new(&mut device);
    510 
    511    let mut vertex_data_textures = Vec::new();
    512    for _ in 0 .. VERTEX_DATA_TEXTURE_COUNT {
    513        vertex_data_textures.push(vertex::VertexDataTextures::new());
    514    }
    515 
    516    let is_software = device.get_capabilities().renderer_name.starts_with("Software");
    517 
    518    device.end_frame();
    519 
    520    let backend_notifier = notifier.clone();
    521 
    522    let clear_alpha_targets_with_quads = !device.get_capabilities().supports_alpha_target_clears;
    523 
    524    let prefer_subpixel_aa = options.enable_subpixel_aa && use_dual_source_blending;
    525    let default_font_render_mode = match (options.enable_aa, prefer_subpixel_aa) {
    526        (true, true) => FontRenderMode::Subpixel,
    527        (true, false) => FontRenderMode::Alpha,
    528        (false, _) => FontRenderMode::Mono,
    529    };
    530 
    531    let compositor_kind = match options.compositor_config {
    532        CompositorConfig::Draw { max_partial_present_rects, draw_previous_partial_present_regions, .. } => {
    533            CompositorKind::Draw { max_partial_present_rects, draw_previous_partial_present_regions }
    534        }
    535        CompositorConfig::Native { ref compositor } => {
    536            let capabilities = compositor.get_capabilities(&mut device);
    537 
    538            CompositorKind::Native {
    539                capabilities,
    540            }
    541        }
    542        CompositorConfig::Layer { .. } => {
    543            CompositorKind::Layer {
    544            }
    545        }
    546    };
    547 
    548    let config = FrameBuilderConfig {
    549        default_font_render_mode,
    550        dual_source_blending_is_supported: use_dual_source_blending,
    551        testing: options.testing,
    552        gpu_supports_fast_clears: options.gpu_supports_fast_clears,
    553        gpu_supports_advanced_blend: ext_blend_equation_advanced,
    554        advanced_blend_is_coherent: ext_blend_equation_advanced_coherent,
    555        gpu_supports_render_target_partial_update: device.get_capabilities().supports_render_target_partial_update,
    556        external_images_require_copy: !device.get_capabilities().supports_image_external_essl3,
    557        batch_lookback_count: WebRenderOptions::BATCH_LOOKBACK_COUNT,
    558        background_color: Some(options.clear_color),
    559        compositor_kind,
    560        tile_size_override: None,
    561        max_surface_override: None,
    562        max_depth_ids: device.max_depth_ids(),
    563        max_target_size: max_internal_texture_size,
    564        force_invalidation: false,
    565        is_software,
    566        low_quality_pinch_zoom: options.low_quality_pinch_zoom,
    567        max_shared_surface_size: options.max_shared_surface_size,
    568        enable_dithering: options.enable_dithering,
    569        precise_linear_gradients: options.precise_linear_gradients,
    570        precise_radial_gradients: options.precise_radial_gradients,
    571        precise_conic_gradients: options.precise_conic_gradients,
    572    };
    573    info!("WR {:?}", config);
    574 
    575    let debug_flags = options.debug_flags;
    576    let size_of_op = options.size_of_op;
    577    let enclosing_size_of_op = options.enclosing_size_of_op;
    578    let make_size_of_ops =
    579        move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op));
    580    let workers = options
    581        .workers
    582        .take()
    583        .unwrap_or_else(|| {
    584            let worker = ThreadPoolBuilder::new()
    585                .thread_name(|idx|{ format!("WRWorker#{}", idx) })
    586                .start_handler(move |idx| {
    587                    register_thread_with_profiler(format!("WRWorker#{}", idx));
    588                    profiler::register_thread(&format!("WRWorker#{}", idx));
    589                })
    590                .exit_handler(move |_idx| {
    591                    profiler::unregister_thread();
    592                })
    593                .build();
    594            Arc::new(worker.unwrap())
    595        });
    596    let sampler = options.sampler;
    597    let namespace_alloc_by_client = options.namespace_alloc_by_client;
    598 
    599    // Ensure shared font keys exist within their own unique namespace so
    600    // that they don't accidentally collide across Renderer instances.
    601    let font_namespace = if namespace_alloc_by_client {
    602        options.shared_font_namespace.expect("Shared font namespace must be allocated by client")
    603    } else {
    604        RenderBackend::next_namespace_id()
    605    };
    606    let fonts = SharedFontResources::new(font_namespace);
    607 
    608    let blob_image_handler = options.blob_image_handler.take();
    609    let scene_builder_hooks = options.scene_builder_hooks;
    610    let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
    611    let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
    612    let lp_scene_thread_name = format!("WRSceneBuilderLP#{}", options.renderer_id.unwrap_or(0));
    613 
    614    let glyph_rasterizer = GlyphRasterizer::new(
    615        workers,
    616        options.dedicated_glyph_raster_thread,
    617        device.get_capabilities().supports_r8_texture_upload,
    618    );
    619 
    620    let (scene_builder_channels, scene_tx) =
    621        SceneBuilderThreadChannels::new(api_tx.clone());
    622 
    623    let sb_fonts = fonts.clone();
    624 
    625    thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
    626        register_thread_with_profiler(scene_thread_name.clone());
    627        profiler::register_thread(&scene_thread_name);
    628 
    629        let mut scene_builder = SceneBuilderThread::new(
    630            config,
    631            sb_fonts,
    632            make_size_of_ops(),
    633            scene_builder_hooks,
    634            scene_builder_channels,
    635        );
    636        scene_builder.run();
    637 
    638        profiler::unregister_thread();
    639    })?;
    640 
    641    let low_priority_scene_tx = if options.support_low_priority_transactions {
    642        let (low_priority_scene_tx, low_priority_scene_rx) = unbounded_channel();
    643        let lp_builder = LowPrioritySceneBuilderThread {
    644            rx: low_priority_scene_rx,
    645            tx: scene_tx.clone(),
    646            tile_pool: api::BlobTilePool::new(),
    647        };
    648 
    649        thread::Builder::new().name(lp_scene_thread_name.clone()).spawn(move || {
    650            register_thread_with_profiler(lp_scene_thread_name.clone());
    651            profiler::register_thread(&lp_scene_thread_name);
    652 
    653            let mut scene_builder = lp_builder;
    654            scene_builder.run();
    655 
    656            profiler::unregister_thread();
    657        })?;
    658 
    659        low_priority_scene_tx
    660    } else {
    661        scene_tx.clone()
    662    };
    663 
    664    let rb_blob_handler = blob_image_handler
    665        .as_ref()
    666        .map(|handler| handler.create_similar());
    667 
    668    let texture_cache_config = options.texture_cache_config.clone();
    669    let mut picture_tile_size = options.picture_tile_size.unwrap_or(crate::tile_cache::TILE_SIZE_DEFAULT);
    670    // Clamp the picture tile size to reasonable values.
    671    picture_tile_size.width = picture_tile_size.width.max(128).min(4096);
    672    picture_tile_size.height = picture_tile_size.height.max(128).min(4096);
    673 
    674    let picture_texture_filter = if options.low_quality_pinch_zoom {
    675        TextureFilter::Linear
    676    } else {
    677        TextureFilter::Nearest
    678    };
    679 
    680    let render_backend_hooks = options.render_backend_hooks.take();
    681 
    682    let chunk_pool = options.chunk_pool.take().unwrap_or_else(|| {
    683        Arc::new(ChunkPool::new())
    684    });
    685 
    686    let rb_scene_tx = scene_tx.clone();
    687    let rb_fonts = fonts.clone();
    688    let enable_multithreading = options.enable_multithreading;
    689    thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
    690        if let Some(hooks) = render_backend_hooks {
    691            hooks.init_thread();
    692        }
    693        register_thread_with_profiler(rb_thread_name.clone());
    694        profiler::register_thread(&rb_thread_name);
    695 
    696        let texture_cache = TextureCache::new(
    697            max_internal_texture_size,
    698            image_tiling_threshold,
    699            color_cache_formats,
    700            swizzle_settings,
    701            &texture_cache_config,
    702        );
    703 
    704        let picture_textures = PictureTextures::new(
    705            picture_tile_size,
    706            picture_texture_filter,
    707        );
    708 
    709        let glyph_cache = GlyphCache::new();
    710 
    711        let mut resource_cache = ResourceCache::new(
    712            texture_cache,
    713            picture_textures,
    714            glyph_rasterizer,
    715            glyph_cache,
    716            rb_fonts,
    717            rb_blob_handler,
    718        );
    719 
    720        resource_cache.enable_multithreading(enable_multithreading);
    721 
    722        let mut backend = RenderBackend::new(
    723            api_rx,
    724            result_tx,
    725            rb_scene_tx,
    726            resource_cache,
    727            chunk_pool,
    728            backend_notifier,
    729            config,
    730            sampler,
    731            make_size_of_ops(),
    732            debug_flags,
    733            namespace_alloc_by_client,
    734        );
    735        backend.run();
    736        profiler::unregister_thread();
    737    })?;
    738 
    739    let debug_method = if !options.enable_gpu_markers {
    740        // The GPU markers are disabled.
    741        GpuDebugMethod::None
    742    } else if device.get_capabilities().supports_khr_debug {
    743        GpuDebugMethod::KHR
    744    } else if device.supports_extension("GL_EXT_debug_marker") {
    745        GpuDebugMethod::MarkerEXT
    746    } else {
    747        warn!("asking to enable_gpu_markers but no supporting extension was found");
    748        GpuDebugMethod::None
    749    };
    750 
    751    info!("using {:?}", debug_method);
    752 
    753    let gpu_profiler = GpuProfiler::new(Rc::clone(device.rc_gl()), debug_method);
    754    #[cfg(feature = "capture")]
    755    let read_fbo = device.create_fbo();
    756 
    757    let mut renderer = Renderer {
    758        result_rx,
    759        api_tx: api_tx.clone(),
    760        device,
    761        active_documents: FastHashMap::default(),
    762        pending_texture_updates: Vec::new(),
    763        pending_texture_cache_updates: false,
    764        pending_native_surface_updates: Vec::new(),
    765        pending_shader_updates: Vec::new(),
    766        shaders,
    767        debug: debug::LazyInitializedDebugRenderer::new(),
    768        debug_flags: DebugFlags::empty(),
    769        profile: TransactionProfile::new(),
    770        frame_counter: 0,
    771        resource_upload_time: 0.0,
    772        profiler: Profiler::new(),
    773        max_recorded_profiles: options.max_recorded_profiles,
    774        clear_color: options.clear_color,
    775        enable_clear_scissor,
    776        enable_advanced_blend_barriers: !ext_blend_equation_advanced_coherent,
    777        clear_caches_with_quads: options.clear_caches_with_quads,
    778        clear_alpha_targets_with_quads,
    779        last_time: 0,
    780        gpu_profiler,
    781        vaos,
    782        gpu_buffer_texture_f: None,
    783        gpu_buffer_texture_f_too_large: 0,
    784        gpu_buffer_texture_i: None,
    785        gpu_buffer_texture_i_too_large: 0,
    786        vertex_data_textures,
    787        current_vertex_data_textures: 0,
    788        pipeline_info: PipelineInfo::default(),
    789        dither_matrix_texture,
    790        external_image_handler: None,
    791        size_of_ops: make_size_of_ops(),
    792        cpu_profiles: VecDeque::new(),
    793        gpu_profiles: VecDeque::new(),
    794        texture_upload_pbo_pool,
    795        staging_texture_pool,
    796        texture_resolver,
    797        renderer_errors: Vec::new(),
    798        async_frame_recorder: None,
    799        async_screenshots: None,
    800        #[cfg(feature = "capture")]
    801        read_fbo,
    802        #[cfg(feature = "replay")]
    803        owned_external_images: FastHashMap::default(),
    804        notifications: Vec::new(),
    805        device_size: None,
    806        zoom_debug_texture: None,
    807        cursor_position: DeviceIntPoint::zero(),
    808        shared_texture_cache_cleared: false,
    809        documents_seen: FastHashSet::default(),
    810        force_redraw: true,
    811        compositor_config: options.compositor_config,
    812        current_compositor_kind: compositor_kind,
    813        allocated_native_surfaces: FastHashSet::default(),
    814        debug_overlay_state: DebugOverlayState::new(),
    815        buffer_damage_tracker: BufferDamageTracker::default(),
    816        max_primitive_instance_count,
    817        enable_instancing: options.enable_instancing,
    818        consecutive_oom_frames: 0,
    819        target_frame_publish_id: None,
    820        pending_result_msg: None,
    821        layer_compositor_frame_state_in_prev_frame: None,
    822        external_composite_debug_items: Vec::new(),
    823        command_log: None,
    824        #[cfg(feature = "debugger")]
    825        debugger: Debugger::new(),
    826    };
    827 
    828    // We initially set the flags to default and then now call set_debug_flags
    829    // to ensure any potential transition when enabling a flag is run.
    830    renderer.set_debug_flags(debug_flags);
    831    renderer.profiler.set_ui("Default");
    832 
    833    let sender = RenderApiSender::new(
    834        api_tx,
    835        scene_tx,
    836        low_priority_scene_tx,
    837        blob_image_handler,
    838        fonts,
    839    );
    840 
    841    #[cfg(feature = "debugger")]
    842    if options.enable_debugger {
    843        let api = if namespace_alloc_by_client {
    844            sender.create_api_by_client(IdNamespace::DEBUGGER)
    845        } else {
    846            sender.create_api()
    847        };
    848        crate::debugger::start(api);
    849    }
    850 
    851    Ok((renderer, sender))
    852 }