Skip to main content

webrender/renderer/
init.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
5use api::{BlobImageHandler, ColorF, CrashAnnotator, DocumentId, IdNamespace};
6use api::{VoidPtrToSizeFn, FontRenderMode, ImageFormat};
7use api::{RenderNotifier, ImageBufferKind};
8use api::units::*;
9use api::channel::unbounded_channel;
10pub use api::DebugFlags;
11
12use crate::bump_allocator::ChunkPool;
13use crate::render_api::{RenderApiSender, FrameMsg};
14use crate::composite::{CompositorKind, CompositorConfig};
15use crate::device::{
16    UploadMethod, UploadPBOPool, VertexUsageHint, Device, ProgramCache, TextureFilter
17};
18use crate::frame_builder::FrameBuilderConfig;
19use crate::glyph_cache::GlyphCache;
20use glyph_rasterizer::{GlyphRasterThread, GlyphRasterizer, SharedFontResources};
21use crate::gpu_types::PrimitiveInstanceData;
22use crate::internal_types::{FastHashMap, FastHashSet};
23use crate::profiler::{self, Profiler, TransactionProfile};
24use crate::device::query::{GpuProfiler, GpuDebugMethod};
25use crate::render_backend::RenderBackend;
26use crate::resource_cache::ResourceCache;
27use crate::scene_builder_thread::{SceneBuilderThread, SceneBuilderThreadChannels, LowPrioritySceneBuilderThread};
28use crate::texture_cache::{TextureCache, TextureCacheConfig};
29use crate::picture_textures::PictureTextures;
30use 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")]
38use crate::debugger::Debugger;
39
40use 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
51use tracy_rs::register_thread_with_profiler;
52use rayon::{ThreadPool, ThreadPoolBuilder};
53use 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.
57pub const ONE_TIME_USAGE_HINT: VertexUsageHint = VertexUsageHint::Stream;
58
59/// Is only false if no WR instances have ever been created.
60static HAS_BEEN_INITIALIZED: AtomicBool = AtomicBool::new(false);
61
62/// Returns true if a WR instance has ever been initialized in this process.
63pub 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.
69pub 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.
103pub 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
116pub trait RenderBackendHooks {
117    fn init_thread(&self);
118}
119
120pub 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
211impl WebRenderOptions {
212    /// Number of batches to look back in history for adding the current
213    /// transparent instance into.
214    const BATCH_LOOKBACK_COUNT: usize = 10;
215
216    /// Since we are re-initializing the instance buffers on every draw call,
217    /// the driver has to internally manage PBOs in flight.
218    /// It's typically done by bucketing up to a specific limit, and then
219    /// just individually managing the largest buffers.
220    /// Having a limit here allows the drivers to more easily manage
221    /// the PBOs for us.
222    const MAX_INSTANCE_BUFFER_SIZE: usize = 0x20000; // actual threshold in macOS GL drivers
223}
224
225impl Default for WebRenderOptions {
226    fn default() -> Self {
227        WebRenderOptions {
228            resource_override_path: None,
229            use_optimized_shaders: false,
230            enable_aa: true,
231            enable_dithering: false,
232            debug_flags: DebugFlags::empty(),
233            max_recorded_profiles: 0,
234            precache_flags: ShaderPrecacheFlags::empty(),
235            enable_subpixel_aa: false,
236            clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0),
237            enable_clear_scissor: None,
238            max_internal_texture_size: None,
239            image_tiling_threshold: 4096,
240            // This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL,
241            // but we are unable to make this decision here, so picking the reasonable medium.
242            upload_method: UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT),
243            upload_pbo_default_size: 512 * 512 * 4,
244            batched_upload_threshold: 512 * 512,
245            workers: None,
246            chunk_pool: None,
247            dedicated_glyph_raster_thread: None,
248            enable_multithreading: true,
249            blob_image_handler: None,
250            crash_annotator: None,
251            size_of_op: None,
252            enclosing_size_of_op: None,
253            renderer_id: None,
254            cached_programs: None,
255            scene_builder_hooks: None,
256            render_backend_hooks: None,
257            sampler: None,
258            support_low_priority_transactions: false,
259            namespace_alloc_by_client: false,
260            shared_font_namespace: None,
261            testing: false,
262            gpu_supports_fast_clears: false,
263            allow_dual_source_blending: true,
264            allow_advanced_blend_equation: false,
265            allow_texture_storage_support: true,
266            allow_texture_swizzling: true,
267            clear_caches_with_quads: true,
268            dump_shader_source: None,
269            surface_origin_is_top_left: false,
270            compositor_config: CompositorConfig::default(),
271            enable_gpu_markers: true,
272            panic_on_gl_error: false,
273            picture_tile_size: None,
274            texture_cache_config: TextureCacheConfig::DEFAULT,
275            // Disabling instancing means more vertex data to upload and potentially
276            // process by the vertex shaders.
277            enable_instancing: true,
278            reject_software_rasterizer: false,
279            low_quality_pinch_zoom: false,
280            max_shared_surface_size: 2048,
281            enable_debugger: true,
282        }
283    }
284}
285
286/// Initializes WebRender and creates a `Renderer` and `RenderApiSender`.
287///
288/// # Examples
289/// Initializes a `Renderer` with some reasonable values. For more information see
290/// [`WebRenderOptions`][WebRenderOptions].
291///
292/// ```rust,ignore
293/// # use webrender::renderer::Renderer;
294/// # use std::path::PathBuf;
295/// let opts = webrender::WebRenderOptions {
296///    device_pixel_ratio: 1.0,
297///    resource_override_path: None,
298///    enable_aa: false,
299/// };
300/// let (renderer, sender) = Renderer::new(opts);
301/// ```
302/// [WebRenderOptions]: struct.WebRenderOptions.html
303pub fn create_webrender_instance(
304    gl: Rc<dyn gl::Gl>,
305    notifier: Box<dyn RenderNotifier>,
306    mut options: WebRenderOptions,
307    shaders: Option<&SharedShaders>,
308) -> Result<(Renderer, RenderApiSender), RendererError> {
309    if !wr_has_been_initialized() {
310        // If the profiler feature is enabled, try to load the profiler shared library
311        // if the path was provided.
312        #[cfg(feature = "profiler")]
313        unsafe {
314            if let Ok(ref tracy_path) = std::env::var("WR_TRACY_PATH") {
315                let ok = tracy_rs::load(tracy_path);
316                info!("Load tracy from {} -> {}", tracy_path, ok);
317            }
318        }
319
320        register_thread_with_profiler("Compositor".to_owned());
321    }
322
323    HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
324
325    // For now, we assume that native OS compositors are top-left origin. If that doesn't
326    // turn out to be the case, we can add a query method on `LayerCompositor`.
327    match options.compositor_config {
328        CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => {}
329        CompositorConfig::Layer { .. } => {
330            options.surface_origin_is_top_left = true;
331        }
332    }
333
334    let (api_tx, api_rx) = unbounded_channel();
335    let (result_tx, result_rx) = unbounded_channel();
336    let gl_type = gl.get_type();
337
338    let mut device = Device::new(
339        gl,
340        options.crash_annotator.clone(),
341        options.resource_override_path.clone(),
342        options.use_optimized_shaders,
343        options.upload_method.clone(),
344        options.batched_upload_threshold,
345        options.cached_programs.take(),
346        options.allow_texture_storage_support,
347        options.allow_texture_swizzling,
348        options.dump_shader_source.take(),
349        options.surface_origin_is_top_left,
350        options.panic_on_gl_error,
351    );
352
353    let color_cache_formats = device.preferred_color_formats();
354    let swizzle_settings = device.swizzle_settings();
355    let use_dual_source_blending =
356        device.get_capabilities().supports_dual_source_blending &&
357        options.allow_dual_source_blending;
358    let ext_blend_equation_advanced =
359        options.allow_advanced_blend_equation &&
360        device.get_capabilities().supports_advanced_blend_equation;
361    let ext_blend_equation_advanced_coherent =
362        device.supports_extension("GL_KHR_blend_equation_advanced_coherent");
363
364    let enable_clear_scissor = options
365        .enable_clear_scissor
366        .unwrap_or(device.get_capabilities().prefers_clear_scissor);
367
368    // 2048 is the minimum that the texture cache can work with.
369    const MIN_TEXTURE_SIZE: i32 = 2048;
370    let mut max_internal_texture_size = device.max_texture_size();
371    if max_internal_texture_size < MIN_TEXTURE_SIZE {
372        // Broken GL contexts can return a max texture size of zero (See #1260).
373        // Better to gracefully fail now than panic as soon as a texture is allocated.
374        error!(
375            "Device reporting insufficient max texture size ({})",
376            max_internal_texture_size
377        );
378        return Err(RendererError::MaxTextureSize);
379    }
380    if let Some(internal_limit) = options.max_internal_texture_size {
381        assert!(internal_limit >= MIN_TEXTURE_SIZE);
382        max_internal_texture_size = max_internal_texture_size.min(internal_limit);
383    }
384
385    if options.reject_software_rasterizer {
386        let renderer_name_lc = device.get_capabilities().renderer_name.to_lowercase();
387        if renderer_name_lc.contains("llvmpipe") || renderer_name_lc.contains("softpipe") || renderer_name_lc.contains("software rasterizer") {
388        return Err(RendererError::SoftwareRasterizer);
389        }
390    }
391
392    let image_tiling_threshold = options.image_tiling_threshold
393        .min(max_internal_texture_size);
394
395    device.begin_frame();
396
397    let shaders = match shaders {
398        Some(shaders) => Rc::clone(shaders),
399        None => {
400            let mut shaders = Shaders::new(&mut device, gl_type, &options)?;
401            if options.precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
402                let mut pending_shaders = shaders.precache_all(options.precache_flags);
403                while shaders.resume_precache(&mut device, &mut pending_shaders)? {}
404            }
405            Rc::new(RefCell::new(shaders))
406        }
407    };
408
409    let dither_matrix_texture = if options.enable_dithering {
410        let dither_matrix: [u8; 64] = [
411            0,
412            48,
413            12,
414            60,
415            3,
416            51,
417            15,
418            63,
419            32,
420            16,
421            44,
422            28,
423            35,
424            19,
425            47,
426            31,
427            8,
428            56,
429            4,
430            52,
431            11,
432            59,
433            7,
434            55,
435            40,
436            24,
437            36,
438            20,
439            43,
440            27,
441            39,
442            23,
443            2,
444            50,
445            14,
446            62,
447            1,
448            49,
449            13,
450            61,
451            34,
452            18,
453            46,
454            30,
455            33,
456            17,
457            45,
458            29,
459            10,
460            58,
461            6,
462            54,
463            9,
464            57,
465            5,
466            53,
467            42,
468            26,
469            38,
470            22,
471            41,
472            25,
473            37,
474            21,
475        ];
476
477        let texture = device.create_texture(
478            ImageBufferKind::Texture2D,
479            ImageFormat::R8,
480            8,
481            8,
482            TextureFilter::Nearest,
483            None,
484        );
485        device.upload_texture_immediate(&texture, &dither_matrix);
486
487        Some(texture)
488    } else {
489        None
490    };
491
492    let max_primitive_instance_count =
493        WebRenderOptions::MAX_INSTANCE_BUFFER_SIZE / mem::size_of::<PrimitiveInstanceData>();
494    let vaos = vertex::RendererVAOs::new(
495        &mut device,
496        if options.enable_instancing { None } else { NonZeroUsize::new(max_primitive_instance_count) },
497    );
498
499    let texture_upload_pbo_pool = UploadPBOPool::new(&mut device, options.upload_pbo_default_size);
500    let staging_texture_pool = UploadTexturePool::new();
501    let texture_resolver = TextureResolver::new(&mut device);
502
503    let mut vertex_data_textures = Vec::new();
504    for _ in 0 .. VERTEX_DATA_TEXTURE_COUNT {
505        vertex_data_textures.push(vertex::VertexDataTextures::new());
506    }
507
508    let is_software = device.get_capabilities().renderer_name.starts_with("Software");
509
510    device.end_frame();
511
512    let backend_notifier = notifier.clone();
513
514    let clear_alpha_targets_with_quads = !device.get_capabilities().supports_alpha_target_clears;
515
516    let prefer_subpixel_aa = options.enable_subpixel_aa && use_dual_source_blending;
517    let default_font_render_mode = match (options.enable_aa, prefer_subpixel_aa) {
518        (true, true) => FontRenderMode::Subpixel,
519        (true, false) => FontRenderMode::Alpha,
520        (false, _) => FontRenderMode::Mono,
521    };
522
523    let compositor_kind = match options.compositor_config {
524        CompositorConfig::Draw { max_partial_present_rects, draw_previous_partial_present_regions, .. } => {
525            CompositorKind::Draw { max_partial_present_rects, draw_previous_partial_present_regions }
526        }
527        CompositorConfig::Native { ref compositor } => {
528            let capabilities = compositor.get_capabilities(&mut device);
529
530            CompositorKind::Native {
531                capabilities,
532            }
533        }
534        CompositorConfig::Layer { .. } => {
535            CompositorKind::Layer {
536            }
537        }
538    };
539
540    let config = FrameBuilderConfig {
541        default_font_render_mode,
542        dual_source_blending_is_supported: use_dual_source_blending,
543        testing: options.testing,
544        gpu_supports_fast_clears: options.gpu_supports_fast_clears,
545        gpu_supports_advanced_blend: ext_blend_equation_advanced,
546        advanced_blend_is_coherent: ext_blend_equation_advanced_coherent,
547        gpu_supports_render_target_partial_update: device.get_capabilities().supports_render_target_partial_update,
548        external_images_require_copy: !device.get_capabilities().supports_image_external_essl3,
549        batch_lookback_count: WebRenderOptions::BATCH_LOOKBACK_COUNT,
550        background_color: Some(options.clear_color),
551        compositor_kind,
552        tile_size_override: None,
553        max_surface_override: None,
554        max_depth_ids: device.max_depth_ids(),
555        max_target_size: max_internal_texture_size,
556        force_invalidation: false,
557        is_software,
558        low_quality_pinch_zoom: options.low_quality_pinch_zoom,
559        max_shared_surface_size: options.max_shared_surface_size,
560        enable_dithering: options.enable_dithering,
561    };
562    info!("WR {:?}", config);
563
564    let debug_flags = options.debug_flags;
565    let size_of_op = options.size_of_op;
566    let enclosing_size_of_op = options.enclosing_size_of_op;
567    let make_size_of_ops =
568        move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op));
569    let workers = options
570        .workers
571        .take()
572        .unwrap_or_else(|| {
573            let worker = ThreadPoolBuilder::new()
574                .thread_name(|idx|{ format!("WRWorker#{}", idx) })
575                .start_handler(move |idx| {
576                    register_thread_with_profiler(format!("WRWorker#{}", idx));
577                    profiler::register_thread(&format!("WRWorker#{}", idx));
578                })
579                .exit_handler(move |_idx| {
580                    profiler::unregister_thread();
581                })
582                .build();
583            Arc::new(worker.unwrap())
584        });
585    let sampler = options.sampler;
586    let namespace_alloc_by_client = options.namespace_alloc_by_client;
587
588    // Ensure shared font keys exist within their own unique namespace so
589    // that they don't accidentally collide across Renderer instances.
590    let font_namespace = if namespace_alloc_by_client {
591        options.shared_font_namespace.expect("Shared font namespace must be allocated by client")
592    } else {
593        RenderBackend::next_namespace_id()
594    };
595    let fonts = SharedFontResources::new(font_namespace);
596
597    let blob_image_handler = options.blob_image_handler.take();
598    let scene_builder_hooks = options.scene_builder_hooks;
599    let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
600    let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
601    let lp_scene_thread_name = format!("WRSceneBuilderLP#{}", options.renderer_id.unwrap_or(0));
602
603    let glyph_rasterizer = GlyphRasterizer::new(
604        workers,
605        options.dedicated_glyph_raster_thread,
606        device.get_capabilities().supports_r8_texture_upload,
607    );
608
609    let (scene_builder_channels, scene_tx) =
610        SceneBuilderThreadChannels::new(api_tx.clone());
611
612    let sb_fonts = fonts.clone();
613
614    thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
615        register_thread_with_profiler(scene_thread_name.clone());
616        profiler::register_thread(&scene_thread_name);
617
618        let mut scene_builder = SceneBuilderThread::new(
619            config,
620            sb_fonts,
621            make_size_of_ops(),
622            scene_builder_hooks,
623            scene_builder_channels,
624        );
625        scene_builder.run();
626
627        profiler::unregister_thread();
628    })?;
629
630    let low_priority_scene_tx = if options.support_low_priority_transactions {
631        let (low_priority_scene_tx, low_priority_scene_rx) = unbounded_channel();
632        let lp_builder = LowPrioritySceneBuilderThread {
633            rx: low_priority_scene_rx,
634            tx: scene_tx.clone(),
635            tile_pool: api::BlobTilePool::new(),
636        };
637
638        thread::Builder::new().name(lp_scene_thread_name.clone()).spawn(move || {
639            register_thread_with_profiler(lp_scene_thread_name.clone());
640            profiler::register_thread(&lp_scene_thread_name);
641
642            let mut scene_builder = lp_builder;
643            scene_builder.run();
644
645            profiler::unregister_thread();
646        })?;
647
648        low_priority_scene_tx
649    } else {
650        scene_tx.clone()
651    };
652
653    let rb_blob_handler = blob_image_handler
654        .as_ref()
655        .map(|handler| handler.create_similar());
656
657    let texture_cache_config = options.texture_cache_config.clone();
658    let mut picture_tile_size = options.picture_tile_size.unwrap_or(crate::tile_cache::TILE_SIZE_DEFAULT);
659    // Clamp the picture tile size to reasonable values.
660    picture_tile_size.width = picture_tile_size.width.max(128).min(4096);
661    picture_tile_size.height = picture_tile_size.height.max(128).min(4096);
662
663    let picture_texture_filter = if options.low_quality_pinch_zoom {
664        TextureFilter::Linear
665    } else {
666        TextureFilter::Nearest
667    };
668
669    let render_backend_hooks = options.render_backend_hooks.take();
670
671    let chunk_pool = options.chunk_pool.take().unwrap_or_else(|| {
672        Arc::new(ChunkPool::new())
673    });
674
675    let rb_scene_tx = scene_tx.clone();
676    let rb_fonts = fonts.clone();
677    let enable_multithreading = options.enable_multithreading;
678    thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
679        if let Some(hooks) = render_backend_hooks {
680            hooks.init_thread();
681        }
682        register_thread_with_profiler(rb_thread_name.clone());
683        profiler::register_thread(&rb_thread_name);
684
685        let texture_cache = TextureCache::new(
686            max_internal_texture_size,
687            image_tiling_threshold,
688            color_cache_formats,
689            swizzle_settings,
690            &texture_cache_config,
691        );
692
693        let picture_textures = PictureTextures::new(
694            picture_tile_size,
695            picture_texture_filter,
696        );
697
698        let glyph_cache = GlyphCache::new();
699
700        let mut resource_cache = ResourceCache::new(
701            texture_cache,
702            picture_textures,
703            glyph_rasterizer,
704            glyph_cache,
705            rb_fonts,
706            rb_blob_handler,
707        );
708
709        resource_cache.enable_multithreading(enable_multithreading);
710
711        let mut backend = RenderBackend::new(
712            api_rx,
713            result_tx,
714            rb_scene_tx,
715            resource_cache,
716            chunk_pool,
717            backend_notifier,
718            config,
719            sampler,
720            make_size_of_ops(),
721            debug_flags,
722            namespace_alloc_by_client,
723        );
724        backend.run();
725        profiler::unregister_thread();
726    })?;
727
728    let debug_method = if !options.enable_gpu_markers {
729        // The GPU markers are disabled.
730        GpuDebugMethod::None
731    } else if device.get_capabilities().supports_khr_debug {
732        GpuDebugMethod::KHR
733    } else if device.supports_extension("GL_EXT_debug_marker") {
734        GpuDebugMethod::MarkerEXT
735    } else {
736        warn!("asking to enable_gpu_markers but no supporting extension was found");
737        GpuDebugMethod::None
738    };
739
740    info!("using {:?}", debug_method);
741
742    let gpu_profiler = GpuProfiler::new(Rc::clone(device.rc_gl()), debug_method);
743    #[cfg(feature = "capture")]
744    let read_fbo = device.create_fbo();
745
746    let mut renderer = Renderer {
747        result_rx,
748        api_tx: api_tx.clone(),
749        device,
750        active_documents: FastHashMap::default(),
751        pending_texture_updates: Vec::new(),
752        pending_texture_cache_updates: false,
753        pending_native_surface_updates: Vec::new(),
754        pending_shader_updates: Vec::new(),
755        shaders,
756        debug: debug::LazyInitializedDebugRenderer::new(),
757        debug_flags: DebugFlags::empty(),
758        profile: TransactionProfile::new(),
759        frame_counter: 0,
760        resource_upload_time: 0.0,
761        profiler: Profiler::new(),
762        max_recorded_profiles: options.max_recorded_profiles,
763        clear_color: options.clear_color,
764        enable_clear_scissor,
765        enable_advanced_blend_barriers: !ext_blend_equation_advanced_coherent,
766        clear_caches_with_quads: options.clear_caches_with_quads,
767        clear_alpha_targets_with_quads,
768        last_time: 0,
769        gpu_profiler,
770        vaos,
771        gpu_buffer_texture_f: None,
772        gpu_buffer_texture_f_too_large: 0,
773        gpu_buffer_texture_i: None,
774        gpu_buffer_texture_i_too_large: 0,
775        vertex_data_textures,
776        current_vertex_data_textures: 0,
777        pipeline_info: PipelineInfo::default(),
778        dither_matrix_texture,
779        external_image_handler: None,
780        size_of_ops: make_size_of_ops(),
781        cpu_profiles: VecDeque::new(),
782        gpu_profiles: VecDeque::new(),
783        texture_upload_pbo_pool,
784        staging_texture_pool,
785        texture_resolver,
786        renderer_errors: Vec::new(),
787        async_frame_recorder: None,
788        async_screenshots: None,
789        #[cfg(feature = "capture")]
790        read_fbo,
791        #[cfg(feature = "replay")]
792        owned_external_images: FastHashMap::default(),
793        notifications: Vec::new(),
794        device_size: None,
795        zoom_debug_texture: None,
796        cursor_position: DeviceIntPoint::zero(),
797        shared_texture_cache_cleared: false,
798        documents_seen: FastHashSet::default(),
799        force_redraw: true,
800        compositor_config: options.compositor_config,
801        current_compositor_kind: compositor_kind,
802        allocated_native_surfaces: FastHashSet::default(),
803        debug_overlay_state: DebugOverlayState::new(),
804        buffer_damage_tracker: BufferDamageTracker::default(),
805        max_primitive_instance_count,
806        enable_instancing: options.enable_instancing,
807        consecutive_oom_frames: 0,
808        target_frame_publish_id: None,
809        pending_result_msg: None,
810        layer_compositor_frame_state_in_prev_frame: None,
811        external_composite_debug_items: Vec::new(),
812        command_log: None,
813        #[cfg(feature = "debugger")]
814        debugger: Debugger::new(),
815    };
816
817    // We initially set the flags to default and then now call set_debug_flags
818    // to ensure any potential transition when enabling a flag is run.
819    renderer.set_debug_flags(debug_flags);
820    renderer.profiler.set_ui("Default");
821
822    let sender = RenderApiSender::new(
823        api_tx,
824        scene_tx,
825        low_priority_scene_tx,
826        blob_image_handler,
827        fonts,
828    );
829
830    #[cfg(feature = "debugger")]
831    if options.enable_debugger {
832        let api = if namespace_alloc_by_client {
833            sender.create_api_by_client(IdNamespace::DEBUGGER)
834        } else {
835            sender.create_api()
836        };
837        crate::debugger::start(api);
838    }
839
840    Ok((renderer, sender))
841}