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 }