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 //! The high-level module responsible for interfacing with the GPU.
6 //!
7 //! Much of WebRender's design is driven by separating work into different
8 //! threads. To avoid the complexities of multi-threaded GPU access, we restrict
9 //! all communication with the GPU to one thread, the render thread. But since
10 //! issuing GPU commands is often a bottleneck, we move everything else (i.e.
11 //! the computation of what commands to issue) to another thread, the
12 //! RenderBackend thread. The RenderBackend, in turn, may delegate work to other
13 //! thread (like the SceneBuilder threads or Rayon workers), but the
14 //! Render-vs-RenderBackend distinction is the most important.
15 //!
16 //! The consumer is responsible for initializing the render thread before
17 //! calling into WebRender, which means that this module also serves as the
18 //! initial entry point into WebRender, and is responsible for spawning the
19 //! various other threads discussed above. That said, WebRender initialization
20 //! returns both the `Renderer` instance as well as a channel for communicating
21 //! directly with the `RenderBackend`. Aside from a few high-level operations
22 //! like 'render now', most of interesting commands from the consumer go over
23 //! that channel and operate on the `RenderBackend`.
24 //!
25 //! ## Space conversion guidelines
26 //! At this stage, we shuld be operating with `DevicePixel` and `FramebufferPixel` only.
27 //! "Framebuffer" space represents the final destination of our rendeing,
28 //! and it happens to be Y-flipped on OpenGL. The conversion is done as follows:
29 //!   - for rasterized primitives, the orthographics projection transforms
30 //! the content rectangle to -1 to 1
31 //!   - the viewport transformation is setup to map the whole range to
32 //! the framebuffer rectangle provided by the document view, stored in `DrawTarget`
33 //!   - all the direct framebuffer operations, like blitting, reading pixels, and setting
34 //! up the scissor, are accepting already transformed coordinates, which we can get by
35 //! calling `DrawTarget::to_framebuffer_rect`
36 
37 use api::{ApiMsg, BlobImageHandler, ColorF, ColorU, MixBlendMode};
38 use api::{DocumentId, Epoch, ExternalImageHandler, ExternalImageId};
39 use api::{ExternalImageSource, ExternalImageType, FontRenderMode, FrameMsg, ImageFormat};
40 use api::{PipelineId, ImageRendering, Checkpoint, NotificationRequest, OutputImageHandler};
41 use api::{DebugCommand, MemoryReport, VoidPtrToSizeFn, PremultipliedColorF};
42 use api::{RenderApiSender, RenderNotifier, TextureTarget, SharedFontInstanceMap};
43 #[cfg(feature = "replay")]
44 use api::ExternalImage;
45 use api::units::*;
46 pub use api::DebugFlags;
47 use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList};
48 #[cfg(any(feature = "capture", feature = "replay"))]
49 use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
50 use crate::composite::{CompositeState, CompositeTileSurface, CompositeTile, ResolvedExternalSurface};
51 use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData};
52 use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation};
53 use crate::debug_colors;
54 use crate::debug_render::{DebugItem, DebugRenderer};
55 use crate::device::{DepthFunction, Device, GpuFrameId, Program, UploadMethod, Texture, PBO};
56 use crate::device::{DrawTarget, ExternalTexture, FBOId, ReadTarget, TextureSlot};
57 use crate::device::{ShaderError, TextureFilter, TextureFlags,
58              VertexUsageHint, VAO, VBO, CustomVAO};
59 use crate::device::ProgramCache;
60 use crate::device::query::GpuTimer;
61 use euclid::{rect, Transform3D, Scale, default};
62 use crate::frame_builder::{Frame, ChasePrimitive, FrameBuilderConfig};
63 use gleam::gl;
64 use crate::glyph_cache::GlyphCache;
65 use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
66 use crate::gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
67 use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
68 use crate::gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF, ScalingInstance, SvgFilterInstance, TransformData};
69 use crate::gpu_types::{CompositeInstance, ResolveInstanceData, ZBufferId};
70 use crate::internal_types::{TextureSource, ResourceCacheError};
71 use crate::internal_types::{CacheTextureId, DebugOutput, FastHashMap, FastHashSet, LayerIndex, RenderedDocument, ResultMsg};
72 use crate::internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource};
73 use crate::internal_types::{RenderTargetInfo, SavedTargetIndex, Swizzle};
74 use malloc_size_of::MallocSizeOfOps;
75 use crate::picture::{RecordedDirtyRegion, tile_cache_sizes, ResolvedSurfaceTexture};
76 use crate::prim_store::DeferredResolve;
77 use crate::profiler::{BackendProfileCounters, FrameProfileCounters, TimeProfileCounter,
78                GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
79 use crate::profiler::{Profiler, ChangeIndicator, ProfileStyle, add_event_marker, thread_is_being_profiled};
80 use crate::device::query::{GpuProfiler, GpuDebugMethod};
81 use rayon::{ThreadPool, ThreadPoolBuilder};
82 use crate::render_backend::{FrameId, RenderBackend};
83 use crate::render_task_graph::RenderTaskGraph;
84 use crate::render_task::{RenderTask, RenderTaskData, RenderTaskKind};
85 use crate::resource_cache::ResourceCache;
86 use crate::scene_builder_thread::{SceneBuilderThread, SceneBuilderThreadChannels, LowPrioritySceneBuilderThread};
87 use crate::screen_capture::AsyncScreenshotGrabber;
88 use crate::shade::{Shaders, WrShaders};
89 use smallvec::SmallVec;
90 use crate::texture_cache::TextureCache;
91 use crate::render_target::{AlphaRenderTarget, ColorRenderTarget, PictureCacheTarget};
92 use crate::render_target::{RenderTarget, TextureCacheRenderTarget, RenderTargetList};
93 use crate::render_target::{RenderTargetKind, BlitJob, BlitJobSource};
94 use crate::render_task_graph::RenderPassKind;
95 use crate::util::drain_filter;
96 use crate::c_str;
97 
98 use std;
99 use std::cmp;
100 use std::collections::VecDeque;
101 use std::collections::hash_map::Entry;
102 use std::f32;
103 use std::marker::PhantomData;
104 use std::mem;
105 use std::os::raw::c_void;
106 use std::path::PathBuf;
107 use std::rc::Rc;
108 use std::sync::Arc;
109 use std::sync::atomic::{AtomicBool, Ordering};
110 use std::sync::mpsc::{channel, Sender, Receiver};
111 use std::thread;
112 use std::cell::RefCell;
113 use tracy_rs::register_thread_with_profiler;
114 use time::precise_time_ns;
115 use std::ffi::CString;
116 
117 cfg_if! {
118     if #[cfg(feature = "debugger")] {
119         use serde_json;
120         use crate::debug_server;
121     }
122 }
123 
124 const DEFAULT_BATCH_LOOKBACK_COUNT: usize = 10;
125 const VERTEX_TEXTURE_EXTRA_ROWS: i32 = 10;
126 
127 /// The size of the array of each type of vertex data texture that
128 /// is round-robin-ed each frame during bind_frame_data. Doing this
129 /// helps avoid driver stalls while updating the texture in some
130 /// drivers. The size of these textures are typically very small
131 /// (e.g. < 16 kB) so it's not a huge waste of memory. Despite that,
132 /// this is a short-term solution - we want to find a better way
133 /// to provide this frame data, which will likely involve some
134 /// combination of UBO/SSBO usage. Although this only affects some
135 /// platforms, it's enabled on all platforms to reduce testing
136 /// differences between platforms.
137 const VERTEX_DATA_TEXTURE_COUNT: usize = 3;
138 
139 /// Is only false if no WR instances have ever been created.
140 static HAS_BEEN_INITIALIZED: AtomicBool = AtomicBool::new(false);
141 
142 /// Returns true if a WR instance has ever been initialized in this process.
wr_has_been_initialized() -> bool143 pub fn wr_has_been_initialized() -> bool {
144     HAS_BEEN_INITIALIZED.load(Ordering::SeqCst)
145 }
146 
147 pub const MAX_VERTEX_TEXTURE_WIDTH: usize = webrender_build::MAX_VERTEX_TEXTURE_WIDTH;
148 /// Enabling this toggle would force the GPU cache scattered texture to
149 /// be resized every frame, which enables GPU debuggers to see if this
150 /// is performed correctly.
151 const GPU_CACHE_RESIZE_TEST: bool = false;
152 
153 /// Number of GPU blocks per UV rectangle provided for an image.
154 pub const BLOCKS_PER_UV_RECT: usize = 2;
155 
156 const GPU_TAG_BRUSH_OPACITY: GpuProfileTag = GpuProfileTag {
157     label: "B_Opacity",
158     color: debug_colors::DARKMAGENTA,
159 };
160 const GPU_TAG_BRUSH_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
161     label: "B_LinearGradient",
162     color: debug_colors::POWDERBLUE,
163 };
164 const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
165     label: "B_RadialGradient",
166     color: debug_colors::LIGHTPINK,
167 };
168 const GPU_TAG_BRUSH_CONIC_GRADIENT: GpuProfileTag = GpuProfileTag {
169     label: "B_ConicGradient",
170     color: debug_colors::GREEN,
171 };
172 const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
173     label: "B_YuvImage",
174     color: debug_colors::DARKGREEN,
175 };
176 const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag {
177     label: "B_MixBlend",
178     color: debug_colors::MAGENTA,
179 };
180 const GPU_TAG_BRUSH_BLEND: GpuProfileTag = GpuProfileTag {
181     label: "B_Blend",
182     color: debug_colors::ORANGE,
183 };
184 const GPU_TAG_BRUSH_IMAGE: GpuProfileTag = GpuProfileTag {
185     label: "B_Image",
186     color: debug_colors::SPRINGGREEN,
187 };
188 const GPU_TAG_BRUSH_SOLID: GpuProfileTag = GpuProfileTag {
189     label: "B_Solid",
190     color: debug_colors::RED,
191 };
192 const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
193     label: "C_Clip",
194     color: debug_colors::PURPLE,
195 };
196 const GPU_TAG_CACHE_BORDER: GpuProfileTag = GpuProfileTag {
197     label: "C_Border",
198     color: debug_colors::CORNSILK,
199 };
200 const GPU_TAG_CACHE_LINE_DECORATION: GpuProfileTag = GpuProfileTag {
201     label: "C_LineDecoration",
202     color: debug_colors::YELLOWGREEN,
203 };
204 const GPU_TAG_CACHE_GRADIENT: GpuProfileTag = GpuProfileTag {
205     label: "C_Gradient",
206     color: debug_colors::BROWN,
207 };
208 const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
209     label: "target init",
210     color: debug_colors::SLATEGREY,
211 };
212 const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag {
213     label: "data init",
214     color: debug_colors::LIGHTGREY,
215 };
216 const GPU_TAG_PRIM_SPLIT_COMPOSITE: GpuProfileTag = GpuProfileTag {
217     label: "SplitComposite",
218     color: debug_colors::DARKBLUE,
219 };
220 const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag {
221     label: "TextRun",
222     color: debug_colors::BLUE,
223 };
224 const GPU_TAG_BLUR: GpuProfileTag = GpuProfileTag {
225     label: "Blur",
226     color: debug_colors::VIOLET,
227 };
228 const GPU_TAG_BLIT: GpuProfileTag = GpuProfileTag {
229     label: "Blit",
230     color: debug_colors::LIME,
231 };
232 const GPU_TAG_SCALE: GpuProfileTag = GpuProfileTag {
233     label: "Scale",
234     color: debug_colors::GHOSTWHITE,
235 };
236 const GPU_SAMPLER_TAG_ALPHA: GpuProfileTag = GpuProfileTag {
237     label: "Alpha Targets",
238     color: debug_colors::BLACK,
239 };
240 const GPU_SAMPLER_TAG_OPAQUE: GpuProfileTag = GpuProfileTag {
241     label: "Opaque Pass",
242     color: debug_colors::BLACK,
243 };
244 const GPU_SAMPLER_TAG_TRANSPARENT: GpuProfileTag = GpuProfileTag {
245     label: "Transparent Pass",
246     color: debug_colors::BLACK,
247 };
248 const GPU_TAG_SVG_FILTER: GpuProfileTag = GpuProfileTag {
249     label: "SvgFilter",
250     color: debug_colors::LEMONCHIFFON,
251 };
252 const GPU_TAG_COMPOSITE: GpuProfileTag = GpuProfileTag {
253     label: "Composite",
254     color: debug_colors::TOMATO,
255 };
256 
257 /// The clear color used for the texture cache when the debug display is enabled.
258 /// We use a shade of blue so that we can still identify completely blue items in
259 /// the texture cache.
260 const TEXTURE_CACHE_DBG_CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.8, 1.0];
261 
262 impl BatchKind {
263     #[cfg(feature = "debugger")]
debug_name(&self) -> &'static str264     fn debug_name(&self) -> &'static str {
265         match *self {
266             BatchKind::SplitComposite => "SplitComposite",
267             BatchKind::Brush(kind) => {
268                 match kind {
269                     BrushBatchKind::Solid => "Brush (Solid)",
270                     BrushBatchKind::Image(..) => "Brush (Image)",
271                     BrushBatchKind::Blend => "Brush (Blend)",
272                     BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
273                     BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
274                     BrushBatchKind::ConicGradient => "Brush (ConicGradient)",
275                     BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
276                     BrushBatchKind::LinearGradient => "Brush (LinearGradient)",
277                     BrushBatchKind::Opacity => "Brush (Opacity)",
278                 }
279             }
280             BatchKind::TextRun(_) => "TextRun",
281         }
282     }
283 
sampler_tag(&self) -> GpuProfileTag284     fn sampler_tag(&self) -> GpuProfileTag {
285         match *self {
286             BatchKind::SplitComposite => GPU_TAG_PRIM_SPLIT_COMPOSITE,
287             BatchKind::Brush(kind) => {
288                 match kind {
289                     BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
290                     BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
291                     BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
292                     BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
293                     BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
294                     BrushBatchKind::ConicGradient => GPU_TAG_BRUSH_CONIC_GRADIENT,
295                     BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT,
296                     BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT,
297                     BrushBatchKind::Opacity => GPU_TAG_BRUSH_OPACITY,
298                 }
299             }
300             BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN,
301         }
302     }
303 }
304 
flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool>305 fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
306     if before & select != after & select {
307         Some(after.contains(select))
308     } else {
309         None
310     }
311 }
312 
313 #[repr(C)]
314 #[derive(Copy, Clone, Debug)]
315 pub enum ShaderColorMode {
316     FromRenderPassMode = 0,
317     Alpha = 1,
318     SubpixelConstantTextColor = 2,
319     SubpixelWithBgColorPass0 = 3,
320     SubpixelWithBgColorPass1 = 4,
321     SubpixelWithBgColorPass2 = 5,
322     SubpixelDualSource = 6,
323     Bitmap = 7,
324     ColorBitmap = 8,
325     Image = 9,
326 }
327 
328 impl From<GlyphFormat> for ShaderColorMode {
from(format: GlyphFormat) -> ShaderColorMode329     fn from(format: GlyphFormat) -> ShaderColorMode {
330         match format {
331             GlyphFormat::Alpha | GlyphFormat::TransformedAlpha => ShaderColorMode::Alpha,
332             GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => {
333                 panic!("Subpixel glyph formats must be handled separately.");
334             }
335             GlyphFormat::Bitmap => ShaderColorMode::Bitmap,
336             GlyphFormat::ColorBitmap => ShaderColorMode::ColorBitmap,
337         }
338     }
339 }
340 
341 /// Enumeration of the texture samplers used across the various WebRender shaders.
342 ///
343 /// Each variant corresponds to a uniform declared in shader source. We only bind
344 /// the variants we need for a given shader, so not every variant is bound for every
345 /// batch.
346 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
347 pub(crate) enum TextureSampler {
348     Color0,
349     Color1,
350     Color2,
351     PrevPassAlpha,
352     PrevPassColor,
353     GpuCache,
354     TransformPalette,
355     RenderTasks,
356     Dither,
357     PrimitiveHeadersF,
358     PrimitiveHeadersI,
359 }
360 
361 impl TextureSampler {
color(n: usize) -> TextureSampler362     pub(crate) fn color(n: usize) -> TextureSampler {
363         match n {
364             0 => TextureSampler::Color0,
365             1 => TextureSampler::Color1,
366             2 => TextureSampler::Color2,
367             _ => {
368                 panic!("There are only 3 color samplers.");
369             }
370         }
371     }
372 }
373 
374 impl Into<TextureSlot> for TextureSampler {
into(self) -> TextureSlot375     fn into(self) -> TextureSlot {
376         match self {
377             TextureSampler::Color0 => TextureSlot(0),
378             TextureSampler::Color1 => TextureSlot(1),
379             TextureSampler::Color2 => TextureSlot(2),
380             TextureSampler::PrevPassAlpha => TextureSlot(3),
381             TextureSampler::PrevPassColor => TextureSlot(4),
382             TextureSampler::GpuCache => TextureSlot(5),
383             TextureSampler::TransformPalette => TextureSlot(6),
384             TextureSampler::RenderTasks => TextureSlot(7),
385             TextureSampler::Dither => TextureSlot(8),
386             TextureSampler::PrimitiveHeadersF => TextureSlot(9),
387             TextureSampler::PrimitiveHeadersI => TextureSlot(10),
388         }
389     }
390 }
391 
392 #[derive(Debug, Clone, Copy)]
393 #[repr(C)]
394 pub struct PackedVertex {
395     pub pos: [f32; 2],
396 }
397 
398 pub(crate) mod desc {
399     use crate::device::{VertexAttribute, VertexAttributeKind, VertexDescriptor};
400 
401     pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor {
402         vertex_attributes: &[
403             VertexAttribute {
404                 name: "aPosition",
405                 count: 2,
406                 kind: VertexAttributeKind::F32,
407             },
408         ],
409         instance_attributes: &[
410             VertexAttribute {
411                 name: "aData",
412                 count: 4,
413                 kind: VertexAttributeKind::I32,
414             },
415         ],
416     };
417 
418     pub const BLUR: VertexDescriptor = VertexDescriptor {
419         vertex_attributes: &[
420             VertexAttribute {
421                 name: "aPosition",
422                 count: 2,
423                 kind: VertexAttributeKind::F32,
424             },
425         ],
426         instance_attributes: &[
427             VertexAttribute {
428                 name: "aBlurRenderTaskAddress",
429                 count: 1,
430                 kind: VertexAttributeKind::U16,
431             },
432             VertexAttribute {
433                 name: "aBlurSourceTaskAddress",
434                 count: 1,
435                 kind: VertexAttributeKind::U16,
436             },
437             VertexAttribute {
438                 name: "aBlurDirection",
439                 count: 1,
440                 kind: VertexAttributeKind::I32,
441             },
442         ],
443     };
444 
445     pub const LINE: VertexDescriptor = VertexDescriptor {
446         vertex_attributes: &[
447             VertexAttribute {
448                 name: "aPosition",
449                 count: 2,
450                 kind: VertexAttributeKind::F32,
451             },
452         ],
453         instance_attributes: &[
454             VertexAttribute {
455                 name: "aTaskRect",
456                 count: 4,
457                 kind: VertexAttributeKind::F32,
458             },
459             VertexAttribute {
460                 name: "aLocalSize",
461                 count: 2,
462                 kind: VertexAttributeKind::F32,
463             },
464             VertexAttribute {
465                 name: "aWavyLineThickness",
466                 count: 1,
467                 kind: VertexAttributeKind::F32,
468             },
469             VertexAttribute {
470                 name: "aStyle",
471                 count: 1,
472                 kind: VertexAttributeKind::I32,
473             },
474             VertexAttribute {
475                 name: "aAxisSelect",
476                 count: 1,
477                 kind: VertexAttributeKind::F32,
478             },
479         ],
480     };
481 
482     pub const GRADIENT: VertexDescriptor = VertexDescriptor {
483         vertex_attributes: &[
484             VertexAttribute {
485                 name: "aPosition",
486                 count: 2,
487                 kind: VertexAttributeKind::F32,
488             },
489         ],
490         instance_attributes: &[
491             VertexAttribute {
492                 name: "aTaskRect",
493                 count: 4,
494                 kind: VertexAttributeKind::F32,
495             },
496             VertexAttribute {
497                 name: "aStops",
498                 count: 4,
499                 kind: VertexAttributeKind::F32,
500             },
501             // TODO(gw): We should probably pack these as u32 colors instead
502             //           of passing as full float vec4 here. It won't make much
503             //           difference in real world, since these are only invoked
504             //           rarely, when creating the cache.
505             VertexAttribute {
506                 name: "aColor0",
507                 count: 4,
508                 kind: VertexAttributeKind::F32,
509             },
510             VertexAttribute {
511                 name: "aColor1",
512                 count: 4,
513                 kind: VertexAttributeKind::F32,
514             },
515             VertexAttribute {
516                 name: "aColor2",
517                 count: 4,
518                 kind: VertexAttributeKind::F32,
519             },
520             VertexAttribute {
521                 name: "aColor3",
522                 count: 4,
523                 kind: VertexAttributeKind::F32,
524             },
525             VertexAttribute {
526                 name: "aAxisSelect",
527                 count: 1,
528                 kind: VertexAttributeKind::F32,
529             },
530             VertexAttribute {
531                 name: "aStartStop",
532                 count: 2,
533                 kind: VertexAttributeKind::F32,
534             },
535         ],
536     };
537 
538     pub const BORDER: VertexDescriptor = VertexDescriptor {
539         vertex_attributes: &[
540             VertexAttribute {
541                 name: "aPosition",
542                 count: 2,
543                 kind: VertexAttributeKind::F32,
544             },
545         ],
546         instance_attributes: &[
547             VertexAttribute {
548                 name: "aTaskOrigin",
549                 count: 2,
550                 kind: VertexAttributeKind::F32,
551             },
552             VertexAttribute {
553                 name: "aRect",
554                 count: 4,
555                 kind: VertexAttributeKind::F32,
556             },
557             VertexAttribute {
558                 name: "aColor0",
559                 count: 4,
560                 kind: VertexAttributeKind::F32,
561             },
562             VertexAttribute {
563                 name: "aColor1",
564                 count: 4,
565                 kind: VertexAttributeKind::F32,
566             },
567             VertexAttribute {
568                 name: "aFlags",
569                 count: 1,
570                 kind: VertexAttributeKind::I32,
571             },
572             VertexAttribute {
573                 name: "aWidths",
574                 count: 2,
575                 kind: VertexAttributeKind::F32,
576             },
577             VertexAttribute {
578                 name: "aRadii",
579                 count: 2,
580                 kind: VertexAttributeKind::F32,
581             },
582             VertexAttribute {
583                 name: "aClipParams1",
584                 count: 4,
585                 kind: VertexAttributeKind::F32,
586             },
587             VertexAttribute {
588                 name: "aClipParams2",
589                 count: 4,
590                 kind: VertexAttributeKind::F32,
591             },
592         ],
593     };
594 
595     pub const SCALE: VertexDescriptor = VertexDescriptor {
596         vertex_attributes: &[
597             VertexAttribute {
598                 name: "aPosition",
599                 count: 2,
600                 kind: VertexAttributeKind::F32,
601             },
602         ],
603         instance_attributes: &[
604             VertexAttribute {
605                 name: "aScaleTargetRect",
606                 count: 4,
607                 kind: VertexAttributeKind::F32,
608             },
609             VertexAttribute {
610                 name: "aScaleSourceRect",
611                 count: 4,
612                 kind: VertexAttributeKind::I32,
613             },
614             VertexAttribute {
615                 name: "aScaleSourceLayer",
616                 count: 1,
617                 kind: VertexAttributeKind::I32,
618             },
619         ],
620     };
621 
622     pub const CLIP: VertexDescriptor = VertexDescriptor {
623         vertex_attributes: &[
624             VertexAttribute {
625                 name: "aPosition",
626                 count: 2,
627                 kind: VertexAttributeKind::F32,
628             },
629         ],
630         instance_attributes: &[
631             VertexAttribute {
632                 name: "aTransformIds",
633                 count: 2,
634                 kind: VertexAttributeKind::I32,
635             },
636             VertexAttribute {
637                 name: "aClipDataResourceAddress",
638                 count: 4,
639                 kind: VertexAttributeKind::U16,
640             },
641             VertexAttribute {
642                 name: "aClipLocalPos",
643                 count: 2,
644                 kind: VertexAttributeKind::F32,
645             },
646             VertexAttribute {
647                 name: "aClipTileRect",
648                 count: 4,
649                 kind: VertexAttributeKind::F32,
650             },
651             VertexAttribute {
652                 name: "aClipDeviceArea",
653                 count: 4,
654                 kind: VertexAttributeKind::F32,
655             },
656             VertexAttribute {
657                 name: "aClipOrigins",
658                 count: 4,
659                 kind: VertexAttributeKind::F32,
660             },
661             VertexAttribute {
662                 name: "aDevicePixelScale",
663                 count: 1,
664                 kind: VertexAttributeKind::F32,
665             },
666         ],
667     };
668 
669     pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor {
670         vertex_attributes: &[
671             VertexAttribute {
672                 name: "aPosition",
673                 count: 2,
674                 kind: VertexAttributeKind::U16Norm,
675             },
676             VertexAttribute {
677                 name: "aValue",
678                 count: 4,
679                 kind: VertexAttributeKind::F32,
680             },
681         ],
682         instance_attributes: &[],
683     };
684 
685     pub const RESOLVE: VertexDescriptor = VertexDescriptor {
686         vertex_attributes: &[
687             VertexAttribute {
688                 name: "aPosition",
689                 count: 2,
690                 kind: VertexAttributeKind::F32,
691             },
692         ],
693         instance_attributes: &[
694             VertexAttribute {
695                 name: "aRect",
696                 count: 4,
697                 kind: VertexAttributeKind::F32,
698             },
699         ],
700     };
701 
702     pub const SVG_FILTER: VertexDescriptor = VertexDescriptor {
703         vertex_attributes: &[
704             VertexAttribute {
705                 name: "aPosition",
706                 count: 2,
707                 kind: VertexAttributeKind::F32,
708             },
709         ],
710         instance_attributes: &[
711             VertexAttribute {
712                 name: "aFilterRenderTaskAddress",
713                 count: 1,
714                 kind: VertexAttributeKind::U16,
715             },
716             VertexAttribute {
717                 name: "aFilterInput1TaskAddress",
718                 count: 1,
719                 kind: VertexAttributeKind::U16,
720             },
721             VertexAttribute {
722                 name: "aFilterInput2TaskAddress",
723                 count: 1,
724                 kind: VertexAttributeKind::U16,
725             },
726             VertexAttribute {
727                 name: "aFilterKind",
728                 count: 1,
729                 kind: VertexAttributeKind::U16,
730             },
731             VertexAttribute {
732                 name: "aFilterInputCount",
733                 count: 1,
734                 kind: VertexAttributeKind::U16,
735             },
736             VertexAttribute {
737                 name: "aFilterGenericInt",
738                 count: 1,
739                 kind: VertexAttributeKind::U16,
740             },
741             VertexAttribute {
742                 name: "aFilterExtraDataAddress",
743                 count: 2,
744                 kind: VertexAttributeKind::U16,
745             },
746         ],
747     };
748 
749     pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor {
750         vertex_attributes: &[
751             VertexAttribute {
752                 name: "aPosition",
753                 count: 2,
754                 kind: VertexAttributeKind::F32,
755             },
756         ],
757         instance_attributes: &[
758             VertexAttribute {
759                 name: "aFromPosition",
760                 count: 2,
761                 kind: VertexAttributeKind::F32,
762             },
763             VertexAttribute {
764                 name: "aCtrlPosition",
765                 count: 2,
766                 kind: VertexAttributeKind::F32,
767             },
768             VertexAttribute {
769                 name: "aToPosition",
770                 count: 2,
771                 kind: VertexAttributeKind::F32,
772             },
773             VertexAttribute {
774                 name: "aFromNormal",
775                 count: 2,
776                 kind: VertexAttributeKind::F32,
777             },
778             VertexAttribute {
779                 name: "aCtrlNormal",
780                 count: 2,
781                 kind: VertexAttributeKind::F32,
782             },
783             VertexAttribute {
784                 name: "aToNormal",
785                 count: 2,
786                 kind: VertexAttributeKind::F32,
787             },
788             VertexAttribute {
789                 name: "aPathID",
790                 count: 1,
791                 kind: VertexAttributeKind::U16,
792             },
793             VertexAttribute {
794                 name: "aPad",
795                 count: 1,
796                 kind: VertexAttributeKind::U16,
797             },
798         ],
799     };
800 
801     pub const VECTOR_COVER: VertexDescriptor = VertexDescriptor {
802         vertex_attributes: &[
803             VertexAttribute {
804                 name: "aPosition",
805                 count: 2,
806                 kind: VertexAttributeKind::F32,
807             },
808         ],
809         instance_attributes: &[
810             VertexAttribute {
811                 name: "aTargetRect",
812                 count: 4,
813                 kind: VertexAttributeKind::I32,
814             },
815             VertexAttribute {
816                 name: "aStencilOrigin",
817                 count: 2,
818                 kind: VertexAttributeKind::I32,
819             },
820             VertexAttribute {
821                 name: "aSubpixel",
822                 count: 1,
823                 kind: VertexAttributeKind::U16,
824             },
825             VertexAttribute {
826                 name: "aPad",
827                 count: 1,
828                 kind: VertexAttributeKind::U16,
829             },
830         ],
831     };
832 
833     pub const COMPOSITE: VertexDescriptor = VertexDescriptor {
834         vertex_attributes: &[
835             VertexAttribute {
836                 name: "aPosition",
837                 count: 2,
838                 kind: VertexAttributeKind::F32,
839             },
840         ],
841         instance_attributes: &[
842             VertexAttribute {
843                 name: "aDeviceRect",
844                 count: 4,
845                 kind: VertexAttributeKind::F32,
846             },
847             VertexAttribute {
848                 name: "aDeviceClipRect",
849                 count: 4,
850                 kind: VertexAttributeKind::F32,
851             },
852             VertexAttribute {
853                 name: "aColor",
854                 count: 4,
855                 kind: VertexAttributeKind::F32,
856             },
857             VertexAttribute {
858                 name: "aParams",
859                 count: 4,
860                 kind: VertexAttributeKind::F32,
861             },
862             VertexAttribute {
863                 name: "aUvRect0",
864                 count: 4,
865                 kind: VertexAttributeKind::F32,
866             },
867             VertexAttribute {
868                 name: "aUvRect1",
869                 count: 4,
870                 kind: VertexAttributeKind::F32,
871             },
872             VertexAttribute {
873                 name: "aUvRect2",
874                 count: 4,
875                 kind: VertexAttributeKind::F32,
876             },
877             VertexAttribute {
878                 name: "aTextureLayers",
879                 count: 3,
880                 kind: VertexAttributeKind::F32,
881             },
882         ],
883     };
884 }
885 
886 #[derive(Debug, Copy, Clone)]
887 pub(crate) enum VertexArrayKind {
888     Primitive,
889     Blur,
890     Clip,
891     VectorStencil,
892     VectorCover,
893     Border,
894     Scale,
895     LineDecoration,
896     Gradient,
897     Resolve,
898     SvgFilter,
899     Composite,
900 }
901 
902 #[derive(Clone, Debug, PartialEq)]
903 pub enum GraphicsApi {
904     OpenGL,
905 }
906 
907 #[derive(Clone, Debug)]
908 pub struct GraphicsApiInfo {
909     pub kind: GraphicsApi,
910     pub renderer: String,
911     pub version: String,
912 }
913 
914 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
915 #[cfg_attr(feature = "capture", derive(Serialize))]
916 #[cfg_attr(feature = "replay", derive(Deserialize))]
917 pub enum ImageBufferKind {
918     Texture2D = 0,
919     TextureRect = 1,
920     TextureExternal = 2,
921     Texture2DArray = 3,
922 }
923 
924 //TODO: those types are the same, so let's merge them
925 impl From<TextureTarget> for ImageBufferKind {
from(target: TextureTarget) -> Self926     fn from(target: TextureTarget) -> Self {
927         match target {
928             TextureTarget::Default => ImageBufferKind::Texture2D,
929             TextureTarget::Rect => ImageBufferKind::TextureRect,
930             TextureTarget::Array => ImageBufferKind::Texture2DArray,
931             TextureTarget::External => ImageBufferKind::TextureExternal,
932         }
933     }
934 }
935 
936 #[derive(Debug)]
937 pub struct GpuProfile {
938     pub frame_id: GpuFrameId,
939     pub paint_time_ns: u64,
940 }
941 
942 impl GpuProfile {
new<T>(frame_id: GpuFrameId, timers: &[GpuTimer<T>]) -> GpuProfile943     fn new<T>(frame_id: GpuFrameId, timers: &[GpuTimer<T>]) -> GpuProfile {
944         let mut paint_time_ns = 0;
945         for timer in timers {
946             paint_time_ns += timer.time_ns;
947         }
948         GpuProfile {
949             frame_id,
950             paint_time_ns,
951         }
952     }
953 }
954 
955 #[derive(Debug)]
956 pub struct CpuProfile {
957     pub frame_id: GpuFrameId,
958     pub backend_time_ns: u64,
959     pub composite_time_ns: u64,
960     pub draw_calls: usize,
961 }
962 
963 impl CpuProfile {
new( frame_id: GpuFrameId, backend_time_ns: u64, composite_time_ns: u64, draw_calls: usize, ) -> CpuProfile964     fn new(
965         frame_id: GpuFrameId,
966         backend_time_ns: u64,
967         composite_time_ns: u64,
968         draw_calls: usize,
969     ) -> CpuProfile {
970         CpuProfile {
971             frame_id,
972             backend_time_ns,
973             composite_time_ns,
974             draw_calls,
975         }
976     }
977 }
978 
979 /// The selected partial present mode for a given frame.
980 #[derive(Debug, Copy, Clone)]
981 enum PartialPresentMode {
982     /// The device supports fewer dirty rects than the number of dirty rects
983     /// that WR produced. In this case, the WR dirty rects are union'ed into
984     /// a single dirty rect, that is provided to the caller.
985     Single {
986         dirty_rect: DeviceRect,
987     },
988 }
989 
990 /// A Texture that has been initialized by the `device` module and is ready to
991 /// be used.
992 struct ActiveTexture {
993     texture: Texture,
994     saved_index: Option<SavedTargetIndex>,
995 }
996 
997 /// Helper struct for resolving device Textures for use during rendering passes.
998 ///
999 /// Manages the mapping between the at-a-distance texture handles used by the
1000 /// `RenderBackend` (which does not directly interface with the GPU) and actual
1001 /// device texture handles.
1002 struct TextureResolver {
1003     /// A map to resolve texture cache IDs to native textures.
1004     texture_cache_map: FastHashMap<CacheTextureId, Texture>,
1005 
1006     /// Map of external image IDs to native textures.
1007     external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
1008 
1009     /// A special 1x1 dummy texture used for shaders that expect to work with
1010     /// the output of the previous pass but are actually running in the first
1011     /// pass.
1012     dummy_cache_texture: Texture,
1013 
1014     /// The outputs of the previous pass, if applicable.
1015     prev_pass_color: Option<ActiveTexture>,
1016     prev_pass_alpha: Option<ActiveTexture>,
1017 
1018     /// Saved render targets from previous passes. This is used when a pass
1019     /// needs access to the result of a pass other than the immediately-preceding
1020     /// one. In this case, the `RenderTask` will get a non-`None` `saved_index`,
1021     /// which will cause the resulting render target to be persisted in this list
1022     /// (at that index) until the end of the frame.
1023     saved_targets: Vec<Texture>,
1024 
1025     /// Pool of idle render target textures ready for re-use.
1026     ///
1027     /// Naively, it would seem like we only ever need two pairs of (color,
1028     /// alpha) render targets: one for the output of the previous pass (serving
1029     /// as input to the current pass), and one for the output of the current
1030     /// pass. However, there are cases where the output of one pass is used as
1031     /// the input to multiple future passes. For example, drop-shadows draw the
1032     /// picture in pass X, then reference it in pass X+1 to create the blurred
1033     /// shadow, and pass the results of both X and X+1 to pass X+2 draw the
1034     /// actual content.
1035     ///
1036     /// See the comments in `allocate_target_texture` for more insight on why
1037     /// reuse is a win.
1038     render_target_pool: Vec<Texture>,
1039 }
1040 
1041 impl TextureResolver {
new(device: &mut Device) -> TextureResolver1042     fn new(device: &mut Device) -> TextureResolver {
1043         let dummy_cache_texture = device
1044             .create_texture(
1045                 TextureTarget::Array,
1046                 ImageFormat::RGBA8,
1047                 1,
1048                 1,
1049                 TextureFilter::Linear,
1050                 None,
1051                 1,
1052             );
1053         device.upload_texture_immediate(
1054             &dummy_cache_texture,
1055             &[0xff, 0xff, 0xff, 0xff],
1056         );
1057 
1058         TextureResolver {
1059             texture_cache_map: FastHashMap::default(),
1060             external_images: FastHashMap::default(),
1061             dummy_cache_texture,
1062             prev_pass_alpha: None,
1063             prev_pass_color: None,
1064             saved_targets: Vec::default(),
1065             render_target_pool: Vec::new(),
1066         }
1067     }
1068 
deinit(self, device: &mut Device)1069     fn deinit(self, device: &mut Device) {
1070         device.delete_texture(self.dummy_cache_texture);
1071 
1072         for (_id, texture) in self.texture_cache_map {
1073             device.delete_texture(texture);
1074         }
1075 
1076         for texture in self.render_target_pool {
1077             device.delete_texture(texture);
1078         }
1079     }
1080 
begin_frame(&mut self)1081     fn begin_frame(&mut self) {
1082         assert!(self.prev_pass_color.is_none());
1083         assert!(self.prev_pass_alpha.is_none());
1084         assert!(self.saved_targets.is_empty());
1085     }
1086 
end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId)1087     fn end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId) {
1088         // return the cached targets to the pool
1089         self.end_pass(device, None, None);
1090         // return the saved targets as well
1091         while let Some(target) = self.saved_targets.pop() {
1092             self.return_to_pool(device, target);
1093         }
1094 
1095         // GC the render target pool, if it's currently > 32 MB in size.
1096         //
1097         // We use a simple scheme whereby we drop any texture that hasn't been used
1098         // in the last 60 frames, until we are below the size threshold. This should
1099         // generally prevent any sustained build-up of unused textures, unless we don't
1100         // generate frames for a long period. This can happen when the window is
1101         // minimized, and we probably want to flush all the WebRender caches in that case [1].
1102         // There is also a second "red line" memory threshold which prevents
1103         // memory exhaustion if many render targets are allocated within a small
1104         // number of frames. For now this is set at 320 MB (10x the normal memory threshold).
1105         //
1106         // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1494099
1107         self.gc_targets(
1108             device,
1109             frame_id,
1110             32 * 1024 * 1024,
1111             32 * 1024 * 1024 * 10,
1112             60,
1113         );
1114     }
1115 
1116     /// Transfers ownership of a render target back to the pool.
return_to_pool(&mut self, device: &mut Device, target: Texture)1117     fn return_to_pool(&mut self, device: &mut Device, target: Texture) {
1118         device.invalidate_render_target(&target);
1119         self.render_target_pool.push(target);
1120     }
1121 
1122     /// Frees any memory possible, in the event of a memory pressure signal.
on_memory_pressure( &mut self, device: &mut Device, )1123     fn on_memory_pressure(
1124         &mut self,
1125         device: &mut Device,
1126     ) {
1127         // Clear all textures in the render target pool
1128         for target in self.render_target_pool.drain(..) {
1129             device.delete_texture(target);
1130         }
1131     }
1132 
1133     /// Drops all targets from the render target pool that do not satisfy the predicate.
gc_targets( &mut self, device: &mut Device, current_frame_id: GpuFrameId, total_bytes_threshold: usize, total_bytes_red_line_threshold: usize, frames_threshold: usize, )1134     pub fn gc_targets(
1135         &mut self,
1136         device: &mut Device,
1137         current_frame_id: GpuFrameId,
1138         total_bytes_threshold: usize,
1139         total_bytes_red_line_threshold: usize,
1140         frames_threshold: usize,
1141     ) {
1142         // Get the total GPU memory size used by the current render target pool
1143         let mut rt_pool_size_in_bytes: usize = self.render_target_pool
1144             .iter()
1145             .map(|t| t.size_in_bytes())
1146             .sum();
1147 
1148         // If the total size of the pool is less than the threshold, don't bother
1149         // trying to GC any targets
1150         if rt_pool_size_in_bytes <= total_bytes_threshold {
1151             return;
1152         }
1153 
1154         // Sort the current pool by age, so that we remove oldest textures first
1155         self.render_target_pool.sort_by_key(|t| t.last_frame_used());
1156 
1157         // We can't just use retain() because `Texture` requires manual cleanup.
1158         let mut retained_targets = SmallVec::<[Texture; 8]>::new();
1159 
1160         for target in self.render_target_pool.drain(..) {
1161             // Drop oldest textures until we are under the allowed size threshold.
1162             // However, if it's been used in very recently, it is always kept around,
1163             // which ensures we don't thrash texture allocations on pages that do
1164             // require a very large render target pool and are regularly changing.
1165             if (rt_pool_size_in_bytes > total_bytes_red_line_threshold) ||
1166                (rt_pool_size_in_bytes > total_bytes_threshold &&
1167                 !target.used_recently(current_frame_id, frames_threshold))
1168             {
1169                 rt_pool_size_in_bytes -= target.size_in_bytes();
1170                 device.delete_texture(target);
1171             } else {
1172                 retained_targets.push(target);
1173             }
1174         }
1175 
1176         self.render_target_pool.extend(retained_targets);
1177     }
1178 
end_pass( &mut self, device: &mut Device, a8_texture: Option<ActiveTexture>, rgba8_texture: Option<ActiveTexture>, )1179     fn end_pass(
1180         &mut self,
1181         device: &mut Device,
1182         a8_texture: Option<ActiveTexture>,
1183         rgba8_texture: Option<ActiveTexture>,
1184     ) {
1185         // If we have cache textures from previous pass, return them to the pool.
1186         // Also assign the pool index of those cache textures to last pass's index because this is
1187         // the result of last pass.
1188         // Note: the order here is important, needs to match the logic in `RenderPass::build()`.
1189         if let Some(at) = self.prev_pass_color.take() {
1190             if let Some(index) = at.saved_index {
1191                 assert_eq!(self.saved_targets.len(), index.0);
1192                 self.saved_targets.push(at.texture);
1193             } else {
1194                 self.return_to_pool(device, at.texture);
1195             }
1196         }
1197         if let Some(at) = self.prev_pass_alpha.take() {
1198             if let Some(index) = at.saved_index {
1199                 assert_eq!(self.saved_targets.len(), index.0);
1200                 self.saved_targets.push(at.texture);
1201             } else {
1202                 self.return_to_pool(device, at.texture);
1203             }
1204         }
1205 
1206         // We have another pass to process, make these textures available
1207         // as inputs to the next pass.
1208         self.prev_pass_color = rgba8_texture;
1209         self.prev_pass_alpha = a8_texture;
1210     }
1211 
1212     // Bind a source texture to the device.
bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) -> Swizzle1213     fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) -> Swizzle {
1214         match *texture_id {
1215             TextureSource::Invalid => {
1216                 Swizzle::default()
1217             }
1218             TextureSource::Dummy => {
1219                 let swizzle = Swizzle::default();
1220                 device.bind_texture(sampler, &self.dummy_cache_texture, swizzle);
1221                 swizzle
1222             }
1223             TextureSource::PrevPassAlpha => {
1224                 let texture = match self.prev_pass_alpha {
1225                     Some(ref at) => &at.texture,
1226                     None => &self.dummy_cache_texture,
1227                 };
1228                 let swizzle = Swizzle::default();
1229                 device.bind_texture(sampler, texture, swizzle);
1230                 swizzle
1231             }
1232             TextureSource::PrevPassColor => {
1233                 let texture = match self.prev_pass_color {
1234                     Some(ref at) => &at.texture,
1235                     None => &self.dummy_cache_texture,
1236                 };
1237                 let swizzle = Swizzle::default();
1238                 device.bind_texture(sampler, texture, swizzle);
1239                 swizzle
1240             }
1241             TextureSource::External(external_image) => {
1242                 let texture = self.external_images
1243                     .get(&(external_image.id, external_image.channel_index))
1244                     .expect("BUG: External image should be resolved by now");
1245                 device.bind_external_texture(sampler, texture);
1246                 Swizzle::default()
1247             }
1248             TextureSource::TextureCache(index, swizzle) => {
1249                 let texture = &self.texture_cache_map[&index];
1250                 device.bind_texture(sampler, texture, swizzle);
1251                 swizzle
1252             }
1253             TextureSource::RenderTaskCache(saved_index, swizzle) => {
1254                 if saved_index.0 < self.saved_targets.len() {
1255                     let texture = &self.saved_targets[saved_index.0];
1256                     device.bind_texture(sampler, texture, swizzle)
1257                 } else {
1258                     // Check if this saved index is referring to a the prev pass
1259                     if Some(saved_index) == self.prev_pass_color.as_ref().and_then(|at| at.saved_index) {
1260                         let texture = match self.prev_pass_color {
1261                             Some(ref at) => &at.texture,
1262                             None => &self.dummy_cache_texture,
1263                         };
1264                         device.bind_texture(sampler, texture, swizzle);
1265                     } else if Some(saved_index) == self.prev_pass_alpha.as_ref().and_then(|at| at.saved_index) {
1266                         let texture = match self.prev_pass_alpha {
1267                             Some(ref at) => &at.texture,
1268                             None => &self.dummy_cache_texture,
1269                         };
1270                         device.bind_texture(sampler, texture, swizzle);
1271                     }
1272                 }
1273                 swizzle
1274             }
1275         }
1276     }
1277 
1278     // Get the real (OpenGL) texture ID for a given source texture.
1279     // For a texture cache texture, the IDs are stored in a vector
1280     // map for fast access.
resolve(&self, texture_id: &TextureSource) -> Option<(&Texture, Swizzle)>1281     fn resolve(&self, texture_id: &TextureSource) -> Option<(&Texture, Swizzle)> {
1282         match *texture_id {
1283             TextureSource::Invalid => None,
1284             TextureSource::Dummy => {
1285                 Some((&self.dummy_cache_texture, Swizzle::default()))
1286             }
1287             TextureSource::PrevPassAlpha => Some((
1288                 match self.prev_pass_alpha {
1289                     Some(ref at) => &at.texture,
1290                     None => &self.dummy_cache_texture,
1291                 },
1292                 Swizzle::default(),
1293             )),
1294             TextureSource::PrevPassColor => Some((
1295                 match self.prev_pass_color {
1296                     Some(ref at) => &at.texture,
1297                     None => &self.dummy_cache_texture,
1298                 },
1299                 Swizzle::default(),
1300             )),
1301             TextureSource::External(..) => {
1302                 panic!("BUG: External textures cannot be resolved, they can only be bound.");
1303             }
1304             TextureSource::TextureCache(index, swizzle) => {
1305                 Some((&self.texture_cache_map[&index], swizzle))
1306             }
1307             TextureSource::RenderTaskCache(saved_index, swizzle) => {
1308                 Some((&self.saved_targets[saved_index.0], swizzle))
1309             }
1310         }
1311     }
1312 
1313     // Retrieve the deferred / resolved UV rect if an external texture, otherwise
1314     // return the default supplied UV rect.
get_uv_rect( &self, source: &TextureSource, default_value: TexelRect, ) -> TexelRect1315     fn get_uv_rect(
1316         &self,
1317         source: &TextureSource,
1318         default_value: TexelRect,
1319     ) -> TexelRect {
1320         match source {
1321             TextureSource::External(ref external_image) => {
1322                 let texture = self.external_images
1323                     .get(&(external_image.id, external_image.channel_index))
1324                     .expect("BUG: External image should be resolved by now");
1325                 texture.get_uv_rect()
1326             }
1327             _ => {
1328                 default_value
1329             }
1330         }
1331     }
1332 
report_memory(&self) -> MemoryReport1333     fn report_memory(&self) -> MemoryReport {
1334         let mut report = MemoryReport::default();
1335 
1336         // We're reporting GPU memory rather than heap-allocations, so we don't
1337         // use size_of_op.
1338         for t in self.texture_cache_map.values() {
1339             report.texture_cache_textures += t.size_in_bytes();
1340         }
1341         for t in self.render_target_pool.iter() {
1342             report.render_target_textures += t.size_in_bytes();
1343         }
1344 
1345         report
1346     }
1347 }
1348 
1349 #[derive(Debug, Copy, Clone, PartialEq)]
1350 #[cfg_attr(feature = "capture", derive(Serialize))]
1351 #[cfg_attr(feature = "replay", derive(Deserialize))]
1352 pub enum BlendMode {
1353     None,
1354     Alpha,
1355     PremultipliedAlpha,
1356     PremultipliedDestOut,
1357     SubpixelDualSource,
1358     SubpixelConstantTextColor(ColorF),
1359     SubpixelWithBgColor,
1360     Advanced(MixBlendMode),
1361 }
1362 
1363 /// Tracks the state of each row in the GPU cache texture.
1364 struct CacheRow {
1365     /// Mirrored block data on CPU for this row. We store a copy of
1366     /// the data on the CPU side to improve upload batching.
1367     cpu_blocks: Box<[GpuBlockData; MAX_VERTEX_TEXTURE_WIDTH]>,
1368     /// The first offset in this row that is dirty.
1369     min_dirty: u16,
1370     /// The last offset in this row that is dirty.
1371     max_dirty: u16,
1372 }
1373 
1374 impl CacheRow {
new() -> Self1375     fn new() -> Self {
1376         CacheRow {
1377             cpu_blocks: Box::new([GpuBlockData::EMPTY; MAX_VERTEX_TEXTURE_WIDTH]),
1378             min_dirty: MAX_VERTEX_TEXTURE_WIDTH as _,
1379             max_dirty: 0,
1380         }
1381     }
1382 
is_dirty(&self) -> bool1383     fn is_dirty(&self) -> bool {
1384         return self.min_dirty < self.max_dirty;
1385     }
1386 
clear_dirty(&mut self)1387     fn clear_dirty(&mut self) {
1388         self.min_dirty = MAX_VERTEX_TEXTURE_WIDTH as _;
1389         self.max_dirty = 0;
1390     }
1391 
add_dirty(&mut self, block_offset: usize, block_count: usize)1392     fn add_dirty(&mut self, block_offset: usize, block_count: usize) {
1393         self.min_dirty = self.min_dirty.min(block_offset as _);
1394         self.max_dirty = self.max_dirty.max((block_offset + block_count) as _);
1395     }
1396 
dirty_blocks(&self) -> &[GpuBlockData]1397     fn dirty_blocks(&self) -> &[GpuBlockData] {
1398         return &self.cpu_blocks[self.min_dirty as usize .. self.max_dirty as usize];
1399     }
1400 }
1401 
1402 /// The bus over which CPU and GPU versions of the GPU cache
1403 /// get synchronized.
1404 enum GpuCacheBus {
1405     /// PBO-based updates, currently operate on a row granularity.
1406     /// Therefore, are subject to fragmentation issues.
1407     PixelBuffer {
1408         /// PBO used for transfers.
1409         buffer: PBO,
1410         /// Per-row data.
1411         rows: Vec<CacheRow>,
1412     },
1413     /// Shader-based scattering updates. Currently rendered by a set
1414     /// of points into the GPU texture, each carrying a `GpuBlockData`.
1415     Scatter {
1416         /// Special program to run the scattered update.
1417         program: Program,
1418         /// VAO containing the source vertex buffers.
1419         vao: CustomVAO,
1420         /// VBO for positional data, supplied as normalized `u16`.
1421         buf_position: VBO<[u16; 2]>,
1422         /// VBO for gpu block data.
1423         buf_value: VBO<GpuBlockData>,
1424         /// Currently stored block count.
1425         count: usize,
1426     },
1427 }
1428 
1429 /// The device-specific representation of the cache texture in gpu_cache.rs
1430 struct GpuCacheTexture {
1431     texture: Option<Texture>,
1432     bus: GpuCacheBus,
1433 }
1434 
1435 impl GpuCacheTexture {
1436 
1437     /// Ensures that we have an appropriately-sized texture. Returns true if a
1438     /// new texture was created.
ensure_texture(&mut self, device: &mut Device, height: i32)1439     fn ensure_texture(&mut self, device: &mut Device, height: i32) {
1440         // If we already have a texture that works, we're done.
1441         if self.texture.as_ref().map_or(false, |t| t.get_dimensions().height >= height) {
1442             if GPU_CACHE_RESIZE_TEST {
1443                 // Special debug mode - resize the texture even though it's fine.
1444             } else {
1445                 return;
1446             }
1447         }
1448 
1449         // Take the old texture, if any.
1450         let blit_source = self.texture.take();
1451 
1452         // Create the new texture.
1453         assert!(height >= 2, "Height is too small for ANGLE");
1454         let new_size = DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as _, height);
1455         // If glCopyImageSubData is supported, this texture doesn't need
1456         // to be a render target. This prevents GL errors due to framebuffer
1457         // incompleteness on devices that don't support RGBAF32 render targets.
1458         // TODO(gw): We still need a proper solution for the subset of devices
1459         //           that don't support glCopyImageSubData *OR* rendering to a
1460         //           RGBAF32 render target. These devices will currently fail
1461         //           to resize the GPU cache texture.
1462         let supports_copy_image_sub_data = device.get_capabilities().supports_copy_image_sub_data;
1463         let rt_info =  if supports_copy_image_sub_data {
1464             None
1465         } else {
1466             Some(RenderTargetInfo { has_depth: false })
1467         };
1468         let mut texture = device.create_texture(
1469             TextureTarget::Default,
1470             ImageFormat::RGBAF32,
1471             new_size.width,
1472             new_size.height,
1473             TextureFilter::Nearest,
1474             rt_info,
1475             1,
1476         );
1477 
1478         // Blit the contents of the previous texture, if applicable.
1479         if let Some(blit_source) = blit_source {
1480             device.blit_renderable_texture(&mut texture, &blit_source);
1481             device.delete_texture(blit_source);
1482         }
1483 
1484         self.texture = Some(texture);
1485     }
1486 
new(device: &mut Device, use_scatter: bool) -> Result<Self, RendererError>1487     fn new(device: &mut Device, use_scatter: bool) -> Result<Self, RendererError> {
1488         let bus = if use_scatter {
1489             let program = device.create_program_linked(
1490                 "gpu_cache_update",
1491                 &[],
1492                 &desc::GPU_CACHE_UPDATE,
1493             )?;
1494             let buf_position = device.create_vbo();
1495             let buf_value = device.create_vbo();
1496             //Note: the vertex attributes have to be supplied in the same order
1497             // as for program creation, but each assigned to a different stream.
1498             let vao = device.create_custom_vao(&[
1499                 buf_position.stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[0..1]),
1500                 buf_value   .stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[1..2]),
1501             ]);
1502             GpuCacheBus::Scatter {
1503                 program,
1504                 vao,
1505                 buf_position,
1506                 buf_value,
1507                 count: 0,
1508             }
1509         } else {
1510             let buffer = device.create_pbo();
1511             GpuCacheBus::PixelBuffer {
1512                 buffer,
1513                 rows: Vec::new(),
1514             }
1515         };
1516 
1517         Ok(GpuCacheTexture {
1518             texture: None,
1519             bus,
1520         })
1521     }
1522 
deinit(mut self, device: &mut Device)1523     fn deinit(mut self, device: &mut Device) {
1524         if let Some(t) = self.texture.take() {
1525             device.delete_texture(t);
1526         }
1527         match self.bus {
1528             GpuCacheBus::PixelBuffer { buffer, ..} => {
1529                 device.delete_pbo(buffer);
1530             }
1531             GpuCacheBus::Scatter { program, vao, buf_position, buf_value, ..} => {
1532                 device.delete_program(program);
1533                 device.delete_custom_vao(vao);
1534                 device.delete_vbo(buf_position);
1535                 device.delete_vbo(buf_value);
1536             }
1537         }
1538     }
1539 
get_height(&self) -> i321540     fn get_height(&self) -> i32 {
1541         self.texture.as_ref().map_or(0, |t| t.get_dimensions().height)
1542     }
1543 
prepare_for_updates( &mut self, device: &mut Device, total_block_count: usize, max_height: i32, )1544     fn prepare_for_updates(
1545         &mut self,
1546         device: &mut Device,
1547         total_block_count: usize,
1548         max_height: i32,
1549     ) {
1550         self.ensure_texture(device, max_height);
1551         match self.bus {
1552             GpuCacheBus::PixelBuffer { .. } => {},
1553             GpuCacheBus::Scatter {
1554                 ref mut buf_position,
1555                 ref mut buf_value,
1556                 ref mut count,
1557                 ..
1558             } => {
1559                 *count = 0;
1560                 if total_block_count > buf_value.allocated_count() {
1561                     device.allocate_vbo(buf_position, total_block_count, VertexUsageHint::Stream);
1562                     device.allocate_vbo(buf_value,    total_block_count, VertexUsageHint::Stream);
1563                 }
1564             }
1565         }
1566     }
1567 
update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList)1568     fn update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList) {
1569         match self.bus {
1570             GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
1571                 for update in &updates.updates {
1572                     match *update {
1573                         GpuCacheUpdate::Copy {
1574                             block_index,
1575                             block_count,
1576                             address,
1577                         } => {
1578                             let row = address.v as usize;
1579 
1580                             // Ensure that the CPU-side shadow copy of the GPU cache data has enough
1581                             // rows to apply this patch.
1582                             while rows.len() <= row {
1583                                 // Add a new row.
1584                                 rows.push(CacheRow::new());
1585                             }
1586 
1587                             // Copy the blocks from the patch array in the shadow CPU copy.
1588                             let block_offset = address.u as usize;
1589                             let data = &mut rows[row].cpu_blocks;
1590                             for i in 0 .. block_count {
1591                                 data[block_offset + i] = updates.blocks[block_index + i];
1592                             }
1593 
1594                             // This row is dirty (needs to be updated in GPU texture).
1595                             rows[row].add_dirty(block_offset, block_count);
1596                         }
1597                     }
1598                 }
1599             }
1600             GpuCacheBus::Scatter {
1601                 ref buf_position,
1602                 ref buf_value,
1603                 ref mut count,
1604                 ..
1605             } => {
1606                 //TODO: re-use this heap allocation
1607                 // Unused positions will be left as 0xFFFF, which translates to
1608                 // (1.0, 1.0) in the vertex output position and gets culled out
1609                 let mut position_data = vec![[!0u16; 2]; updates.blocks.len()];
1610                 let size = self.texture.as_ref().unwrap().get_dimensions().to_usize();
1611 
1612                 for update in &updates.updates {
1613                     match *update {
1614                         GpuCacheUpdate::Copy {
1615                             block_index,
1616                             block_count,
1617                             address,
1618                         } => {
1619                             // Convert the absolute texel position into normalized
1620                             let y = ((2*address.v as usize + 1) << 15) / size.height;
1621                             for i in 0 .. block_count {
1622                                 let x = ((2*address.u as usize + 2*i + 1) << 15) / size.width;
1623                                 position_data[block_index + i] = [x as _, y as _];
1624                             }
1625                         }
1626                     }
1627                 }
1628 
1629                 device.fill_vbo(buf_value, &updates.blocks, *count);
1630                 device.fill_vbo(buf_position, &position_data, *count);
1631                 *count += position_data.len();
1632             }
1633         }
1634     }
1635 
flush(&mut self, device: &mut Device) -> usize1636     fn flush(&mut self, device: &mut Device) -> usize {
1637         let texture = self.texture.as_ref().unwrap();
1638         match self.bus {
1639             GpuCacheBus::PixelBuffer { ref buffer, ref mut rows } => {
1640                 let rows_dirty = rows
1641                     .iter()
1642                     .filter(|row| row.is_dirty())
1643                     .count();
1644                 if rows_dirty == 0 {
1645                     return 0
1646                 }
1647 
1648                 let (upload_size, _) = device.required_upload_size_and_stride(
1649                     DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32, 1),
1650                     texture.get_format(),
1651                 );
1652 
1653                 let mut uploader = device.upload_texture(
1654                     texture,
1655                     buffer,
1656                     rows_dirty * upload_size,
1657                 );
1658 
1659                 for (row_index, row) in rows.iter_mut().enumerate() {
1660                     if !row.is_dirty() {
1661                         continue;
1662                     }
1663 
1664                     let blocks = row.dirty_blocks();
1665                     let rect = DeviceIntRect::new(
1666                         DeviceIntPoint::new(row.min_dirty as i32, row_index as i32),
1667                         DeviceIntSize::new(blocks.len() as i32, 1),
1668                     );
1669 
1670                     uploader.upload(rect, 0, None, None, blocks.as_ptr(), blocks.len());
1671 
1672                     row.clear_dirty();
1673                 }
1674 
1675                 rows_dirty
1676             }
1677             GpuCacheBus::Scatter { ref program, ref vao, count, .. } => {
1678                 device.disable_depth();
1679                 device.set_blend(false);
1680                 device.bind_program(program);
1681                 device.bind_custom_vao(vao);
1682                 device.bind_draw_target(
1683                     DrawTarget::from_texture(
1684                         texture,
1685                         0,
1686                         false,
1687                     ),
1688                 );
1689                 device.draw_nonindexed_points(0, count as _);
1690                 0
1691             }
1692         }
1693     }
1694 }
1695 
1696 struct VertexDataTexture<T> {
1697     texture: Option<Texture>,
1698     format: ImageFormat,
1699     pbo: PBO,
1700     _marker: PhantomData<T>,
1701 }
1702 
1703 impl<T> VertexDataTexture<T> {
new( device: &mut Device, format: ImageFormat, ) -> Self1704     fn new(
1705         device: &mut Device,
1706         format: ImageFormat,
1707     ) -> Self {
1708         VertexDataTexture {
1709             texture: None,
1710             format,
1711             pbo: device.create_pbo(),
1712             _marker: PhantomData,
1713         }
1714     }
1715 
1716     /// Returns a borrow of the GPU texture. Panics if it hasn't been initialized.
texture(&self) -> &Texture1717     fn texture(&self) -> &Texture {
1718         self.texture.as_ref().unwrap()
1719     }
1720 
1721     /// Returns an estimate of the GPU memory consumed by this VertexDataTexture.
size_in_bytes(&self) -> usize1722     fn size_in_bytes(&self) -> usize {
1723         self.texture.as_ref().map_or(0, |t| t.size_in_bytes())
1724     }
1725 
update(&mut self, device: &mut Device, data: &mut Vec<T>)1726     fn update(&mut self, device: &mut Device, data: &mut Vec<T>) {
1727         debug_assert!(mem::size_of::<T>() % 16 == 0);
1728         let texels_per_item = mem::size_of::<T>() / 16;
1729         let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item;
1730         debug_assert_ne!(items_per_row, 0);
1731 
1732         // Ensure we always end up with a texture when leaving this method.
1733         let mut len = data.len();
1734         if len == 0 {
1735             if self.texture.is_some() {
1736                 return;
1737             }
1738             data.reserve(items_per_row);
1739             len = items_per_row;
1740         } else {
1741             // Extend the data array to have enough capacity to upload at least
1742             // a multiple of the row size.  This ensures memory safety when the
1743             // array is passed to OpenGL to upload to the GPU.
1744             let extra = len % items_per_row;
1745             if extra != 0 {
1746                 let padding = items_per_row - extra;
1747                 data.reserve(padding);
1748                 len += padding;
1749             }
1750         }
1751 
1752         let needed_height = (len / items_per_row) as i32;
1753         let existing_height = self.texture.as_ref().map_or(0, |t| t.get_dimensions().height);
1754 
1755         // Create a new texture if needed.
1756         //
1757         // These textures are generally very small, which is why we don't bother
1758         // with incremental updates and just re-upload every frame. For most pages
1759         // they're one row each, and on stress tests like css-francine they end up
1760         // in the 6-14 range. So we size the texture tightly to what we need (usually
1761         // 1), and shrink it if the waste would be more than `VERTEX_TEXTURE_EXTRA_ROWS`
1762         // rows. This helps with memory overhead, especially because there are several
1763         // instances of these textures per Renderer.
1764         if needed_height > existing_height || needed_height + VERTEX_TEXTURE_EXTRA_ROWS < existing_height {
1765             // Drop the existing texture, if any.
1766             if let Some(t) = self.texture.take() {
1767                 device.delete_texture(t);
1768             }
1769 
1770             let texture = device.create_texture(
1771                 TextureTarget::Default,
1772                 self.format,
1773                 MAX_VERTEX_TEXTURE_WIDTH as i32,
1774                 // Ensure height is at least two to work around
1775                 // https://bugs.chromium.org/p/angleproject/issues/detail?id=3039
1776                 needed_height.max(2),
1777                 TextureFilter::Nearest,
1778                 None,
1779                 1,
1780             );
1781             self.texture = Some(texture);
1782         }
1783 
1784         // Note: the actual width can be larger than the logical one, with a few texels
1785         // of each row unused at the tail. This is needed because there is still hardware
1786         // (like Intel iGPUs) that prefers power-of-two sizes of textures ([1]).
1787         //
1788         // [1] https://software.intel.com/en-us/articles/opengl-performance-tips-power-of-two-textures-have-better-performance
1789         let logical_width = if needed_height == 1 {
1790             data.len() * texels_per_item
1791         } else {
1792             MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)
1793         };
1794 
1795         let rect = DeviceIntRect::new(
1796             DeviceIntPoint::zero(),
1797             DeviceIntSize::new(logical_width as i32, needed_height),
1798         );
1799 
1800         debug_assert!(len <= data.capacity(), "CPU copy will read out of bounds");
1801         let (upload_size, _) = device.required_upload_size_and_stride(
1802             rect.size,
1803             self.texture().get_format(),
1804         );
1805         if upload_size > 0 {
1806             device
1807                 .upload_texture(self.texture(), &self.pbo, upload_size)
1808                 .upload(rect, 0, None, None, data.as_ptr(), len);
1809         }
1810     }
1811 
deinit(mut self, device: &mut Device)1812     fn deinit(mut self, device: &mut Device) {
1813         device.delete_pbo(self.pbo);
1814         if let Some(t) = self.texture.take() {
1815             device.delete_texture(t);
1816         }
1817     }
1818 }
1819 
1820 struct FrameOutput {
1821     last_access: GpuFrameId,
1822     fbo_id: FBOId,
1823 }
1824 
1825 #[derive(PartialEq)]
1826 struct TargetSelector {
1827     size: DeviceIntSize,
1828     num_layers: usize,
1829     format: ImageFormat,
1830 }
1831 
1832 struct LazyInitializedDebugRenderer {
1833     debug_renderer: Option<DebugRenderer>,
1834     failed: bool,
1835 }
1836 
1837 impl LazyInitializedDebugRenderer {
new() -> Self1838     pub fn new() -> Self {
1839         Self {
1840             debug_renderer: None,
1841             failed: false,
1842         }
1843     }
1844 
get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer>1845     pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> {
1846         if self.failed {
1847             return None;
1848         }
1849         if self.debug_renderer.is_none() {
1850             match DebugRenderer::new(device) {
1851                 Ok(renderer) => { self.debug_renderer = Some(renderer); }
1852                 Err(_) => {
1853                     // The shader compilation code already logs errors.
1854                     self.failed = true;
1855                 }
1856             }
1857         }
1858 
1859         self.debug_renderer.as_mut()
1860     }
1861 
1862     /// Returns mut ref to `DebugRenderer` if one already exists, otherwise returns `None`.
try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer>1863     pub fn try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer> {
1864         self.debug_renderer.as_mut()
1865     }
1866 
deinit(self, device: &mut Device)1867     pub fn deinit(self, device: &mut Device) {
1868         if let Some(debug_renderer) = self.debug_renderer {
1869             debug_renderer.deinit(device);
1870         }
1871     }
1872 }
1873 
1874 // NB: If you add more VAOs here, be sure to deinitialize them in
1875 // `Renderer::deinit()` below.
1876 pub struct RendererVAOs {
1877     prim_vao: VAO,
1878     blur_vao: VAO,
1879     clip_vao: VAO,
1880     border_vao: VAO,
1881     line_vao: VAO,
1882     scale_vao: VAO,
1883     gradient_vao: VAO,
1884     resolve_vao: VAO,
1885     svg_filter_vao: VAO,
1886     composite_vao: VAO,
1887 }
1888 
1889 /// Information about the state of the debugging / profiler overlay in native compositing mode.
1890 struct DebugOverlayState {
1891     /// True if any of the current debug flags will result in drawing a debug overlay.
1892     is_enabled: bool,
1893 
1894     /// The current size of the debug overlay surface. None implies that the
1895     /// debug surface isn't currently allocated.
1896     current_size: Option<DeviceIntSize>,
1897 }
1898 
1899 impl DebugOverlayState {
new() -> Self1900     fn new() -> Self {
1901         DebugOverlayState {
1902             is_enabled: false,
1903             current_size: None,
1904         }
1905     }
1906 }
1907 
1908 pub struct VertexDataTextures {
1909     prim_header_f_texture: VertexDataTexture<PrimitiveHeaderF>,
1910     prim_header_i_texture: VertexDataTexture<PrimitiveHeaderI>,
1911     transforms_texture: VertexDataTexture<TransformData>,
1912     render_task_texture: VertexDataTexture<RenderTaskData>,
1913 }
1914 
1915 impl VertexDataTextures {
new( device: &mut Device, ) -> Self1916     fn new(
1917         device: &mut Device,
1918     ) -> Self {
1919         VertexDataTextures {
1920             prim_header_f_texture: VertexDataTexture::new(device, ImageFormat::RGBAF32),
1921             prim_header_i_texture: VertexDataTexture::new(device, ImageFormat::RGBAI32),
1922             transforms_texture: VertexDataTexture::new(device, ImageFormat::RGBAF32),
1923             render_task_texture: VertexDataTexture::new(device, ImageFormat::RGBAF32),
1924         }
1925     }
1926 
update( &mut self, device: &mut Device, frame: &mut Frame, )1927     fn update(
1928         &mut self,
1929         device: &mut Device,
1930         frame: &mut Frame,
1931     ) {
1932         self.prim_header_f_texture.update(
1933             device,
1934             &mut frame.prim_headers.headers_float,
1935         );
1936         device.bind_texture(
1937             TextureSampler::PrimitiveHeadersF,
1938             &self.prim_header_f_texture.texture(),
1939             Swizzle::default(),
1940         );
1941 
1942         self.prim_header_i_texture.update(
1943             device,
1944             &mut frame.prim_headers.headers_int,
1945         );
1946         device.bind_texture(
1947             TextureSampler::PrimitiveHeadersI,
1948             &self.prim_header_i_texture.texture(),
1949             Swizzle::default(),
1950         );
1951 
1952         self.transforms_texture.update(
1953             device,
1954             &mut frame.transform_palette,
1955         );
1956         device.bind_texture(
1957             TextureSampler::TransformPalette,
1958             &self.transforms_texture.texture(),
1959             Swizzle::default(),
1960         );
1961 
1962         self.render_task_texture.update(
1963             device,
1964             &mut frame.render_tasks.task_data,
1965         );
1966         device.bind_texture(
1967             TextureSampler::RenderTasks,
1968             &self.render_task_texture.texture(),
1969             Swizzle::default(),
1970         );
1971     }
1972 
size_in_bytes(&self) -> usize1973     fn size_in_bytes(&self) -> usize {
1974         self.prim_header_f_texture.size_in_bytes() +
1975         self.prim_header_i_texture.size_in_bytes() +
1976         self.transforms_texture.size_in_bytes() +
1977         self.render_task_texture.size_in_bytes()
1978     }
1979 
deinit( self, device: &mut Device, )1980     fn deinit(
1981         self,
1982         device: &mut Device,
1983     ) {
1984         self.transforms_texture.deinit(device);
1985         self.prim_header_f_texture.deinit(device);
1986         self.prim_header_i_texture.deinit(device);
1987         self.render_task_texture.deinit(device);
1988     }
1989 }
1990 
1991 /// The renderer is responsible for submitting to the GPU the work prepared by the
1992 /// RenderBackend.
1993 ///
1994 /// We have a separate `Renderer` instance for each instance of WebRender (generally
1995 /// one per OS window), and all instances share the same thread.
1996 pub struct Renderer {
1997     result_rx: Receiver<ResultMsg>,
1998     debug_server: Box<dyn DebugServer>,
1999     pub device: Device,
2000     pending_texture_updates: Vec<TextureUpdateList>,
2001     /// True if there are any TextureCacheUpdate pending.
2002     pending_texture_cache_updates: bool,
2003     pending_native_surface_updates: Vec<NativeSurfaceOperation>,
2004     pending_gpu_cache_updates: Vec<GpuCacheUpdateList>,
2005     pending_gpu_cache_clear: bool,
2006     pending_shader_updates: Vec<PathBuf>,
2007     active_documents: Vec<(DocumentId, RenderedDocument)>,
2008 
2009     shaders: Rc<RefCell<Shaders>>,
2010 
2011     max_recorded_profiles: usize,
2012 
2013     clear_color: Option<ColorF>,
2014     enable_clear_scissor: bool,
2015     enable_advanced_blend_barriers: bool,
2016 
2017     debug: LazyInitializedDebugRenderer,
2018     debug_flags: DebugFlags,
2019     backend_profile_counters: BackendProfileCounters,
2020     profile_counters: RendererProfileCounters,
2021     resource_upload_time: u64,
2022     gpu_cache_upload_time: u64,
2023     profiler: Profiler,
2024     new_frame_indicator: ChangeIndicator,
2025     new_scene_indicator: ChangeIndicator,
2026     slow_frame_indicator: ChangeIndicator,
2027     slow_txn_indicator: ChangeIndicator,
2028 
2029     last_time: u64,
2030 
2031     pub gpu_profile: GpuProfiler<GpuProfileTag>,
2032     vaos: RendererVAOs,
2033 
2034     gpu_cache_texture: GpuCacheTexture,
2035     vertex_data_textures: Vec<VertexDataTextures>,
2036     current_vertex_data_textures: usize,
2037 
2038     /// When the GPU cache debugger is enabled, we keep track of the live blocks
2039     /// in the GPU cache so that we can use them for the debug display. This
2040     /// member stores those live blocks, indexed by row.
2041     gpu_cache_debug_chunks: Vec<Vec<GpuCacheDebugChunk>>,
2042 
2043     gpu_cache_frame_id: FrameId,
2044     gpu_cache_overflow: bool,
2045 
2046     pipeline_info: PipelineInfo,
2047 
2048     // Manages and resolves source textures IDs to real texture IDs.
2049     texture_resolver: TextureResolver,
2050 
2051     // A PBO used to do asynchronous texture cache uploads.
2052     texture_cache_upload_pbo: PBO,
2053 
2054     dither_matrix_texture: Option<Texture>,
2055 
2056     /// Optional trait object that allows the client
2057     /// application to provide external buffers for image data.
2058     external_image_handler: Option<Box<dyn ExternalImageHandler>>,
2059 
2060     /// Optional trait object that allows the client
2061     /// application to provide a texture handle to
2062     /// copy the WR output to.
2063     output_image_handler: Option<Box<dyn OutputImageHandler>>,
2064 
2065     /// Optional function pointers for measuring memory used by a given
2066     /// heap-allocated pointer.
2067     size_of_ops: Option<MallocSizeOfOps>,
2068 
2069     // Currently allocated FBOs for output frames.
2070     output_targets: FastHashMap<u32, FrameOutput>,
2071 
2072     pub renderer_errors: Vec<RendererError>,
2073 
2074     pub(in crate) async_frame_recorder: Option<AsyncScreenshotGrabber>,
2075     pub(in crate) async_screenshots: Option<AsyncScreenshotGrabber>,
2076 
2077     /// List of profile results from previous frames. Can be retrieved
2078     /// via get_frame_profiles().
2079     cpu_profiles: VecDeque<CpuProfile>,
2080     gpu_profiles: VecDeque<GpuProfile>,
2081 
2082     /// Notification requests to be fulfilled after rendering.
2083     notifications: Vec<NotificationRequest>,
2084 
2085     device_size: Option<DeviceIntSize>,
2086 
2087     /// A lazily created texture for the zoom debugging widget.
2088     zoom_debug_texture: Option<Texture>,
2089 
2090     /// The current mouse position. This is used for debugging
2091     /// functionality only, such as the debug zoom widget.
2092     cursor_position: DeviceIntPoint,
2093 
2094     /// Guards to check if we might be rendering a frame with expired texture
2095     /// cache entries.
2096     shared_texture_cache_cleared: bool,
2097 
2098     /// The set of documents which we've seen a publish for since last render.
2099     documents_seen: FastHashSet<DocumentId>,
2100 
2101     #[cfg(feature = "capture")]
2102     read_fbo: FBOId,
2103     #[cfg(feature = "replay")]
2104     owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
2105 
2106     /// The compositing config, affecting how WR composites into the final scene.
2107     compositor_config: CompositorConfig,
2108 
2109     current_compositor_kind: CompositorKind,
2110 
2111     /// Maintains a set of allocated native composite surfaces. This allows any
2112     /// currently allocated surfaces to be cleaned up as soon as deinit() is
2113     /// called (the normal bookkeeping for native surfaces exists in the
2114     /// render backend thread).
2115     allocated_native_surfaces: FastHashSet<NativeSurfaceId>,
2116 
2117     /// If true, partial present state has been reset and everything needs to
2118     /// be drawn on the next render.
2119     force_redraw: bool,
2120 
2121     /// State related to the debug / profiling overlays
2122     debug_overlay_state: DebugOverlayState,
2123 
2124     /// The dirty rectangle from the previous frame, used on platforms that
2125     /// require keeping the front buffer fully correct when doing
2126     /// partial present (e.g. unix desktop with EGL_EXT_buffer_age).
2127     prev_dirty_rect: DeviceRect,
2128 }
2129 
2130 #[derive(Debug)]
2131 pub enum RendererError {
2132     Shader(ShaderError),
2133     Thread(std::io::Error),
2134     Resource(ResourceCacheError),
2135     MaxTextureSize,
2136 }
2137 
2138 impl From<ShaderError> for RendererError {
from(err: ShaderError) -> Self2139     fn from(err: ShaderError) -> Self {
2140         RendererError::Shader(err)
2141     }
2142 }
2143 
2144 impl From<std::io::Error> for RendererError {
from(err: std::io::Error) -> Self2145     fn from(err: std::io::Error) -> Self {
2146         RendererError::Thread(err)
2147     }
2148 }
2149 
2150 impl From<ResourceCacheError> for RendererError {
from(err: ResourceCacheError) -> Self2151     fn from(err: ResourceCacheError) -> Self {
2152         RendererError::Resource(err)
2153     }
2154 }
2155 
2156 impl Renderer {
2157     /// Initializes WebRender and creates a `Renderer` and `RenderApiSender`.
2158     ///
2159     /// # Examples
2160     /// Initializes a `Renderer` with some reasonable values. For more information see
2161     /// [`RendererOptions`][rendereroptions].
2162     ///
2163     /// ```rust,ignore
2164     /// # use webrender::renderer::Renderer;
2165     /// # use std::path::PathBuf;
2166     /// let opts = webrender::RendererOptions {
2167     ///    device_pixel_ratio: 1.0,
2168     ///    resource_override_path: None,
2169     ///    enable_aa: false,
2170     /// };
2171     /// let (renderer, sender) = Renderer::new(opts);
2172     /// ```
2173     /// [rendereroptions]: struct.RendererOptions.html
new( gl: Rc<dyn gl::Gl>, notifier: Box<dyn RenderNotifier>, mut options: RendererOptions, shaders: Option<&mut WrShaders>, start_size: DeviceIntSize, ) -> Result<(Self, RenderApiSender), RendererError>2174     pub fn new(
2175         gl: Rc<dyn gl::Gl>,
2176         notifier: Box<dyn RenderNotifier>,
2177         mut options: RendererOptions,
2178         shaders: Option<&mut WrShaders>,
2179         start_size: DeviceIntSize,
2180     ) -> Result<(Self, RenderApiSender), RendererError> {
2181         if !wr_has_been_initialized() {
2182             // If the profiler feature is enabled, try to load the profiler shared library
2183             // if the path was provided.
2184             #[cfg(feature = "profiler")]
2185             unsafe {
2186                 if let Ok(ref tracy_path) = std::env::var("WR_TRACY_PATH") {
2187                     let ok = tracy_rs::load(tracy_path);
2188                     println!("Load tracy from {} -> {}", tracy_path, ok);
2189                 }
2190             }
2191 
2192             register_thread_with_profiler("Compositor".to_owned());
2193         }
2194 
2195         HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
2196 
2197         let (api_tx, api_rx) = channel();
2198         let (result_tx, result_rx) = channel();
2199         let gl_type = gl.get_type();
2200 
2201         let debug_server = new_debug_server(options.start_debug_server, api_tx.clone());
2202 
2203         let mut device = Device::new(
2204             gl,
2205             options.resource_override_path.clone(),
2206             options.use_optimized_shaders,
2207             options.upload_method.clone(),
2208             options.cached_programs.take(),
2209             options.allow_pixel_local_storage_support,
2210             options.allow_texture_storage_support,
2211             options.allow_texture_swizzling,
2212             options.dump_shader_source.take(),
2213             options.surface_origin_is_top_left,
2214             options.panic_on_gl_error,
2215         );
2216 
2217         let color_cache_formats = device.preferred_color_formats();
2218         let swizzle_settings = device.swizzle_settings();
2219         let use_dual_source_blending =
2220             device.get_capabilities().supports_dual_source_blending &&
2221             options.allow_dual_source_blending &&
2222             // If using pixel local storage, subpixel AA isn't supported (we disable it on all
2223             // mobile devices explicitly anyway).
2224             !device.get_capabilities().supports_pixel_local_storage;
2225         let ext_blend_equation_advanced =
2226             options.allow_advanced_blend_equation &&
2227             device.get_capabilities().supports_advanced_blend_equation;
2228         let ext_blend_equation_advanced_coherent =
2229             device.supports_extension("GL_KHR_blend_equation_advanced_coherent");
2230 
2231         // 512 is the minimum that the texture cache can work with.
2232         const MIN_TEXTURE_SIZE: i32 = 512;
2233         if let Some(user_limit) = options.max_texture_size {
2234             assert!(user_limit >= MIN_TEXTURE_SIZE);
2235             device.clamp_max_texture_size(user_limit);
2236         }
2237         if device.max_texture_size() < MIN_TEXTURE_SIZE {
2238             // Broken GL contexts can return a max texture size of zero (See #1260).
2239             // Better to gracefully fail now than panic as soon as a texture is allocated.
2240             error!(
2241                 "Device reporting insufficient max texture size ({})",
2242                 device.max_texture_size()
2243             );
2244             return Err(RendererError::MaxTextureSize);
2245         }
2246         let max_texture_size = device.max_texture_size();
2247         let max_texture_layers = device.max_texture_layers();
2248 
2249         device.begin_frame();
2250 
2251         let shaders = match shaders {
2252             Some(shaders) => Rc::clone(&shaders.shaders),
2253             None => Rc::new(RefCell::new(Shaders::new(&mut device, gl_type, &options)?)),
2254         };
2255 
2256         let backend_profile_counters = BackendProfileCounters::new();
2257 
2258         let dither_matrix_texture = if options.enable_dithering {
2259             let dither_matrix: [u8; 64] = [
2260                 0,
2261                 48,
2262                 12,
2263                 60,
2264                 3,
2265                 51,
2266                 15,
2267                 63,
2268                 32,
2269                 16,
2270                 44,
2271                 28,
2272                 35,
2273                 19,
2274                 47,
2275                 31,
2276                 8,
2277                 56,
2278                 4,
2279                 52,
2280                 11,
2281                 59,
2282                 7,
2283                 55,
2284                 40,
2285                 24,
2286                 36,
2287                 20,
2288                 43,
2289                 27,
2290                 39,
2291                 23,
2292                 2,
2293                 50,
2294                 14,
2295                 62,
2296                 1,
2297                 49,
2298                 13,
2299                 61,
2300                 34,
2301                 18,
2302                 46,
2303                 30,
2304                 33,
2305                 17,
2306                 45,
2307                 29,
2308                 10,
2309                 58,
2310                 6,
2311                 54,
2312                 9,
2313                 57,
2314                 5,
2315                 53,
2316                 42,
2317                 26,
2318                 38,
2319                 22,
2320                 41,
2321                 25,
2322                 37,
2323                 21,
2324             ];
2325 
2326             let texture = device.create_texture(
2327                 TextureTarget::Default,
2328                 ImageFormat::R8,
2329                 8,
2330                 8,
2331                 TextureFilter::Nearest,
2332                 None,
2333                 1,
2334             );
2335             device.upload_texture_immediate(&texture, &dither_matrix);
2336 
2337             Some(texture)
2338         } else {
2339             None
2340         };
2341 
2342         let x0 = 0.0;
2343         let y0 = 0.0;
2344         let x1 = 1.0;
2345         let y1 = 1.0;
2346 
2347         let quad_indices: [u16; 6] = [0, 1, 2, 2, 1, 3];
2348         let quad_vertices = [
2349             PackedVertex { pos: [x0, y0] },
2350             PackedVertex { pos: [x1, y0] },
2351             PackedVertex { pos: [x0, y1] },
2352             PackedVertex { pos: [x1, y1] },
2353         ];
2354 
2355         let prim_vao = device.create_vao(&desc::PRIM_INSTANCES);
2356         device.bind_vao(&prim_vao);
2357         device.update_vao_indices(&prim_vao, &quad_indices, VertexUsageHint::Static);
2358         device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static);
2359 
2360         let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao);
2361         let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao);
2362         let border_vao = device.create_vao_with_new_instances(&desc::BORDER, &prim_vao);
2363         let scale_vao = device.create_vao_with_new_instances(&desc::SCALE, &prim_vao);
2364         let line_vao = device.create_vao_with_new_instances(&desc::LINE, &prim_vao);
2365         let gradient_vao = device.create_vao_with_new_instances(&desc::GRADIENT, &prim_vao);
2366         let resolve_vao = device.create_vao_with_new_instances(&desc::RESOLVE, &prim_vao);
2367         let svg_filter_vao = device.create_vao_with_new_instances(&desc::SVG_FILTER, &prim_vao);
2368         let composite_vao = device.create_vao_with_new_instances(&desc::COMPOSITE, &prim_vao);
2369         let texture_cache_upload_pbo = device.create_pbo();
2370 
2371         let texture_resolver = TextureResolver::new(&mut device);
2372 
2373         let mut vertex_data_textures = Vec::new();
2374         for _ in 0 .. VERTEX_DATA_TEXTURE_COUNT {
2375             vertex_data_textures.push(VertexDataTextures::new(&mut device));
2376         }
2377 
2378         // On some (mostly older, integrated) GPUs, the normal GPU texture cache update path
2379         // doesn't work well when running on ANGLE, causing CPU stalls inside D3D and/or the
2380         // GPU driver. See https://bugzilla.mozilla.org/show_bug.cgi?id=1576637 for much
2381         // more detail. To reduce the number of code paths we have active that require testing,
2382         // we will enable the GPU cache scatter update path on all devices running with ANGLE.
2383         // We want a better solution long-term, but for now this is a significant performance
2384         // improvement on HD4600 era GPUs, and shouldn't hurt performance in a noticeable
2385         // way on other systems running under ANGLE.
2386         let is_angle = device.get_capabilities().renderer_name.contains("ANGLE");
2387 
2388         let gpu_cache_texture = GpuCacheTexture::new(
2389             &mut device,
2390             is_angle,
2391         )?;
2392 
2393         device.end_frame();
2394 
2395         let backend_notifier = notifier.clone();
2396 
2397         let prefer_subpixel_aa = options.force_subpixel_aa || (options.enable_subpixel_aa && use_dual_source_blending);
2398         let default_font_render_mode = match (options.enable_aa, prefer_subpixel_aa) {
2399             (true, true) => FontRenderMode::Subpixel,
2400             (true, false) => FontRenderMode::Alpha,
2401             (false, _) => FontRenderMode::Mono,
2402         };
2403 
2404         let compositor_kind = match options.compositor_config {
2405             CompositorConfig::Draw { max_partial_present_rects, draw_previous_partial_present_regions } => {
2406                 CompositorKind::Draw { max_partial_present_rects, draw_previous_partial_present_regions }
2407             }
2408             CompositorConfig::Native { ref compositor, max_update_rects, .. } => {
2409                 let capabilities = compositor.get_capabilities();
2410 
2411                 CompositorKind::Native {
2412                     max_update_rects,
2413                     virtual_surface_size: capabilities.virtual_surface_size,
2414                 }
2415             }
2416         };
2417 
2418         let config = FrameBuilderConfig {
2419             default_font_render_mode,
2420             dual_source_blending_is_enabled: true,
2421             dual_source_blending_is_supported: use_dual_source_blending,
2422             chase_primitive: options.chase_primitive,
2423             global_enable_picture_caching: options.enable_picture_caching,
2424             testing: options.testing,
2425             gpu_supports_fast_clears: options.gpu_supports_fast_clears,
2426             gpu_supports_advanced_blend: ext_blend_equation_advanced,
2427             advanced_blend_is_coherent: ext_blend_equation_advanced_coherent,
2428             batch_lookback_count: options.batch_lookback_count,
2429             background_color: options.clear_color,
2430             compositor_kind,
2431             tile_size_override: None,
2432             max_depth_ids: device.max_depth_ids(),
2433             max_target_size: max_texture_size,
2434         };
2435         info!("WR {:?}", config);
2436 
2437         let device_pixel_ratio = options.device_pixel_ratio;
2438         let debug_flags = options.debug_flags;
2439         let size_of_op = options.size_of_op;
2440         let enclosing_size_of_op = options.enclosing_size_of_op;
2441         let make_size_of_ops =
2442             move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op));
2443         let thread_listener = Arc::new(options.thread_listener);
2444         let thread_listener_for_rayon_start = thread_listener.clone();
2445         let thread_listener_for_rayon_end = thread_listener.clone();
2446         let workers = options
2447             .workers
2448             .take()
2449             .unwrap_or_else(|| {
2450                 let worker = ThreadPoolBuilder::new()
2451                     .thread_name(|idx|{ format!("WRWorker#{}", idx) })
2452                     .start_handler(move |idx| {
2453                         register_thread_with_profiler(format!("WRWorker#{}", idx));
2454                         if let Some(ref thread_listener) = *thread_listener_for_rayon_start {
2455                             thread_listener.thread_started(&format!("WRWorker#{}", idx));
2456                         }
2457                     })
2458                     .exit_handler(move |idx| {
2459                         if let Some(ref thread_listener) = *thread_listener_for_rayon_end {
2460                             thread_listener.thread_stopped(&format!("WRWorker#{}", idx));
2461                         }
2462                     })
2463                     .build();
2464                 Arc::new(worker.unwrap())
2465             });
2466         let sampler = options.sampler;
2467         let namespace_alloc_by_client = options.namespace_alloc_by_client;
2468         let max_glyph_cache_size = options.max_glyph_cache_size.unwrap_or(GlyphCache::DEFAULT_MAX_BYTES_USED);
2469 
2470         let font_instances = SharedFontInstanceMap::new();
2471 
2472         let blob_image_handler = options.blob_image_handler.take();
2473         let thread_listener_for_render_backend = thread_listener.clone();
2474         let thread_listener_for_scene_builder = thread_listener.clone();
2475         let thread_listener_for_lp_scene_builder = thread_listener.clone();
2476         let scene_builder_hooks = options.scene_builder_hooks;
2477         let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
2478         let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
2479         let lp_scene_thread_name = format!("WRSceneBuilderLP#{}", options.renderer_id.unwrap_or(0));
2480         let glyph_rasterizer = GlyphRasterizer::new(workers)?;
2481 
2482         let (scene_builder_channels, scene_tx, backend_scene_tx, scene_rx) =
2483             SceneBuilderThreadChannels::new(api_tx.clone());
2484 
2485         let sb_font_instances = font_instances.clone();
2486 
2487         thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
2488             register_thread_with_profiler(scene_thread_name.clone());
2489             if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
2490                 thread_listener.thread_started(&scene_thread_name);
2491             }
2492 
2493             let mut scene_builder = SceneBuilderThread::new(
2494                 config,
2495                 device_pixel_ratio,
2496                 sb_font_instances,
2497                 make_size_of_ops(),
2498                 scene_builder_hooks,
2499                 scene_builder_channels,
2500             );
2501             scene_builder.run();
2502 
2503             if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
2504                 thread_listener.thread_stopped(&scene_thread_name);
2505             }
2506         })?;
2507 
2508         let low_priority_scene_tx = if options.support_low_priority_transactions {
2509             let (low_priority_scene_tx, low_priority_scene_rx) = channel();
2510             let lp_builder = LowPrioritySceneBuilderThread {
2511                 rx: low_priority_scene_rx,
2512                 tx: scene_tx.clone(),
2513                 simulate_slow_ms: 0,
2514             };
2515 
2516             thread::Builder::new().name(lp_scene_thread_name.clone()).spawn(move || {
2517                 register_thread_with_profiler(lp_scene_thread_name.clone());
2518                 if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder {
2519                     thread_listener.thread_started(&lp_scene_thread_name);
2520                 }
2521 
2522                 let mut scene_builder = lp_builder;
2523                 scene_builder.run();
2524 
2525                 if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder {
2526                     thread_listener.thread_stopped(&lp_scene_thread_name);
2527                 }
2528             })?;
2529 
2530             low_priority_scene_tx
2531         } else {
2532             scene_tx.clone()
2533         };
2534 
2535         let backend_blob_handler = blob_image_handler
2536             .as_ref()
2537             .map(|handler| handler.create_similar());
2538 
2539         let rb_font_instances = font_instances.clone();
2540         let enable_multithreading = options.enable_multithreading;
2541         thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
2542             register_thread_with_profiler(rb_thread_name.clone());
2543             if let Some(ref thread_listener) = *thread_listener_for_render_backend {
2544                 thread_listener.thread_started(&rb_thread_name);
2545             }
2546 
2547             let texture_cache = TextureCache::new(
2548                 max_texture_size,
2549                 max_texture_layers,
2550                 if config.global_enable_picture_caching {
2551                     tile_cache_sizes(config.testing)
2552                 } else {
2553                     &[]
2554                 },
2555                 start_size,
2556                 color_cache_formats,
2557                 swizzle_settings,
2558             );
2559 
2560             let glyph_cache = GlyphCache::new(max_glyph_cache_size);
2561 
2562             let mut resource_cache = ResourceCache::new(
2563                 texture_cache,
2564                 glyph_rasterizer,
2565                 glyph_cache,
2566                 rb_font_instances,
2567             );
2568 
2569             resource_cache.enable_multithreading(enable_multithreading);
2570 
2571             let mut backend = RenderBackend::new(
2572                 api_rx,
2573                 result_tx,
2574                 scene_tx,
2575                 low_priority_scene_tx,
2576                 backend_scene_tx,
2577                 scene_rx,
2578                 device_pixel_ratio,
2579                 resource_cache,
2580                 backend_notifier,
2581                 backend_blob_handler,
2582                 config,
2583                 sampler,
2584                 make_size_of_ops(),
2585                 debug_flags,
2586                 namespace_alloc_by_client,
2587             );
2588             backend.run(backend_profile_counters);
2589             if let Some(ref thread_listener) = *thread_listener_for_render_backend {
2590                 thread_listener.thread_stopped(&rb_thread_name);
2591             }
2592         })?;
2593 
2594         let debug_method = if !options.enable_gpu_markers {
2595             // The GPU markers are disabled.
2596             GpuDebugMethod::None
2597         } else if device.supports_extension("GL_KHR_debug") {
2598             GpuDebugMethod::KHR
2599         } else if device.supports_extension("GL_EXT_debug_marker") {
2600             GpuDebugMethod::MarkerEXT
2601         } else {
2602             println!("Warning: asking to enable_gpu_markers but no supporting extension was found");
2603             GpuDebugMethod::None
2604         };
2605 
2606         info!("using {:?}", debug_method);
2607 
2608         let gpu_profile = GpuProfiler::new(Rc::clone(device.rc_gl()), debug_method);
2609         #[cfg(feature = "capture")]
2610         let read_fbo = device.create_fbo();
2611 
2612         let mut renderer = Renderer {
2613             result_rx,
2614             debug_server,
2615             device,
2616             active_documents: Vec::new(),
2617             pending_texture_updates: Vec::new(),
2618             pending_texture_cache_updates: false,
2619             pending_native_surface_updates: Vec::new(),
2620             pending_gpu_cache_updates: Vec::new(),
2621             pending_gpu_cache_clear: false,
2622             pending_shader_updates: Vec::new(),
2623             shaders,
2624             debug: LazyInitializedDebugRenderer::new(),
2625             debug_flags: DebugFlags::empty(),
2626             backend_profile_counters: BackendProfileCounters::new(),
2627             profile_counters: RendererProfileCounters::new(),
2628             resource_upload_time: 0,
2629             gpu_cache_upload_time: 0,
2630             profiler: Profiler::new(),
2631             new_frame_indicator: ChangeIndicator::new(),
2632             new_scene_indicator: ChangeIndicator::new(),
2633             slow_frame_indicator: ChangeIndicator::new(),
2634             slow_txn_indicator: ChangeIndicator::new(),
2635             max_recorded_profiles: options.max_recorded_profiles,
2636             clear_color: options.clear_color,
2637             enable_clear_scissor: options.enable_clear_scissor,
2638             enable_advanced_blend_barriers: !ext_blend_equation_advanced_coherent,
2639             last_time: 0,
2640             gpu_profile,
2641             vaos: RendererVAOs {
2642                 prim_vao,
2643                 blur_vao,
2644                 clip_vao,
2645                 border_vao,
2646                 scale_vao,
2647                 gradient_vao,
2648                 resolve_vao,
2649                 line_vao,
2650                 svg_filter_vao,
2651                 composite_vao,
2652             },
2653             vertex_data_textures,
2654             current_vertex_data_textures: 0,
2655             pipeline_info: PipelineInfo::default(),
2656             dither_matrix_texture,
2657             external_image_handler: None,
2658             output_image_handler: None,
2659             size_of_ops: make_size_of_ops(),
2660             output_targets: FastHashMap::default(),
2661             cpu_profiles: VecDeque::new(),
2662             gpu_profiles: VecDeque::new(),
2663             gpu_cache_texture,
2664             gpu_cache_debug_chunks: Vec::new(),
2665             gpu_cache_frame_id: FrameId::INVALID,
2666             gpu_cache_overflow: false,
2667             texture_cache_upload_pbo,
2668             texture_resolver,
2669             renderer_errors: Vec::new(),
2670             async_frame_recorder: None,
2671             async_screenshots: None,
2672             #[cfg(feature = "capture")]
2673             read_fbo,
2674             #[cfg(feature = "replay")]
2675             owned_external_images: FastHashMap::default(),
2676             notifications: Vec::new(),
2677             device_size: None,
2678             zoom_debug_texture: None,
2679             cursor_position: DeviceIntPoint::zero(),
2680             shared_texture_cache_cleared: false,
2681             documents_seen: FastHashSet::default(),
2682             force_redraw: true,
2683             compositor_config: options.compositor_config,
2684             current_compositor_kind: compositor_kind,
2685             allocated_native_surfaces: FastHashSet::default(),
2686             debug_overlay_state: DebugOverlayState::new(),
2687             prev_dirty_rect: DeviceRect::zero(),
2688         };
2689 
2690         // We initially set the flags to default and then now call set_debug_flags
2691         // to ensure any potential transition when enabling a flag is run.
2692         renderer.set_debug_flags(debug_flags);
2693 
2694         let sender = RenderApiSender::new(api_tx, blob_image_handler, font_instances);
2695         Ok((renderer, sender))
2696     }
2697 
device_size(&self) -> Option<DeviceIntSize>2698     pub fn device_size(&self) -> Option<DeviceIntSize> {
2699         self.device_size
2700     }
2701 
2702     /// Update the current position of the debug cursor.
set_cursor_position( &mut self, position: DeviceIntPoint, )2703     pub fn set_cursor_position(
2704         &mut self,
2705         position: DeviceIntPoint,
2706     ) {
2707         self.cursor_position = position;
2708     }
2709 
get_max_texture_size(&self) -> i322710     pub fn get_max_texture_size(&self) -> i32 {
2711         self.device.max_texture_size()
2712     }
2713 
get_graphics_api_info(&self) -> GraphicsApiInfo2714     pub fn get_graphics_api_info(&self) -> GraphicsApiInfo {
2715         GraphicsApiInfo {
2716             kind: GraphicsApi::OpenGL,
2717             version: self.device.gl().get_string(gl::VERSION),
2718             renderer: self.device.gl().get_string(gl::RENDERER),
2719         }
2720     }
2721 
preferred_color_format(&self) -> ImageFormat2722     pub fn preferred_color_format(&self) -> ImageFormat {
2723         self.device.preferred_color_formats().external
2724     }
2725 
optimal_texture_stride_alignment(&self, format: ImageFormat) -> usize2726     pub fn optimal_texture_stride_alignment(&self, format: ImageFormat) -> usize {
2727         self.device.optimal_pbo_stride().num_bytes(format).get()
2728     }
2729 
flush_pipeline_info(&mut self) -> PipelineInfo2730     pub fn flush_pipeline_info(&mut self) -> PipelineInfo {
2731         mem::replace(&mut self.pipeline_info, PipelineInfo::default())
2732     }
2733 
2734     /// Returns the Epoch of the current frame in a pipeline.
current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option<Epoch>2735     pub fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option<Epoch> {
2736         self.pipeline_info.epochs.get(&(pipeline_id, document_id)).cloned()
2737     }
2738 
2739     /// Processes the result queue.
2740     ///
2741     /// Should be called before `render()`, as texture cache updates are done here.
update(&mut self)2742     pub fn update(&mut self) {
2743         profile_scope!("update");
2744         // Pull any pending results and return the most recent.
2745         while let Ok(msg) = self.result_rx.try_recv() {
2746             match msg {
2747                 ResultMsg::PublishPipelineInfo(mut pipeline_info) => {
2748                     for ((pipeline_id, document_id), epoch) in pipeline_info.epochs {
2749                         self.pipeline_info.epochs.insert((pipeline_id, document_id), epoch);
2750                     }
2751                     self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..));
2752                 }
2753                 ResultMsg::PublishDocument(
2754                     document_id,
2755                     doc,
2756                     resource_update_list,
2757                     profile_counters,
2758                 ) => {
2759                     if doc.is_new_scene {
2760                         self.new_scene_indicator.changed();
2761                     }
2762 
2763                     // Add a new document to the active set, expressed as a `Vec` in order
2764                     // to re-order based on `DocumentLayer` during rendering.
2765                     match self.active_documents.iter().position(|&(id, _)| id == document_id) {
2766                         Some(pos) => {
2767                             // If the document we are replacing must be drawn
2768                             // (in order to update the texture cache), issue
2769                             // a render just to off-screen targets.
2770                             if self.active_documents[pos].1.frame.must_be_drawn() {
2771                                 let device_size = self.device_size;
2772                                 self.render_impl(device_size).ok();
2773                             }
2774 
2775                             self.active_documents[pos].1 = doc;
2776                         }
2777                         None => self.active_documents.push((document_id, doc)),
2778                     }
2779 
2780                     // IMPORTANT: The pending texture cache updates must be applied
2781                     //            *after* the previous frame has been rendered above
2782                     //            (if neceessary for a texture cache update). For
2783                     //            an example of why this is required:
2784                     //            1) Previous frame contains a render task that
2785                     //               targets Texture X.
2786                     //            2) New frame contains a texture cache update which
2787                     //               frees Texture X.
2788                     //            3) bad stuff happens.
2789 
2790                     //TODO: associate `document_id` with target window
2791                     self.pending_texture_cache_updates |= !resource_update_list.texture_updates.updates.is_empty();
2792                     self.pending_texture_updates.push(resource_update_list.texture_updates);
2793                     self.pending_native_surface_updates.extend(resource_update_list.native_surface_updates);
2794                     self.backend_profile_counters = profile_counters;
2795                     self.documents_seen.insert(document_id);
2796                 }
2797                 ResultMsg::UpdateGpuCache(mut list) => {
2798                     if list.clear {
2799                         self.pending_gpu_cache_clear = true;
2800                     }
2801                     if list.clear {
2802                         self.gpu_cache_debug_chunks = Vec::new();
2803                     }
2804                     for cmd in mem::replace(&mut list.debug_commands, Vec::new()) {
2805                         match cmd {
2806                             GpuCacheDebugCmd::Alloc(chunk) => {
2807                                 let row = chunk.address.v as usize;
2808                                 if row >= self.gpu_cache_debug_chunks.len() {
2809                                     self.gpu_cache_debug_chunks.resize(row + 1, Vec::new());
2810                                 }
2811                                 self.gpu_cache_debug_chunks[row].push(chunk);
2812                             },
2813                             GpuCacheDebugCmd::Free(address) => {
2814                                 let chunks = &mut self.gpu_cache_debug_chunks[address.v as usize];
2815                                 let pos = chunks.iter()
2816                                     .position(|x| x.address == address).unwrap();
2817                                 chunks.remove(pos);
2818                             },
2819                         }
2820                     }
2821                     self.pending_gpu_cache_updates.push(list);
2822                 }
2823                 ResultMsg::UpdateResources {
2824                     resource_updates,
2825                     memory_pressure,
2826                 } => {
2827                     if memory_pressure {
2828                         // If a memory pressure event arrives _after_ a new scene has
2829                         // been published that writes persistent targets (i.e. cached
2830                         // render tasks to the texture cache, or picture cache tiles)
2831                         // but _before_ the next update/render loop, those targets
2832                         // will not be updated due to the active_documents list being
2833                         // cleared at the end of this message. To work around that,
2834                         // if any of the existing documents have not rendered yet, and
2835                         // have picture/texture cache targets, force a render so that
2836                         // those targets are updated.
2837                         let must_be_drawn = self.active_documents
2838                             .iter()
2839                             .any(|(_, doc)| {
2840                                 doc.frame.must_be_drawn()
2841                             });
2842 
2843                         if must_be_drawn {
2844                             let device_size = self.device_size;
2845                             self.render_impl(device_size).ok();
2846                         }
2847                     }
2848 
2849                     self.pending_texture_cache_updates |= !resource_updates.texture_updates.updates.is_empty();
2850                     self.pending_texture_updates.push(resource_updates.texture_updates);
2851                     self.pending_native_surface_updates.extend(resource_updates.native_surface_updates);
2852                     self.device.begin_frame();
2853 
2854                     self.update_texture_cache();
2855                     self.update_native_surfaces();
2856 
2857                     // Flush the render target pool on memory pressure.
2858                     //
2859                     // This needs to be separate from the block below because
2860                     // the device module asserts if we delete textures while
2861                     // not in a frame.
2862                     if memory_pressure {
2863                         self.texture_resolver.on_memory_pressure(
2864                             &mut self.device,
2865                         );
2866                     }
2867 
2868                     self.device.end_frame();
2869                     // If we receive a `PublishDocument` message followed by this one
2870                     // within the same update we need to cancel the frame because we
2871                     // might have deleted the resources in use in the frame due to a
2872                     // memory pressure event.
2873                     if memory_pressure {
2874                         self.active_documents.clear();
2875                     }
2876                 }
2877                 ResultMsg::AppendNotificationRequests(mut notifications) => {
2878                     // We need to know specifically if there are any pending
2879                     // TextureCacheUpdate updates in any of the entries in
2880                     // pending_texture_updates. They may simply be nops, which do not
2881                     // need to prevent issuing the notification, and if so, may not
2882                     // cause a timely frame render to occur to wake up any listeners.
2883                     if !self.pending_texture_cache_updates {
2884                         drain_filter(
2885                             &mut notifications,
2886                             |n| { n.when() == Checkpoint::FrameTexturesUpdated },
2887                             |n| { n.notify(); },
2888                         );
2889                     }
2890                     self.notifications.append(&mut notifications);
2891                 }
2892                 ResultMsg::ForceRedraw => {
2893                     self.force_redraw = true;
2894                 }
2895                 ResultMsg::RefreshShader(path) => {
2896                     self.pending_shader_updates.push(path);
2897                 }
2898                 ResultMsg::DebugOutput(output) => match output {
2899                     DebugOutput::FetchDocuments(string) |
2900                     DebugOutput::FetchClipScrollTree(string) => {
2901                         self.debug_server.send(string);
2902                     }
2903                     #[cfg(feature = "capture")]
2904                     DebugOutput::SaveCapture(config, deferred) => {
2905                         self.save_capture(config, deferred);
2906                     }
2907                     #[cfg(feature = "replay")]
2908                     DebugOutput::LoadCapture(config, plain_externals) => {
2909                         self.active_documents.clear();
2910                         self.load_capture(config, plain_externals);
2911                     }
2912                 },
2913                 ResultMsg::DebugCommand(command) => {
2914                     self.handle_debug_command(command);
2915                 }
2916             }
2917         }
2918     }
2919 
2920     #[cfg(not(feature = "debugger"))]
get_screenshot_for_debugger(&mut self) -> String2921     fn get_screenshot_for_debugger(&mut self) -> String {
2922         // Avoid unused param warning.
2923         let _ = &self.debug_server;
2924         String::new()
2925     }
2926 
2927     #[cfg(feature = "debugger")]
get_screenshot_for_debugger(&mut self) -> String2928     fn get_screenshot_for_debugger(&mut self) -> String {
2929         use api::{ImageDescriptor, ImageDescriptorFlags};
2930 
2931         let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, ImageDescriptorFlags::IS_OPAQUE);
2932         let data = self.device.read_pixels(&desc);
2933         let screenshot = debug_server::Screenshot::new(desc.size, data);
2934 
2935         serde_json::to_string(&screenshot).unwrap()
2936     }
2937 
2938     #[cfg(not(feature = "debugger"))]
get_passes_for_debugger(&self) -> String2939     fn get_passes_for_debugger(&self) -> String {
2940         // Avoid unused param warning.
2941         let _ = &self.debug_server;
2942         String::new()
2943     }
2944 
2945     #[cfg(feature = "debugger")]
debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target2946     fn debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target {
2947         let mut debug_target = debug_server::Target::new("A8");
2948 
2949         debug_target.add(
2950             debug_server::BatchKind::Cache,
2951             "Scalings",
2952             target.scalings.len(),
2953         );
2954         debug_target.add(
2955             debug_server::BatchKind::Cache,
2956             "Zero Clears",
2957             target.zero_clears.len(),
2958         );
2959         debug_target.add(
2960             debug_server::BatchKind::Cache,
2961             "One Clears",
2962             target.one_clears.len(),
2963         );
2964         debug_target.add(
2965             debug_server::BatchKind::Clip,
2966             "BoxShadows [p]",
2967             target.clip_batcher.primary_clips.box_shadows.len(),
2968         );
2969         debug_target.add(
2970             debug_server::BatchKind::Clip,
2971             "BoxShadows [s]",
2972             target.clip_batcher.secondary_clips.box_shadows.len(),
2973         );
2974         debug_target.add(
2975             debug_server::BatchKind::Cache,
2976             "Vertical Blur",
2977             target.vertical_blurs.len(),
2978         );
2979         debug_target.add(
2980             debug_server::BatchKind::Cache,
2981             "Horizontal Blur",
2982             target.horizontal_blurs.len(),
2983         );
2984         debug_target.add(
2985             debug_server::BatchKind::Clip,
2986             "Slow Rectangles [p]",
2987             target.clip_batcher.primary_clips.slow_rectangles.len(),
2988         );
2989         debug_target.add(
2990             debug_server::BatchKind::Clip,
2991             "Fast Rectangles [p]",
2992             target.clip_batcher.primary_clips.fast_rectangles.len(),
2993         );
2994         debug_target.add(
2995             debug_server::BatchKind::Clip,
2996             "Slow Rectangles [s]",
2997             target.clip_batcher.secondary_clips.slow_rectangles.len(),
2998         );
2999         debug_target.add(
3000             debug_server::BatchKind::Clip,
3001             "Fast Rectangles [s]",
3002             target.clip_batcher.secondary_clips.fast_rectangles.len(),
3003         );
3004         for (_, items) in target.clip_batcher.primary_clips.images.iter() {
3005             debug_target.add(debug_server::BatchKind::Clip, "Image mask [p]", items.len());
3006         }
3007         for (_, items) in target.clip_batcher.secondary_clips.images.iter() {
3008             debug_target.add(debug_server::BatchKind::Clip, "Image mask [s]", items.len());
3009         }
3010 
3011         debug_target
3012     }
3013 
3014     #[cfg(feature = "debugger")]
debug_color_target(target: &ColorRenderTarget) -> debug_server::Target3015     fn debug_color_target(target: &ColorRenderTarget) -> debug_server::Target {
3016         let mut debug_target = debug_server::Target::new("RGBA8");
3017 
3018         debug_target.add(
3019             debug_server::BatchKind::Cache,
3020             "Scalings",
3021             target.scalings.len(),
3022         );
3023         debug_target.add(
3024             debug_server::BatchKind::Cache,
3025             "Readbacks",
3026             target.readbacks.len(),
3027         );
3028         debug_target.add(
3029             debug_server::BatchKind::Cache,
3030             "Vertical Blur",
3031             target.vertical_blurs.len(),
3032         );
3033         debug_target.add(
3034             debug_server::BatchKind::Cache,
3035             "Horizontal Blur",
3036             target.horizontal_blurs.len(),
3037         );
3038         debug_target.add(
3039             debug_server::BatchKind::Cache,
3040             "SVG Filters",
3041             target.svg_filters.iter().map(|(_, batch)| batch.len()).sum(),
3042         );
3043 
3044         for alpha_batch_container in &target.alpha_batch_containers {
3045             for batch in alpha_batch_container.opaque_batches.iter().rev() {
3046                 debug_target.add(
3047                     debug_server::BatchKind::Opaque,
3048                     batch.key.kind.debug_name(),
3049                     batch.instances.len(),
3050                 );
3051             }
3052 
3053             for batch in &alpha_batch_container.alpha_batches {
3054                 debug_target.add(
3055                     debug_server::BatchKind::Alpha,
3056                     batch.key.kind.debug_name(),
3057                     batch.instances.len(),
3058                 );
3059             }
3060         }
3061 
3062         debug_target
3063     }
3064 
3065     #[cfg(feature = "debugger")]
debug_texture_cache_target(target: &TextureCacheRenderTarget) -> debug_server::Target3066     fn debug_texture_cache_target(target: &TextureCacheRenderTarget) -> debug_server::Target {
3067         let mut debug_target = debug_server::Target::new("Texture Cache");
3068 
3069         debug_target.add(
3070             debug_server::BatchKind::Cache,
3071             "Horizontal Blur",
3072             target.horizontal_blurs.len(),
3073         );
3074 
3075         debug_target
3076     }
3077 
3078     #[cfg(feature = "debugger")]
get_passes_for_debugger(&self) -> String3079     fn get_passes_for_debugger(&self) -> String {
3080         let mut debug_passes = debug_server::PassList::new();
3081 
3082         for &(_, ref render_doc) in &self.active_documents {
3083             for pass in &render_doc.frame.passes {
3084                 let mut debug_targets = Vec::new();
3085                 match pass.kind {
3086                     RenderPassKind::MainFramebuffer { ref main_target, .. } => {
3087                         debug_targets.push(Self::debug_color_target(main_target));
3088                     }
3089                     RenderPassKind::OffScreen { ref alpha, ref color, ref texture_cache, .. } => {
3090                         debug_targets.extend(alpha.targets.iter().map(Self::debug_alpha_target));
3091                         debug_targets.extend(color.targets.iter().map(Self::debug_color_target));
3092                         debug_targets.extend(texture_cache.iter().map(|(_, target)| Self::debug_texture_cache_target(target)));
3093                     }
3094                 }
3095 
3096                 debug_passes.add(debug_server::Pass { targets: debug_targets });
3097             }
3098         }
3099 
3100         serde_json::to_string(&debug_passes).unwrap()
3101     }
3102 
3103     #[cfg(not(feature = "debugger"))]
get_render_tasks_for_debugger(&self) -> String3104     fn get_render_tasks_for_debugger(&self) -> String {
3105         String::new()
3106     }
3107 
3108     #[cfg(feature = "debugger")]
get_render_tasks_for_debugger(&self) -> String3109     fn get_render_tasks_for_debugger(&self) -> String {
3110         let mut debug_root = debug_server::RenderTaskList::new();
3111 
3112         for &(_, ref render_doc) in &self.active_documents {
3113             let debug_node = debug_server::TreeNode::new("document render tasks");
3114             let mut builder = debug_server::TreeNodeBuilder::new(debug_node);
3115 
3116             let render_tasks = &render_doc.frame.render_tasks;
3117             match render_tasks.tasks.first() {
3118                 Some(main_task) => main_task.print_with(&mut builder, render_tasks),
3119                 None => continue,
3120             };
3121 
3122             debug_root.add(builder.build());
3123         }
3124 
3125         serde_json::to_string(&debug_root).unwrap()
3126     }
3127 
handle_debug_command(&mut self, command: DebugCommand)3128     fn handle_debug_command(&mut self, command: DebugCommand) {
3129         match command {
3130             DebugCommand::EnableDualSourceBlending(_) |
3131             DebugCommand::SetPictureTileSize(_) => {
3132                 panic!("Should be handled by render backend");
3133             }
3134             DebugCommand::FetchDocuments |
3135             DebugCommand::FetchClipScrollTree => {}
3136             DebugCommand::FetchRenderTasks => {
3137                 let json = self.get_render_tasks_for_debugger();
3138                 self.debug_server.send(json);
3139             }
3140             DebugCommand::FetchPasses => {
3141                 let json = self.get_passes_for_debugger();
3142                 self.debug_server.send(json);
3143             }
3144             DebugCommand::FetchScreenshot => {
3145                 let json = self.get_screenshot_for_debugger();
3146                 self.debug_server.send(json);
3147             }
3148             DebugCommand::SaveCapture(..) |
3149             DebugCommand::LoadCapture(..) |
3150             DebugCommand::StartCaptureSequence(..) |
3151             DebugCommand::StopCaptureSequence => {
3152                 panic!("Capture commands are not welcome here! Did you build with 'capture' feature?")
3153             }
3154             DebugCommand::ClearCaches(_)
3155             | DebugCommand::SimulateLongSceneBuild(_)
3156             | DebugCommand::SimulateLongLowPrioritySceneBuild(_)
3157             | DebugCommand::EnableNativeCompositor(_)
3158             | DebugCommand::SetBatchingLookback(_)
3159             | DebugCommand::EnableMultithreading(_) => {}
3160             DebugCommand::InvalidateGpuCache => {
3161                 match self.gpu_cache_texture.bus {
3162                     GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
3163                         info!("Invalidating GPU caches");
3164                         for row in rows {
3165                             row.add_dirty(0, MAX_VERTEX_TEXTURE_WIDTH);
3166                         }
3167                     }
3168                     GpuCacheBus::Scatter { .. } => {
3169                         warn!("Unable to invalidate scattered GPU cache");
3170                     }
3171                 }
3172             }
3173             DebugCommand::SetFlags(flags) => {
3174                 self.set_debug_flags(flags);
3175             }
3176         }
3177     }
3178 
3179     /// Set a callback for handling external images.
set_external_image_handler(&mut self, handler: Box<dyn ExternalImageHandler>)3180     pub fn set_external_image_handler(&mut self, handler: Box<dyn ExternalImageHandler>) {
3181         self.external_image_handler = Some(handler);
3182     }
3183 
3184     /// Set a callback for handling external outputs.
set_output_image_handler(&mut self, handler: Box<dyn OutputImageHandler>)3185     pub fn set_output_image_handler(&mut self, handler: Box<dyn OutputImageHandler>) {
3186         self.output_image_handler = Some(handler);
3187     }
3188 
3189     /// Retrieve (and clear) the current list of recorded frame profiles.
get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>)3190     pub fn get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>) {
3191         let cpu_profiles = self.cpu_profiles.drain(..).collect();
3192         let gpu_profiles = self.gpu_profiles.drain(..).collect();
3193         (cpu_profiles, gpu_profiles)
3194     }
3195 
3196     /// Reset the current partial present state. This forces the entire framebuffer
3197     /// to be refreshed next time `render` is called.
force_redraw(&mut self)3198     pub fn force_redraw(&mut self) {
3199         self.force_redraw = true;
3200     }
3201 
3202     /// Renders the current frame.
3203     ///
3204     /// A Frame is supplied by calling [`generate_frame()`][webrender_api::Transaction::generate_frame].
render( &mut self, device_size: DeviceIntSize, ) -> Result<RenderResults, Vec<RendererError>>3205     pub fn render(
3206         &mut self,
3207         device_size: DeviceIntSize,
3208     ) -> Result<RenderResults, Vec<RendererError>> {
3209         self.device_size = Some(device_size);
3210 
3211         let result = self.render_impl(Some(device_size));
3212 
3213         drain_filter(
3214             &mut self.notifications,
3215             |n| { n.when() == Checkpoint::FrameRendered },
3216             |n| { n.notify(); },
3217         );
3218 
3219         // This is the end of the rendering pipeline. If some notifications are is still there,
3220         // just clear them and they will autimatically fire the Checkpoint::TransactionDropped
3221         // event. Otherwise they would just pile up in this vector forever.
3222         self.notifications.clear();
3223 
3224         tracy_frame_marker!();
3225 
3226         result
3227     }
3228 
3229     /// Update the state of any debug / profiler overlays. This is currently only needed
3230     /// when running with the native compositor enabled.
update_debug_overlay(&mut self, framebuffer_size: DeviceIntSize)3231     fn update_debug_overlay(&mut self, framebuffer_size: DeviceIntSize) {
3232         // If any of the following debug flags are set, something will be drawn on the debug overlay.
3233         self.debug_overlay_state.is_enabled = self.debug_flags.intersects(
3234             DebugFlags::PROFILER_DBG |
3235             DebugFlags::RENDER_TARGET_DBG |
3236             DebugFlags::TEXTURE_CACHE_DBG |
3237             DebugFlags::EPOCHS |
3238             DebugFlags::NEW_FRAME_INDICATOR |
3239             DebugFlags::NEW_SCENE_INDICATOR |
3240             DebugFlags::GPU_CACHE_DBG |
3241             DebugFlags::SLOW_FRAME_INDICATOR |
3242             DebugFlags::PICTURE_CACHING_DBG |
3243             DebugFlags::PRIMITIVE_DBG |
3244             DebugFlags::ZOOM_DBG
3245         );
3246 
3247         // Update the debug overlay surface, if we are running in native compositor mode.
3248         if let CompositorKind::Native { .. } = self.current_compositor_kind {
3249             let compositor = self.compositor_config.compositor().unwrap();
3250 
3251             // If there is a current surface, destroy it if we don't need it for this frame, or if
3252             // the size has changed.
3253             if let Some(current_size) = self.debug_overlay_state.current_size {
3254                 if !self.debug_overlay_state.is_enabled || current_size != framebuffer_size {
3255                     compositor.destroy_surface(NativeSurfaceId::DEBUG_OVERLAY);
3256                     self.debug_overlay_state.current_size = None;
3257                 }
3258             }
3259 
3260             // Allocate a new surface, if we need it and there isn't one.
3261             if self.debug_overlay_state.is_enabled && self.debug_overlay_state.current_size.is_none() {
3262                 compositor.create_surface(
3263                     NativeSurfaceId::DEBUG_OVERLAY,
3264                     DeviceIntPoint::zero(),
3265                     framebuffer_size,
3266                     false,
3267                 );
3268                 compositor.create_tile(
3269                     NativeTileId::DEBUG_OVERLAY,
3270                 );
3271                 self.debug_overlay_state.current_size = Some(framebuffer_size);
3272             }
3273         }
3274     }
3275 
3276     /// Bind a draw target for the debug / profiler overlays, if required.
bind_debug_overlay(&mut self)3277     fn bind_debug_overlay(&mut self) {
3278         // Debug overlay setup are only required in native compositing mode
3279         if self.debug_overlay_state.is_enabled {
3280             if let CompositorKind::Native { .. } = self.current_compositor_kind {
3281                 let compositor = self.compositor_config.compositor().unwrap();
3282                 let surface_size = self.debug_overlay_state.current_size.unwrap();
3283 
3284                 // Bind the native surface
3285                 let surface_info = compositor.bind(
3286                     NativeTileId::DEBUG_OVERLAY,
3287                     DeviceIntRect::new(
3288                         DeviceIntPoint::zero(),
3289                         surface_size,
3290                     ),
3291                     DeviceIntRect::new(
3292                         DeviceIntPoint::zero(),
3293                         surface_size,
3294                     ),
3295                 );
3296 
3297                 // Bind the native surface to current FBO target
3298                 let draw_target = DrawTarget::NativeSurface {
3299                     offset: surface_info.origin,
3300                     external_fbo_id: surface_info.fbo_id,
3301                     dimensions: surface_size,
3302                 };
3303                 self.device.bind_draw_target(draw_target);
3304 
3305                 // When native compositing, clear the debug overlay each frame.
3306                 self.device.clear_target(
3307                     Some([0.0, 0.0, 0.0, 0.0]),
3308                     Some(1.0),
3309                     None,
3310                 );
3311             }
3312         }
3313     }
3314 
3315     /// Unbind the draw target for debug / profiler overlays, if required.
unbind_debug_overlay(&mut self)3316     fn unbind_debug_overlay(&mut self) {
3317         // Debug overlay setup are only required in native compositing mode
3318         if self.debug_overlay_state.is_enabled {
3319             if let CompositorKind::Native { .. } = self.current_compositor_kind {
3320                 let compositor = self.compositor_config.compositor().unwrap();
3321                 // Unbind the draw target and add it to the visual tree to be composited
3322                 compositor.unbind();
3323 
3324                 compositor.add_surface(
3325                     NativeSurfaceId::DEBUG_OVERLAY,
3326                     DeviceIntPoint::zero(),
3327                     DeviceIntRect::new(
3328                         DeviceIntPoint::zero(),
3329                         self.debug_overlay_state.current_size.unwrap(),
3330                     ),
3331                 );
3332             }
3333         }
3334     }
3335 
3336     // If device_size is None, don't render
3337     // to the main frame buffer. This is useful
3338     // to update texture cache render tasks but
3339     // avoid doing a full frame render.
render_impl( &mut self, device_size: Option<DeviceIntSize>, ) -> Result<RenderResults, Vec<RendererError>>3340     fn render_impl(
3341         &mut self,
3342         device_size: Option<DeviceIntSize>,
3343     ) -> Result<RenderResults, Vec<RendererError>> {
3344         profile_scope!("render");
3345         let mut results = RenderResults::default();
3346         if self.active_documents.is_empty() {
3347             self.last_time = precise_time_ns();
3348             return Ok(results);
3349         }
3350 
3351         let compositor_kind = self.active_documents[0].1.frame.composite_state.compositor_kind;
3352         // CompositorKind is updated
3353         if self.current_compositor_kind != compositor_kind {
3354             let enable = match (self.current_compositor_kind, compositor_kind) {
3355                 (CompositorKind::Native { .. }, CompositorKind::Draw { .. }) => {
3356                     if self.debug_overlay_state.current_size.is_some() {
3357                         self.compositor_config
3358                             .compositor()
3359                             .unwrap()
3360                             .destroy_surface(NativeSurfaceId::DEBUG_OVERLAY);
3361                         self.debug_overlay_state.current_size = None;
3362                     }
3363                     false
3364                 }
3365                 (CompositorKind::Draw { .. }, CompositorKind::Native { .. }) => {
3366                     true
3367                 }
3368                 (_, _) => {
3369                     unreachable!();
3370                 }
3371             };
3372 
3373             self.compositor_config
3374                 .compositor()
3375                 .unwrap()
3376                 .enable_native_compositor(enable);
3377             self.current_compositor_kind = compositor_kind;
3378         }
3379 
3380         let mut frame_profiles = Vec::new();
3381         let mut profile_timers = RendererProfileTimers::new();
3382 
3383         // The texture resolver scope should be outside of any rendering, including
3384         // debug rendering. This ensures that when we return render targets to the
3385         // pool via glInvalidateFramebuffer, we don't do any debug rendering after
3386         // that point. Otherwise, the bind / invalidate / bind logic trips up the
3387         // render pass logic in tiled / mobile GPUs, resulting in an extra copy /
3388         // resolve step when the debug overlay is enabled.
3389         self.texture_resolver.begin_frame();
3390 
3391         let profile_samplers = {
3392             let _gm = self.gpu_profile.start_marker("build samples");
3393             // Block CPU waiting for last frame's GPU profiles to arrive.
3394             // In general this shouldn't block unless heavily GPU limited.
3395             let (gpu_frame_id, timers, samplers) = self.gpu_profile.build_samples();
3396 
3397             if self.max_recorded_profiles > 0 {
3398                 while self.gpu_profiles.len() >= self.max_recorded_profiles {
3399                     self.gpu_profiles.pop_front();
3400                 }
3401                 self.gpu_profiles
3402                     .push_back(GpuProfile::new(gpu_frame_id, &timers));
3403             }
3404             profile_timers.gpu_samples = timers;
3405             samplers
3406         };
3407 
3408 
3409         let cpu_frame_id = profile_timers.cpu_time.profile(|| {
3410             let _gm = self.gpu_profile.start_marker("begin frame");
3411             let frame_id = self.device.begin_frame();
3412             self.gpu_profile.begin_frame(frame_id);
3413 
3414             self.device.disable_scissor();
3415             self.device.disable_depth();
3416             self.set_blend(false, FramebufferKind::Main);
3417             //self.update_shaders();
3418 
3419             self.update_texture_cache();
3420             self.update_native_surfaces();
3421 
3422             frame_id
3423         });
3424 
3425         // Inform the client that we are starting a composition transaction if native
3426         // compositing is enabled. This needs to be done early in the frame, so that
3427         // we can create debug overlays after drawing the main surfaces.
3428         if let CompositorKind::Native { .. } = self.current_compositor_kind {
3429             let compositor = self.compositor_config.compositor().unwrap();
3430             compositor.begin_frame();
3431         }
3432 
3433         profile_timers.cpu_time.profile(|| {
3434             //Note: another borrowck dance
3435             let mut active_documents = mem::replace(&mut self.active_documents, Vec::default());
3436             // sort by the document layer id
3437             active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer);
3438 
3439             #[cfg(feature = "replay")]
3440             self.texture_resolver.external_images.extend(
3441                 self.owned_external_images.iter().map(|(key, value)| (*key, value.clone()))
3442             );
3443 
3444             let last_document_index = active_documents.len() - 1;
3445             for (doc_index, (document_id, RenderedDocument { ref mut frame, .. })) in active_documents.iter_mut().enumerate() {
3446                 assert!(self.current_compositor_kind == frame.composite_state.compositor_kind);
3447 
3448                 if self.shared_texture_cache_cleared {
3449                     assert!(self.documents_seen.contains(&document_id),
3450                             "Cleared texture cache without sending new document frame.");
3451                 }
3452 
3453                 frame.profile_counters.reset_targets();
3454                 if let Err(e) = self.prepare_gpu_cache(frame) {
3455                     self.renderer_errors.push(e);
3456                     continue;
3457                 }
3458                 assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
3459                     "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
3460                     frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
3461 
3462                 {
3463                     profile_scope!("gl.flush");
3464                     self.device.gl().flush();  // early start on gpu cache updates
3465                 }
3466 
3467                 self.draw_frame(
3468                     frame,
3469                     device_size,
3470                     cpu_frame_id,
3471                     &mut results,
3472                     doc_index == 0,
3473                 );
3474 
3475                 // Profile marker for the number of invalidated picture cache
3476                 if thread_is_being_profiled() {
3477                     let num_invalidated = self.profile_counters.rendered_picture_cache_tiles.get_accum();
3478                     let message = format!("NumPictureCacheInvalidated: {}", num_invalidated);
3479                     add_event_marker(&(CString::new(message).unwrap()));
3480                 }
3481 
3482                 if device_size.is_some() {
3483                     self.draw_frame_debug_items(&frame.debug_items);
3484                 }
3485                 if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
3486                     frame_profiles.push(frame.profile_counters.clone());
3487                 }
3488 
3489                 let dirty_regions =
3490                     mem::replace(&mut frame.recorded_dirty_regions, Vec::new());
3491                 results.recorded_dirty_regions.extend(dirty_regions);
3492 
3493                 // If we're the last document, don't call end_pass here, because we'll
3494                 // be moving on to drawing the debug overlays. See the comment above
3495                 // the end_pass call in draw_frame about debug draw overlays
3496                 // for a bit more context.
3497                 if doc_index != last_document_index {
3498                     self.texture_resolver.end_pass(&mut self.device, None, None);
3499                 }
3500             }
3501 
3502             self.unlock_external_images();
3503             self.active_documents = active_documents;
3504 
3505             let _gm = self.gpu_profile.start_marker("end frame");
3506             self.gpu_profile.end_frame();
3507         });
3508 
3509         if let Some(device_size) = device_size {
3510             // Update the state of the debug overlay surface, ensuring that
3511             // the compositor mode has a suitable surface to draw to, if required.
3512             self.update_debug_overlay(device_size);
3513 
3514             // Bind a surface to draw the debug / profiler information to.
3515             self.bind_debug_overlay();
3516 
3517             self.draw_render_target_debug(device_size);
3518             self.draw_texture_cache_debug(device_size);
3519             self.draw_gpu_cache_debug(device_size);
3520             self.draw_zoom_debug(device_size);
3521             self.draw_epoch_debug();
3522         }
3523 
3524         let current_time = precise_time_ns();
3525         if device_size.is_some() {
3526             let ns = current_time - self.last_time;
3527             self.profile_counters.frame_time.set(ns);
3528         }
3529 
3530         let frame_cpu_time_ns = self.backend_profile_counters.total_time.get()
3531             + profile_timers.cpu_time.get();
3532         let frame_cpu_time_ms = frame_cpu_time_ns as f64 / 1000000.0;
3533         if frame_cpu_time_ms > 16.0 {
3534             self.slow_frame_indicator.changed();
3535         }
3536 
3537         if self.backend_profile_counters.scene_changed {
3538             let txn_time_ns = self.backend_profile_counters.txn.total_send_time.get()
3539                 + self.backend_profile_counters.txn.display_list_build_time.get()
3540                 + self.backend_profile_counters.txn.scene_build_time.get();
3541             let txn_time_ms = txn_time_ns as f64 / 1000000.0;
3542             if txn_time_ms > 100.0 {
3543                 self.slow_txn_indicator.changed();
3544             }
3545         }
3546 
3547         if self.max_recorded_profiles > 0 {
3548             while self.cpu_profiles.len() >= self.max_recorded_profiles {
3549                 self.cpu_profiles.pop_front();
3550             }
3551             let cpu_profile = CpuProfile::new(
3552                 cpu_frame_id,
3553                 self.backend_profile_counters.total_time.get(),
3554                 profile_timers.cpu_time.get(),
3555                 self.profile_counters.draw_calls.get(),
3556             );
3557             self.cpu_profiles.push_back(cpu_profile);
3558         }
3559 
3560         if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
3561             if let Some(device_size) = device_size {
3562                 //TODO: take device/pixel ratio into equation?
3563                 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
3564                     let style = if self.debug_flags.contains(DebugFlags::SMART_PROFILER) {
3565                         ProfileStyle::Smart
3566                     } else if self.debug_flags.contains(DebugFlags::COMPACT_PROFILER) {
3567                         ProfileStyle::Compact
3568                     } else {
3569                         ProfileStyle::Full
3570                     };
3571 
3572                     let screen_fraction = 1.0 / device_size.to_f32().area();
3573                     self.profiler.draw_profile(
3574                         &frame_profiles,
3575                         &self.backend_profile_counters,
3576                         &self.profile_counters,
3577                         &mut profile_timers,
3578                         &profile_samplers,
3579                         screen_fraction,
3580                         debug_renderer,
3581                         style,
3582                     );
3583                 }
3584             }
3585         }
3586 
3587         let mut x = 0.0;
3588         if self.debug_flags.contains(DebugFlags::NEW_FRAME_INDICATOR) {
3589             if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
3590                 self.new_frame_indicator.changed();
3591                 self.new_frame_indicator.draw(
3592                     x, 0.0,
3593                     ColorU::new(0, 110, 220, 255),
3594                     debug_renderer,
3595                 );
3596                 x += ChangeIndicator::width();
3597             }
3598         }
3599 
3600         if self.debug_flags.contains(DebugFlags::NEW_SCENE_INDICATOR) {
3601             if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
3602                 self.new_scene_indicator.draw(
3603                     x, 0.0,
3604                     ColorU::new(0, 220, 110, 255),
3605                     debug_renderer,
3606                 );
3607                 x += ChangeIndicator::width();
3608             }
3609         }
3610 
3611         if self.debug_flags.contains(DebugFlags::SLOW_FRAME_INDICATOR) {
3612             if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
3613                 self.slow_txn_indicator.draw(
3614                     x, 0.0,
3615                     ColorU::new(250, 80, 80, 255),
3616                     debug_renderer,
3617                 );
3618                 self.slow_frame_indicator.draw(
3619                     x, 10.0,
3620                     ColorU::new(220, 30, 10, 255),
3621                     debug_renderer,
3622                 );
3623             }
3624         }
3625 
3626         if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
3627             self.device.echo_driver_messages();
3628         }
3629 
3630         results.stats.texture_upload_kb = self.profile_counters.texture_data_uploaded.get();
3631         self.backend_profile_counters.reset();
3632         self.profile_counters.reset();
3633         self.profile_counters.frame_counter.inc();
3634         results.stats.resource_upload_time = self.resource_upload_time;
3635         self.resource_upload_time = 0;
3636         results.stats.gpu_cache_upload_time = self.gpu_cache_upload_time;
3637         self.gpu_cache_upload_time = 0;
3638 
3639         profile_timers.cpu_time.profile(|| {
3640             if let Some(debug_renderer) = self.debug.try_get_mut() {
3641                 let small_screen = self.debug_flags.contains(DebugFlags::SMALL_SCREEN);
3642                 let scale = if small_screen { 1.6 } else { 1.0 };
3643                 // TODO(gw): Tidy this up so that compositor config integrates better
3644                 //           with the (non-compositor) surface y-flip options.
3645                 let surface_origin_is_top_left = match self.current_compositor_kind {
3646                     CompositorKind::Native { .. } => true,
3647                     CompositorKind::Draw { .. } => self.device.surface_origin_is_top_left(),
3648                 };
3649                 debug_renderer.render(
3650                     &mut self.device,
3651                     device_size,
3652                     scale,
3653                     surface_origin_is_top_left,
3654                 );
3655             }
3656             // See comment for texture_resolver.begin_frame() for explanation
3657             // of why this must be done after all rendering, including debug
3658             // overlays. The end_frame() call implicitly calls end_pass(), which
3659             // should ensure any left over render targets get invalidated and
3660             // returned to the pool correctly.
3661             self.texture_resolver.end_frame(&mut self.device, cpu_frame_id);
3662             self.device.end_frame();
3663         });
3664 
3665         if device_size.is_some() {
3666             self.last_time = current_time;
3667 
3668             // Unbind the target for the debug overlay. No debug or profiler drawing
3669             // can occur afer this point.
3670             self.unbind_debug_overlay();
3671         }
3672 
3673         // Inform the client that we are finished this composition transaction if native
3674         // compositing is enabled. This must be called after any debug / profiling compositor
3675         // surfaces have been drawn and added to the visual tree.
3676         if let CompositorKind::Native { .. } = self.current_compositor_kind {
3677             profile_scope!("compositor.end_frame");
3678             let compositor = self.compositor_config.compositor().unwrap();
3679             compositor.end_frame();
3680         }
3681 
3682         self.documents_seen.clear();
3683         self.shared_texture_cache_cleared = false;
3684 
3685         if self.renderer_errors.is_empty() {
3686             Ok(results)
3687         } else {
3688             Err(mem::replace(&mut self.renderer_errors, Vec::new()))
3689         }
3690     }
3691 
update_gpu_cache(&mut self)3692     fn update_gpu_cache(&mut self) {
3693         let _gm = self.gpu_profile.start_marker("gpu cache update");
3694 
3695         // For an artificial stress test of GPU cache resizing,
3696         // always pass an extra update list with at least one block in it.
3697         let gpu_cache_height = self.gpu_cache_texture.get_height();
3698         if gpu_cache_height != 0 && GPU_CACHE_RESIZE_TEST {
3699             self.pending_gpu_cache_updates.push(GpuCacheUpdateList {
3700                 frame_id: FrameId::INVALID,
3701                 clear: false,
3702                 height: gpu_cache_height,
3703                 blocks: vec![[1f32; 4].into()],
3704                 updates: Vec::new(),
3705                 debug_commands: Vec::new(),
3706             });
3707         }
3708 
3709         let (updated_blocks, max_requested_height) = self
3710             .pending_gpu_cache_updates
3711             .iter()
3712             .fold((0, gpu_cache_height), |(count, height), list| {
3713                 (count + list.blocks.len(), cmp::max(height, list.height))
3714             });
3715 
3716         if max_requested_height > self.get_max_texture_size() && !self.gpu_cache_overflow {
3717             self.gpu_cache_overflow = true;
3718             self.renderer_errors.push(RendererError::MaxTextureSize);
3719         }
3720 
3721         // Note: if we decide to switch to scatter-style GPU cache update
3722         // permanently, we can have this code nicer with `BufferUploader` kind
3723         // of helper, similarly to how `TextureUploader` API is used.
3724         self.gpu_cache_texture.prepare_for_updates(
3725             &mut self.device,
3726             updated_blocks,
3727             max_requested_height,
3728         );
3729 
3730         for update_list in self.pending_gpu_cache_updates.drain(..) {
3731             assert!(update_list.height <= max_requested_height);
3732             if update_list.frame_id > self.gpu_cache_frame_id {
3733                 self.gpu_cache_frame_id = update_list.frame_id
3734             }
3735             self.gpu_cache_texture
3736                 .update(&mut self.device, &update_list);
3737         }
3738 
3739         let mut upload_time = TimeProfileCounter::new("GPU cache upload time", false, Some(0.0..2.0));
3740         let updated_rows = upload_time.profile(|| {
3741             self.gpu_cache_texture.flush(&mut self.device)
3742         });
3743         self.gpu_cache_upload_time += upload_time.get();
3744 
3745         let counters = &mut self.backend_profile_counters.resources.gpu_cache;
3746         counters.updated_rows.set(updated_rows);
3747         counters.updated_blocks.set(updated_blocks);
3748     }
3749 
prepare_gpu_cache(&mut self, frame: &Frame) -> Result<(), RendererError>3750     fn prepare_gpu_cache(&mut self, frame: &Frame) -> Result<(), RendererError> {
3751         if self.pending_gpu_cache_clear {
3752             let use_scatter =
3753                 matches!(self.gpu_cache_texture.bus, GpuCacheBus::Scatter { .. });
3754             let new_cache = GpuCacheTexture::new(&mut self.device, use_scatter)?;
3755             let old_cache = mem::replace(&mut self.gpu_cache_texture, new_cache);
3756             old_cache.deinit(&mut self.device);
3757             self.pending_gpu_cache_clear = false;
3758         }
3759 
3760         let deferred_update_list = self.update_deferred_resolves(&frame.deferred_resolves);
3761         self.pending_gpu_cache_updates.extend(deferred_update_list);
3762 
3763         self.update_gpu_cache();
3764 
3765         // Note: the texture might have changed during the `update`,
3766         // so we need to bind it here.
3767         self.device.bind_texture(
3768             TextureSampler::GpuCache,
3769             self.gpu_cache_texture.texture.as_ref().unwrap(),
3770             Swizzle::default(),
3771         );
3772 
3773         Ok(())
3774     }
3775 
update_texture_cache(&mut self)3776     fn update_texture_cache(&mut self) {
3777         profile_scope!("update_texture_cache");
3778 
3779         let _gm = self.gpu_profile.start_marker("texture cache update");
3780         let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
3781         self.pending_texture_cache_updates = false;
3782 
3783         let mut upload_time = TimeProfileCounter::new("Resource upload time", false, Some(0.0..2.0));
3784         upload_time.profile(|| {
3785             for update_list in pending_texture_updates.drain(..) {
3786                 for allocation in update_list.allocations {
3787                     match allocation.kind {
3788                         TextureCacheAllocationKind::Alloc(_) => add_event_marker(c_str!("TextureCacheAlloc")),
3789                         TextureCacheAllocationKind::Realloc(_) => add_event_marker(c_str!("TextureCacheRealloc")),
3790                         TextureCacheAllocationKind::Reset(_) => add_event_marker(c_str!("TextureCacheReset")),
3791                         TextureCacheAllocationKind::Free => add_event_marker(c_str!("TextureCacheFree")),
3792                     };
3793                     let old = match allocation.kind {
3794                         TextureCacheAllocationKind::Alloc(ref info) |
3795                         TextureCacheAllocationKind::Realloc(ref info) |
3796                         TextureCacheAllocationKind::Reset(ref info) => {
3797                             // Create a new native texture, as requested by the texture cache.
3798                             //
3799                             // Ensure no PBO is bound when creating the texture storage,
3800                             // or GL will attempt to read data from there.
3801                             let mut texture = self.device.create_texture(
3802                                 TextureTarget::Array,
3803                                 info.format,
3804                                 info.width,
3805                                 info.height,
3806                                 info.filter,
3807                                 // This needs to be a render target because some render
3808                                 // tasks get rendered into the texture cache.
3809                                 Some(RenderTargetInfo { has_depth: info.has_depth }),
3810                                 info.layer_count,
3811                             );
3812 
3813                             if info.is_shared_cache {
3814                                 texture.flags_mut()
3815                                     .insert(TextureFlags::IS_SHARED_TEXTURE_CACHE);
3816 
3817                                 // Textures in the cache generally don't need to be cleared,
3818                                 // but we do so if the debug display is active to make it
3819                                 // easier to identify unallocated regions.
3820                                 if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
3821                                     self.clear_texture(&texture, TEXTURE_CACHE_DBG_CLEAR_COLOR);
3822                                 }
3823                             }
3824 
3825                             self.texture_resolver.texture_cache_map.insert(allocation.id, texture)
3826                         }
3827                         TextureCacheAllocationKind::Free => {
3828                             self.texture_resolver.texture_cache_map.remove(&allocation.id)
3829                         }
3830                     };
3831 
3832                     match allocation.kind {
3833                         TextureCacheAllocationKind::Alloc(_) => {
3834                             assert!(old.is_none(), "Renderer and backend disagree!");
3835                         }
3836                         TextureCacheAllocationKind::Realloc(_) => {
3837                             self.device.blit_renderable_texture(
3838                                 self.texture_resolver.texture_cache_map.get_mut(&allocation.id).unwrap(),
3839                                 old.as_ref().unwrap(),
3840                             );
3841                         }
3842                         TextureCacheAllocationKind::Reset(_) |
3843                         TextureCacheAllocationKind::Free => {
3844                             assert!(old.is_some(), "Renderer and backend disagree!");
3845                         }
3846                     }
3847 
3848                     if let Some(old) = old {
3849                         self.device.delete_texture(old);
3850                     }
3851                 }
3852 
3853                 for (texture_id, updates) in update_list.updates {
3854                     let texture = &self.texture_resolver.texture_cache_map[&texture_id];
3855                     let device = &mut self.device;
3856 
3857                     // Calculate the total size of buffer required to upload all updates.
3858                     let required_size = updates.iter().map(|update| {
3859                         // Perform any debug clears now. As this requires a mutable borrow of device,
3860                         // it must be done before all the updates which require a TextureUploader.
3861                         if let TextureUpdateSource::DebugClear = update.source  {
3862                             let draw_target = DrawTarget::from_texture(
3863                                 texture,
3864                                 update.layer_index as usize,
3865                                 false,
3866                             );
3867                             device.bind_draw_target(draw_target);
3868                             device.clear_target(
3869                                 Some(TEXTURE_CACHE_DBG_CLEAR_COLOR),
3870                                 None,
3871                                 Some(draw_target.to_framebuffer_rect(update.rect.to_i32()))
3872                             );
3873 
3874                             0
3875                         } else {
3876                             let (upload_size, _) = device.required_upload_size_and_stride(
3877                                 update.rect.size,
3878                                 texture.get_format(),
3879                             );
3880                             upload_size
3881                         }
3882                     }).sum();
3883 
3884                     if required_size == 0 {
3885                         continue;
3886                     }
3887 
3888                     // For best performance we use a single TextureUploader for all uploads.
3889                     // Using individual TextureUploaders was causing performance issues on some drivers
3890                     // due to allocating too many PBOs.
3891                     let mut uploader = device.upload_texture(
3892                         texture,
3893                         &self.texture_cache_upload_pbo,
3894                         required_size
3895                     );
3896 
3897                     for update in updates {
3898                         let TextureCacheUpdate { rect, stride, offset, layer_index, format_override, source } = update;
3899 
3900                         let bytes_uploaded = match source {
3901                             TextureUpdateSource::Bytes { data } => {
3902                                 let data = &data[offset as usize ..];
3903                                 uploader.upload(
3904                                     rect,
3905                                     layer_index,
3906                                     stride,
3907                                     format_override,
3908                                     data.as_ptr(),
3909                                     data.len(),
3910                                 )
3911                             }
3912                             TextureUpdateSource::External { id, channel_index } => {
3913                                 let handler = self.external_image_handler
3914                                     .as_mut()
3915                                     .expect("Found external image, but no handler set!");
3916                                 // The filter is only relevant for NativeTexture external images.
3917                                 let dummy_data;
3918                                 let data = match handler.lock(id, channel_index, ImageRendering::Auto).source {
3919                                     ExternalImageSource::RawData(data) => {
3920                                         &data[offset as usize ..]
3921                                     }
3922                                     ExternalImageSource::Invalid => {
3923                                         // Create a local buffer to fill the pbo.
3924                                         let bpp = texture.get_format().bytes_per_pixel();
3925                                         let width = stride.unwrap_or(rect.size.width * bpp);
3926                                         let total_size = width * rect.size.height;
3927                                         // WR haven't support RGBAF32 format in texture_cache, so
3928                                         // we use u8 type here.
3929                                         dummy_data = vec![0xFFu8; total_size as usize];
3930                                         &dummy_data
3931                                     }
3932                                     ExternalImageSource::NativeTexture(eid) => {
3933                                         panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
3934                                     }
3935                                 };
3936                                 let size = uploader.upload(
3937                                     rect,
3938                                     layer_index,
3939                                     stride,
3940                                     format_override,
3941                                     data.as_ptr(),
3942                                     data.len()
3943                                 );
3944                                 handler.unlock(id, channel_index);
3945                                 size
3946                             }
3947                             TextureUpdateSource::DebugClear => {
3948                                 // DebugClear updates are handled separately.
3949                                 0
3950                             }
3951                         };
3952                         self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
3953                     }
3954                 }
3955 
3956                 if update_list.clears_shared_cache {
3957                     self.shared_texture_cache_cleared = true;
3958                 }
3959             }
3960 
3961             drain_filter(
3962                 &mut self.notifications,
3963                 |n| { n.when() == Checkpoint::FrameTexturesUpdated },
3964                 |n| { n.notify(); },
3965             );
3966         });
3967         self.resource_upload_time += upload_time.get();
3968     }
3969 
draw_instanced_batch<T>( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, textures: &BatchTextures, stats: &mut RendererStats, )3970     pub(crate) fn draw_instanced_batch<T>(
3971         &mut self,
3972         data: &[T],
3973         vertex_array_kind: VertexArrayKind,
3974         textures: &BatchTextures,
3975         stats: &mut RendererStats,
3976     ) {
3977         let mut swizzles = [Swizzle::default(); 3];
3978         for i in 0 .. textures.colors.len() {
3979             let swizzle = self.texture_resolver.bind(
3980                 &textures.colors[i],
3981                 TextureSampler::color(i),
3982                 &mut self.device,
3983             );
3984             if cfg!(debug_assertions) {
3985                 swizzles[i] = swizzle;
3986                 for j in 0 .. i {
3987                     if textures.colors[j] == textures.colors[i] && swizzles[j] != swizzle {
3988                         error!("Swizzling conflict in {:?}", textures);
3989                     }
3990                 }
3991             }
3992         }
3993 
3994         // TODO: this probably isn't the best place for this.
3995         if let Some(ref texture) = self.dither_matrix_texture {
3996             self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
3997         }
3998 
3999         self.draw_instanced_batch_with_previously_bound_textures(data, vertex_array_kind, stats)
4000     }
4001 
draw_instanced_batch_with_previously_bound_textures<T>( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, stats: &mut RendererStats, )4002     pub(crate) fn draw_instanced_batch_with_previously_bound_textures<T>(
4003         &mut self,
4004         data: &[T],
4005         vertex_array_kind: VertexArrayKind,
4006         stats: &mut RendererStats,
4007     ) {
4008         // If we end up with an empty draw call here, that means we have
4009         // probably introduced unnecessary batch breaks during frame
4010         // building - so we should be catching this earlier and removing
4011         // the batch.
4012         debug_assert!(!data.is_empty());
4013 
4014         let vao = get_vao(vertex_array_kind, &self.vaos);
4015 
4016         self.device.bind_vao(vao);
4017 
4018         let batched = !self.debug_flags.contains(DebugFlags::DISABLE_BATCHING);
4019 
4020         if batched {
4021             self.device
4022                 .update_vao_instances(vao, data, VertexUsageHint::Stream);
4023             self.device
4024                 .draw_indexed_triangles_instanced_u16(6, data.len() as i32);
4025             self.profile_counters.draw_calls.inc();
4026             stats.total_draw_calls += 1;
4027         } else {
4028             for i in 0 .. data.len() {
4029                 self.device
4030                     .update_vao_instances(vao, &data[i .. i + 1], VertexUsageHint::Stream);
4031                 self.device.draw_triangles_u16(0, 6);
4032                 self.profile_counters.draw_calls.inc();
4033                 stats.total_draw_calls += 1;
4034             }
4035         }
4036 
4037         self.profile_counters.vertices.add(6 * data.len());
4038     }
4039 
handle_readback_composite( &mut self, draw_target: DrawTarget, uses_scissor: bool, source: &RenderTask, backdrop: &RenderTask, readback: &RenderTask, )4040     fn handle_readback_composite(
4041         &mut self,
4042         draw_target: DrawTarget,
4043         uses_scissor: bool,
4044         source: &RenderTask,
4045         backdrop: &RenderTask,
4046         readback: &RenderTask,
4047     ) {
4048         if uses_scissor {
4049             self.device.disable_scissor();
4050         }
4051 
4052         let (cache_texture, _) = self.texture_resolver
4053             .resolve(&TextureSource::PrevPassColor)
4054             .unwrap();
4055 
4056         // Before submitting the composite batch, do the
4057         // framebuffer readbacks that are needed for each
4058         // composite operation in this batch.
4059         let (readback_rect, readback_layer) = readback.get_target_rect();
4060         let (backdrop_rect, _) = backdrop.get_target_rect();
4061         let (backdrop_screen_origin, backdrop_scale) = match backdrop.kind {
4062             RenderTaskKind::Picture(ref task_info) => (task_info.content_origin, task_info.device_pixel_scale),
4063             _ => panic!("bug: composite on non-picture?"),
4064         };
4065         let (source_screen_origin, source_scale) = match source.kind {
4066             RenderTaskKind::Picture(ref task_info) => (task_info.content_origin, task_info.device_pixel_scale),
4067             _ => panic!("bug: composite on non-picture?"),
4068         };
4069 
4070         // Bind the FBO to blit the backdrop to.
4071         // Called per-instance in case the layer (and therefore FBO)
4072         // changes. The device will skip the GL call if the requested
4073         // target is already bound.
4074         let cache_draw_target = DrawTarget::from_texture(
4075             cache_texture,
4076             readback_layer.0 as usize,
4077             false,
4078         );
4079 
4080         let source_in_backdrop_space = source_screen_origin.to_f32() * (backdrop_scale.0 / source_scale.0);
4081 
4082         let mut src = DeviceIntRect::new(
4083             (source_in_backdrop_space + (backdrop_rect.origin - backdrop_screen_origin).to_f32()).to_i32(),
4084             readback_rect.size,
4085         );
4086         let mut dest = readback_rect.to_i32();
4087         let device_to_framebuffer = Scale::new(1i32);
4088 
4089         // Need to invert the y coordinates and flip the image vertically when
4090         // reading back from the framebuffer.
4091         if draw_target.is_default() {
4092             src.origin.y = draw_target.dimensions().height as i32 - src.size.height - src.origin.y;
4093             dest.origin.y += dest.size.height;
4094             dest.size.height = -dest.size.height;
4095         }
4096 
4097         self.device.blit_render_target(
4098             draw_target.into(),
4099             src * device_to_framebuffer,
4100             cache_draw_target,
4101             dest * device_to_framebuffer,
4102             TextureFilter::Linear,
4103         );
4104 
4105         // Restore draw target to current pass render target + layer, and reset
4106         // the read target.
4107         self.device.bind_draw_target(draw_target);
4108         self.device.reset_read_target();
4109 
4110         if uses_scissor {
4111             self.device.enable_scissor();
4112         }
4113     }
4114 
handle_blits( &mut self, blits: &[BlitJob], render_tasks: &RenderTaskGraph, draw_target: DrawTarget, content_origin: &DeviceIntPoint, )4115     fn handle_blits(
4116         &mut self,
4117         blits: &[BlitJob],
4118         render_tasks: &RenderTaskGraph,
4119         draw_target: DrawTarget,
4120         content_origin: &DeviceIntPoint,
4121     ) {
4122         if blits.is_empty() {
4123             return;
4124         }
4125 
4126         let _timer = self.gpu_profile.start_timer(GPU_TAG_BLIT);
4127 
4128         // TODO(gw): For now, we don't bother batching these by source texture.
4129         //           If if ever shows up as an issue, we can easily batch them.
4130         for blit in blits {
4131             let (source, layer, source_rect) = match blit.source {
4132                 BlitJobSource::Texture(texture_id, layer, source_rect) => {
4133                     // A blit from a texture into this target.
4134                     (texture_id, layer as usize, source_rect)
4135                 }
4136                 BlitJobSource::RenderTask(task_id) => {
4137                     // A blit from the child render task into this target.
4138                     // TODO(gw): Support R8 format here once we start
4139                     //           creating mips for alpha masks.
4140                     let source = &render_tasks[task_id];
4141                     let (source_rect, layer) = source.get_target_rect();
4142                     (TextureSource::PrevPassColor, layer.0, source_rect)
4143                 }
4144             };
4145 
4146             debug_assert_eq!(source_rect.size, blit.target_rect.size);
4147             let (texture, swizzle) = self.texture_resolver
4148                 .resolve(&source)
4149                 .expect("BUG: invalid source texture");
4150 
4151             if swizzle != Swizzle::default() {
4152                 error!("Swizzle {:?} can't be handled by a blit", swizzle);
4153             }
4154 
4155             let read_target = DrawTarget::from_texture(
4156                 texture,
4157                 layer,
4158                 false,
4159             );
4160 
4161             self.device.blit_render_target(
4162                 read_target.into(),
4163                 read_target.to_framebuffer_rect(source_rect),
4164                 draw_target,
4165                 draw_target.to_framebuffer_rect(blit.target_rect.translate(-content_origin.to_vector())),
4166                 TextureFilter::Linear,
4167             );
4168         }
4169     }
4170 
handle_scaling( &mut self, scalings: &FastHashMap<TextureSource, Vec<ScalingInstance>>, projection: &default::Transform3D<f32>, stats: &mut RendererStats, )4171     fn handle_scaling(
4172         &mut self,
4173         scalings: &FastHashMap<TextureSource, Vec<ScalingInstance>>,
4174         projection: &default::Transform3D<f32>,
4175         stats: &mut RendererStats,
4176     ) {
4177         if scalings.is_empty() {
4178             return
4179         }
4180 
4181         let _timer = self.gpu_profile.start_timer(GPU_TAG_SCALE);
4182 
4183         self.shaders
4184             .borrow_mut()
4185             .cs_scale
4186             .bind(
4187                 &mut self.device,
4188                 &projection,
4189                 &mut self.renderer_errors,
4190             );
4191 
4192         for (source, instances) in scalings {
4193             self.draw_instanced_batch(
4194                 instances,
4195                 VertexArrayKind::Scale,
4196                 &BatchTextures::color(*source),
4197                 stats,
4198             );
4199         }
4200     }
4201 
handle_svg_filters( &mut self, textures: &BatchTextures, svg_filters: &[SvgFilterInstance], projection: &default::Transform3D<f32>, stats: &mut RendererStats, )4202     fn handle_svg_filters(
4203         &mut self,
4204         textures: &BatchTextures,
4205         svg_filters: &[SvgFilterInstance],
4206         projection: &default::Transform3D<f32>,
4207         stats: &mut RendererStats,
4208     ) {
4209         if svg_filters.is_empty() {
4210             return;
4211         }
4212 
4213         let _timer = self.gpu_profile.start_timer(GPU_TAG_SVG_FILTER);
4214 
4215         self.shaders.borrow_mut().cs_svg_filter.bind(
4216             &mut self.device,
4217             &projection,
4218             &mut self.renderer_errors
4219         );
4220 
4221         self.draw_instanced_batch(
4222             &svg_filters,
4223             VertexArrayKind::SvgFilter,
4224             textures,
4225             stats,
4226         );
4227     }
4228 
draw_picture_cache_target( &mut self, target: &PictureCacheTarget, draw_target: DrawTarget, content_origin: DeviceIntPoint, projection: &default::Transform3D<f32>, render_tasks: &RenderTaskGraph, stats: &mut RendererStats, )4229     fn draw_picture_cache_target(
4230         &mut self,
4231         target: &PictureCacheTarget,
4232         draw_target: DrawTarget,
4233         content_origin: DeviceIntPoint,
4234         projection: &default::Transform3D<f32>,
4235         render_tasks: &RenderTaskGraph,
4236         stats: &mut RendererStats,
4237     ) {
4238         profile_scope!("draw_picture_cache_target");
4239 
4240         self.profile_counters.rendered_picture_cache_tiles.inc();
4241         let _gm = self.gpu_profile.start_marker("picture cache target");
4242         let framebuffer_kind = FramebufferKind::Other;
4243 
4244         {
4245             let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
4246             self.device.bind_draw_target(draw_target);
4247             self.device.disable_depth();
4248             self.device.enable_depth_write();
4249             self.set_blend(false, framebuffer_kind);
4250 
4251             // If updating only a dirty rect within a picture cache target, the
4252             // clear must also be scissored to that dirty region.
4253             let scissor_rect = target.alpha_batch_container.task_scissor_rect.map(|rect| {
4254                 draw_target.build_scissor_rect(
4255                     Some(rect),
4256                     content_origin,
4257                 )
4258             });
4259 
4260             self.device.clear_target(
4261                 target.clear_color.map(|c| c.to_array()),
4262                 Some(1.0),
4263                 scissor_rect,
4264             );
4265 
4266             self.device.disable_depth_write();
4267         }
4268 
4269         self.draw_alpha_batch_container(
4270             &target.alpha_batch_container,
4271             draw_target,
4272             content_origin,
4273             framebuffer_kind,
4274             projection,
4275             render_tasks,
4276             stats,
4277         );
4278     }
4279 
4280     /// Draw an alpha batch container into a given draw target. This is used
4281     /// by both color and picture cache target kinds.
draw_alpha_batch_container( &mut self, alpha_batch_container: &AlphaBatchContainer, draw_target: DrawTarget, content_origin: DeviceIntPoint, framebuffer_kind: FramebufferKind, projection: &default::Transform3D<f32>, render_tasks: &RenderTaskGraph, stats: &mut RendererStats, )4282     fn draw_alpha_batch_container(
4283         &mut self,
4284         alpha_batch_container: &AlphaBatchContainer,
4285         draw_target: DrawTarget,
4286         content_origin: DeviceIntPoint,
4287         framebuffer_kind: FramebufferKind,
4288         projection: &default::Transform3D<f32>,
4289         render_tasks: &RenderTaskGraph,
4290         stats: &mut RendererStats,
4291     ) {
4292         let uses_scissor = alpha_batch_container.task_scissor_rect.is_some();
4293 
4294         if uses_scissor {
4295             self.device.enable_scissor();
4296             let scissor_rect = draw_target.build_scissor_rect(
4297                 alpha_batch_container.task_scissor_rect,
4298                 content_origin,
4299             );
4300             self.device.set_scissor_rect(scissor_rect)
4301         }
4302 
4303         if !alpha_batch_container.opaque_batches.is_empty()
4304             && !self.debug_flags.contains(DebugFlags::DISABLE_OPAQUE_PASS) {
4305             let _gl = self.gpu_profile.start_marker("opaque batches");
4306             let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
4307             self.set_blend(false, framebuffer_kind);
4308             //Note: depth equality is needed for split planes
4309             self.device.set_depth_func(DepthFunction::LessEqual);
4310             self.device.enable_depth();
4311             self.device.enable_depth_write();
4312 
4313             // Draw opaque batches front-to-back for maximum
4314             // z-buffer efficiency!
4315             for batch in alpha_batch_container
4316                 .opaque_batches
4317                 .iter()
4318                 .rev()
4319                 {
4320                     if should_skip_batch(&batch.key.kind, self.debug_flags) {
4321                         continue;
4322                     }
4323 
4324                     self.shaders.borrow_mut()
4325                         .get(&batch.key, batch.features, self.debug_flags)
4326                         .bind(
4327                             &mut self.device, projection,
4328                             &mut self.renderer_errors,
4329                         );
4330 
4331                     let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
4332                     self.draw_instanced_batch(
4333                         &batch.instances,
4334                         VertexArrayKind::Primitive,
4335                         &batch.key.textures,
4336                         stats
4337                     );
4338                 }
4339 
4340             self.device.disable_depth_write();
4341             self.gpu_profile.finish_sampler(opaque_sampler);
4342         }
4343 
4344         if !alpha_batch_container.alpha_batches.is_empty()
4345             && !self.debug_flags.contains(DebugFlags::DISABLE_ALPHA_PASS) {
4346             let _gl = self.gpu_profile.start_marker("alpha batches");
4347             let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
4348             self.set_blend(true, framebuffer_kind);
4349 
4350             let mut prev_blend_mode = BlendMode::None;
4351             let shaders_rc = self.shaders.clone();
4352 
4353             // If the device supports pixel local storage, initialize the PLS buffer for
4354             // the transparent pass. This involves reading the current framebuffer value
4355             // and storing that in PLS.
4356             // TODO(gw): This is quite expensive and relies on framebuffer fetch being
4357             //           available. We can probably switch the opaque pass over to use
4358             //           PLS too, and remove this pass completely.
4359             if self.device.get_capabilities().supports_pixel_local_storage {
4360                 // TODO(gw): If using PLS, the fixed function blender is disabled. It's possible
4361                 //           we could take advantage of this by skipping batching on the blend
4362                 //           mode in these cases.
4363                 self.init_pixel_local_storage(
4364                     alpha_batch_container.task_rect,
4365                     projection,
4366                     stats,
4367                 );
4368             }
4369 
4370             for batch in &alpha_batch_container.alpha_batches {
4371                 if should_skip_batch(&batch.key.kind, self.debug_flags) {
4372                     continue;
4373                 }
4374 
4375                 let mut shaders = shaders_rc.borrow_mut();
4376                 let shader = shaders.get(
4377                     &batch.key,
4378                     batch.features | BatchFeatures::ALPHA_PASS,
4379                     self.debug_flags,
4380                 );
4381 
4382                 if batch.key.blend_mode != prev_blend_mode {
4383                     match batch.key.blend_mode {
4384                         _ if self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) &&
4385                             framebuffer_kind == FramebufferKind::Main => {
4386                             self.device.set_blend_mode_show_overdraw();
4387                         }
4388                         BlendMode::None => {
4389                             unreachable!("bug: opaque blend in alpha pass");
4390                         }
4391                         BlendMode::Alpha => {
4392                             self.device.set_blend_mode_alpha();
4393                         }
4394                         BlendMode::PremultipliedAlpha => {
4395                             self.device.set_blend_mode_premultiplied_alpha();
4396                         }
4397                         BlendMode::PremultipliedDestOut => {
4398                             self.device.set_blend_mode_premultiplied_dest_out();
4399                         }
4400                         BlendMode::SubpixelDualSource => {
4401                             self.device.set_blend_mode_subpixel_dual_source();
4402                         }
4403                         BlendMode::SubpixelConstantTextColor(color) => {
4404                             self.device.set_blend_mode_subpixel_constant_text_color(color);
4405                         }
4406                         BlendMode::SubpixelWithBgColor => {
4407                             // Using the three pass "component alpha with font smoothing
4408                             // background color" rendering technique:
4409                             //
4410                             // /webrender/doc/text-rendering.md
4411                             //
4412                             self.device.set_blend_mode_subpixel_with_bg_color_pass0();
4413                             // need to make sure the shader is bound
4414                             shader.bind(
4415                                 &mut self.device,
4416                                 projection,
4417                                 &mut self.renderer_errors,
4418                             );
4419                             self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
4420                         }
4421                         BlendMode::Advanced(mode) => {
4422                             if self.enable_advanced_blend_barriers {
4423                                 self.device.gl().blend_barrier_khr();
4424                             }
4425                             self.device.set_blend_mode_advanced(mode);
4426                         }
4427                     }
4428                     prev_blend_mode = batch.key.blend_mode;
4429                 }
4430 
4431                 // Handle special case readback for composites.
4432                 if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = batch.key.kind {
4433                     // composites can't be grouped together because
4434                     // they may overlap and affect each other.
4435                     debug_assert_eq!(batch.instances.len(), 1);
4436                     self.handle_readback_composite(
4437                         draw_target,
4438                         uses_scissor,
4439                         &render_tasks[source_id],
4440                         &render_tasks[task_id],
4441                         &render_tasks[backdrop_id],
4442                     );
4443                 }
4444 
4445                 let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
4446                 shader.bind(
4447                     &mut self.device,
4448                     projection,
4449                     &mut self.renderer_errors,
4450                 );
4451 
4452                 self.draw_instanced_batch(
4453                     &batch.instances,
4454                     VertexArrayKind::Primitive,
4455                     &batch.key.textures,
4456                     stats
4457                 );
4458 
4459                 if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
4460                     self.set_blend_mode_subpixel_with_bg_color_pass1(framebuffer_kind);
4461                     // re-binding the shader after the blend mode change
4462                     shader.bind(
4463                         &mut self.device,
4464                         projection,
4465                         &mut self.renderer_errors,
4466                     );
4467                     self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass1 as _);
4468 
4469                     // When drawing the 2nd and 3rd passes, we know that the VAO, textures etc
4470                     // are all set up from the previous draw_instanced_batch call,
4471                     // so just issue a draw call here to avoid re-uploading the
4472                     // instances and re-binding textures etc.
4473                     self.device
4474                         .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
4475 
4476                     self.set_blend_mode_subpixel_with_bg_color_pass2(framebuffer_kind);
4477                     // re-binding the shader after the blend mode change
4478                     shader.bind(
4479                         &mut self.device,
4480                         projection,
4481                         &mut self.renderer_errors,
4482                     );
4483                     self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _);
4484 
4485                     self.device
4486                         .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
4487                 }
4488 
4489                 if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
4490                     prev_blend_mode = BlendMode::None;
4491                 }
4492             }
4493 
4494             // If the device supports pixel local storage, resolve the PLS values.
4495             // This pass reads the final PLS color value, and writes it to a normal
4496             // fragment output.
4497             if self.device.get_capabilities().supports_pixel_local_storage {
4498                 self.resolve_pixel_local_storage(
4499                     alpha_batch_container.task_rect,
4500                     projection,
4501                     stats,
4502                 );
4503             }
4504 
4505             self.device.disable_depth();
4506             self.set_blend(false, framebuffer_kind);
4507             self.gpu_profile.finish_sampler(transparent_sampler);
4508         }
4509 
4510         if uses_scissor {
4511             self.device.disable_scissor();
4512         }
4513     }
4514 
4515     /// Rasterize any external compositor surfaces that require updating
update_external_native_surfaces( &mut self, external_surfaces: &[ResolvedExternalSurface], results: &mut RenderResults, )4516     fn update_external_native_surfaces(
4517         &mut self,
4518         external_surfaces: &[ResolvedExternalSurface],
4519         results: &mut RenderResults,
4520     ) {
4521         if external_surfaces.is_empty() {
4522             return;
4523         }
4524 
4525         let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
4526 
4527         self.device.disable_depth();
4528         self.set_blend(false, FramebufferKind::Main);
4529 
4530         for surface in external_surfaces {
4531             // See if this surface needs to be updated
4532             let (native_surface_id, surface_size) = match surface.update_params {
4533                 Some(params) => params,
4534                 None => continue,
4535             };
4536 
4537             // When updating an external surface, the entire surface rect is used
4538             // for all of the draw, dirty, valid and clip rect parameters.
4539             let surface_rect = surface_size.into();
4540 
4541             // Bind the native compositor surface to update
4542             let surface_info = self.compositor_config
4543                 .compositor()
4544                 .unwrap()
4545                 .bind(
4546                     NativeTileId {
4547                         surface_id: native_surface_id,
4548                         x: 0,
4549                         y: 0,
4550                     },
4551                     surface_rect,
4552                     surface_rect,
4553                 );
4554 
4555             // Bind the native surface to current FBO target
4556             let draw_target = DrawTarget::NativeSurface {
4557                 offset: surface_info.origin,
4558                 external_fbo_id: surface_info.fbo_id,
4559                 dimensions: surface_size,
4560             };
4561             self.device.bind_draw_target(draw_target);
4562 
4563             let projection = Transform3D::ortho(
4564                 0.0,
4565                 surface_size.width as f32,
4566                 0.0,
4567                 surface_size.height as f32,
4568                 self.device.ortho_near_plane(),
4569                 self.device.ortho_far_plane(),
4570             );
4571 
4572             let ( textures, instance ) = match surface.color_data {
4573                 ResolvedExternalSurfaceColorData::Yuv{
4574                         ref planes, color_space, format, rescale, .. } => {
4575 
4576                     // Bind an appropriate YUV shader for the texture format kind
4577                     self.shaders
4578                         .borrow_mut()
4579                         .get_composite_shader(
4580                             CompositeSurfaceFormat::Yuv,
4581                             surface.image_buffer_kind,
4582                         ).bind(
4583                             &mut self.device,
4584                             &projection,
4585                             &mut self.renderer_errors
4586                         );
4587 
4588                     let textures = BatchTextures {
4589                         colors: [
4590                             planes[0].texture,
4591                             planes[1].texture,
4592                             planes[2].texture,
4593                         ],
4594                     };
4595 
4596                     // When the texture is an external texture, the UV rect is not known when
4597                     // the external surface descriptor is created, because external textures
4598                     // are not resolved until the lock() callback is invoked at the start of
4599                     // the frame render. To handle this, query the texture resolver for the
4600                     // UV rect if it's an external texture, otherwise use the default UV rect.
4601                     let uv_rects = [
4602                         self.texture_resolver.get_uv_rect(&textures.colors[0], planes[0].uv_rect),
4603                         self.texture_resolver.get_uv_rect(&textures.colors[1], planes[1].uv_rect),
4604                         self.texture_resolver.get_uv_rect(&textures.colors[2], planes[2].uv_rect),
4605                     ];
4606 
4607                     let instance = CompositeInstance::new_yuv(
4608                         surface_rect.to_f32(),
4609                         surface_rect.to_f32(),
4610                         // z-id is not relevant when updating a native compositor surface.
4611                         // TODO(gw): Support compositor surfaces without z-buffer, for memory / perf win here.
4612                         ZBufferId(0),
4613                         color_space,
4614                         format,
4615                         rescale,
4616                         [
4617                             planes[0].texture_layer as f32,
4618                             planes[1].texture_layer as f32,
4619                             planes[2].texture_layer as f32,
4620                         ],
4621                         uv_rects,
4622                     );
4623 
4624                     ( textures, instance )
4625                 },
4626                 ResolvedExternalSurfaceColorData::Rgb{ ref plane, flip_y, .. } => {
4627 
4628                     self.shaders
4629                         .borrow_mut()
4630                         .get_composite_shader(
4631                             CompositeSurfaceFormat::Rgba,
4632                             surface.image_buffer_kind,
4633                         ).bind(
4634                             &mut self.device,
4635                             &projection,
4636                             &mut self.renderer_errors
4637                         );
4638 
4639                     let textures = BatchTextures::color(plane.texture);
4640                     let mut uv_rect = self.texture_resolver.get_uv_rect(&textures.colors[0], plane.uv_rect);
4641                     if flip_y {
4642                         let y = uv_rect.uv0.y;
4643                         uv_rect.uv0.y = uv_rect.uv1.y;
4644                         uv_rect.uv1.y = y;
4645                     }
4646 
4647                     let instance = CompositeInstance::new_rgb(
4648                         surface_rect.to_f32(),
4649                         surface_rect.to_f32(),
4650                         PremultipliedColorF::WHITE,
4651                         plane.texture_layer as f32,
4652                         ZBufferId(0),
4653                         uv_rect,
4654                     );
4655 
4656                     ( textures, instance )
4657                 },
4658             };
4659 
4660             self.draw_instanced_batch(
4661                 &[instance],
4662                 VertexArrayKind::Composite,
4663                 &textures,
4664                 &mut results.stats,
4665             );
4666 
4667             self.compositor_config
4668                 .compositor()
4669                 .unwrap()
4670                 .unbind();
4671         }
4672 
4673         self.gpu_profile.finish_sampler(opaque_sampler);
4674     }
4675 
4676     /// Draw a list of tiles to the framebuffer
draw_tile_list<'a, I: Iterator<Item = &'a CompositeTile>>( &mut self, tiles_iter: I, external_surfaces: &[ResolvedExternalSurface], projection: &default::Transform3D<f32>, partial_present_mode: Option<PartialPresentMode>, stats: &mut RendererStats, )4677     fn draw_tile_list<'a, I: Iterator<Item = &'a CompositeTile>>(
4678         &mut self,
4679         tiles_iter: I,
4680         external_surfaces: &[ResolvedExternalSurface],
4681         projection: &default::Transform3D<f32>,
4682         partial_present_mode: Option<PartialPresentMode>,
4683         stats: &mut RendererStats,
4684     ) {
4685         self.shaders
4686             .borrow_mut()
4687             .get_composite_shader(
4688                 CompositeSurfaceFormat::Rgba,
4689                 ImageBufferKind::Texture2DArray,
4690             ).bind(
4691                 &mut self.device,
4692                 projection,
4693                 &mut self.renderer_errors
4694             );
4695 
4696         let mut current_shader_params = (CompositeSurfaceFormat::Rgba, ImageBufferKind::Texture2DArray);
4697         let mut current_textures = BatchTextures::no_texture();
4698         let mut instances = Vec::new();
4699 
4700         for tile in tiles_iter {
4701             // Determine a clip rect to apply to this tile, depending on what
4702             // the partial present mode is.
4703             let partial_clip_rect = match partial_present_mode {
4704                 Some(PartialPresentMode::Single { dirty_rect }) => dirty_rect,
4705                 None => tile.rect,
4706             };
4707 
4708             let clip_rect = match partial_clip_rect.intersection(&tile.clip_rect) {
4709                 Some(rect) => rect,
4710                 None => continue,
4711             };
4712 
4713             // Simple compositor needs the valid rect in device space to match clip rect
4714             let valid_device_rect = tile.valid_rect.translate(
4715                 tile.rect.origin.to_vector()
4716             );
4717 
4718             // Only composite the part of the tile that contains valid pixels
4719             let clip_rect = match clip_rect.intersection(&valid_device_rect) {
4720                 Some(rect) => rect,
4721                 None => continue,
4722             };
4723 
4724             // Work out the draw params based on the tile surface
4725             let (instance, textures, shader_params) = match tile.surface {
4726                 CompositeTileSurface::Color { color } => {
4727                     (
4728                         CompositeInstance::new(
4729                             tile.rect,
4730                             clip_rect,
4731                             color.premultiplied(),
4732                             0.0,
4733                             tile.z_id,
4734                         ),
4735                         BatchTextures::color(TextureSource::Dummy),
4736                         (CompositeSurfaceFormat::Rgba, ImageBufferKind::Texture2DArray),
4737                     )
4738                 }
4739                 CompositeTileSurface::Clear => {
4740                     (
4741                         CompositeInstance::new(
4742                             tile.rect,
4743                             clip_rect,
4744                             PremultipliedColorF::BLACK,
4745                             0.0,
4746                             tile.z_id,
4747                         ),
4748                         BatchTextures::color(TextureSource::Dummy),
4749                         (CompositeSurfaceFormat::Rgba, ImageBufferKind::Texture2DArray),
4750                     )
4751                 }
4752                 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::TextureCache { texture, layer } } => {
4753                     (
4754                         CompositeInstance::new(
4755                             tile.rect,
4756                             clip_rect,
4757                             PremultipliedColorF::WHITE,
4758                             layer as f32,
4759                             tile.z_id,
4760                         ),
4761                         BatchTextures::color(texture),
4762                         (CompositeSurfaceFormat::Rgba, ImageBufferKind::Texture2DArray),
4763                     )
4764                 }
4765                 CompositeTileSurface::ExternalSurface { external_surface_index } => {
4766                     let surface = &external_surfaces[external_surface_index.0];
4767 
4768                     match surface.color_data {
4769                         ResolvedExternalSurfaceColorData::Yuv{ ref planes, color_space, format, rescale, .. } => {
4770 
4771                             let textures = BatchTextures {
4772                                 colors: [
4773                                     planes[0].texture,
4774                                     planes[1].texture,
4775                                     planes[2].texture,
4776                                 ],
4777                             };
4778 
4779                             // When the texture is an external texture, the UV rect is not known when
4780                             // the external surface descriptor is created, because external textures
4781                             // are not resolved until the lock() callback is invoked at the start of
4782                             // the frame render. To handle this, query the texture resolver for the
4783                             // UV rect if it's an external texture, otherwise use the default UV rect.
4784                             let uv_rects = [
4785                                 self.texture_resolver.get_uv_rect(&textures.colors[0], planes[0].uv_rect),
4786                                 self.texture_resolver.get_uv_rect(&textures.colors[1], planes[1].uv_rect),
4787                                 self.texture_resolver.get_uv_rect(&textures.colors[2], planes[2].uv_rect),
4788                             ];
4789 
4790                             (
4791                                 CompositeInstance::new_yuv(
4792                                     tile.rect,
4793                                     clip_rect,
4794                                     tile.z_id,
4795                                     color_space,
4796                                     format,
4797                                     rescale,
4798                                     [
4799                                         planes[0].texture_layer as f32,
4800                                         planes[1].texture_layer as f32,
4801                                         planes[2].texture_layer as f32,
4802                                     ],
4803                                     uv_rects,
4804                                 ),
4805                                 textures,
4806                                 (CompositeSurfaceFormat::Yuv, surface.image_buffer_kind),
4807                             )
4808                         },
4809                         ResolvedExternalSurfaceColorData::Rgb{ ref plane, flip_y, .. } => {
4810 
4811                             let mut uv_rect = self.texture_resolver.get_uv_rect(&plane.texture, plane.uv_rect);
4812                             if flip_y {
4813                                 let y = uv_rect.uv0.y;
4814                                 uv_rect.uv0.y = uv_rect.uv1.y;
4815                                 uv_rect.uv1.y = y;
4816                             }
4817 
4818                             (
4819                                 CompositeInstance::new_rgb(
4820                                     tile.rect,
4821                                     clip_rect,
4822                                     PremultipliedColorF::WHITE,
4823                                     plane.texture_layer as f32,
4824                                     tile.z_id,
4825                                     uv_rect,
4826                                 ),
4827                                 BatchTextures::color(plane.texture),
4828                                 (CompositeSurfaceFormat::Rgba, surface.image_buffer_kind),
4829                             )
4830                         },
4831                     }
4832                 }
4833                 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { .. } } => {
4834                     unreachable!("bug: found native surface in simple composite path");
4835                 }
4836             };
4837 
4838             // Flush batch if shader params or textures changed
4839             let flush_batch = !current_textures.is_compatible_with(&textures) ||
4840                 shader_params != current_shader_params;
4841 
4842             if flush_batch {
4843                 if !instances.is_empty() {
4844                     self.draw_instanced_batch(
4845                         &instances,
4846                         VertexArrayKind::Composite,
4847                         &current_textures,
4848                         stats,
4849                     );
4850                     instances.clear();
4851                 }
4852             }
4853 
4854             if shader_params != current_shader_params {
4855                 self.shaders
4856                     .borrow_mut()
4857                     .get_composite_shader(shader_params.0, shader_params.1)
4858                     .bind(
4859                         &mut self.device,
4860                         projection,
4861                         &mut self.renderer_errors
4862                     );
4863 
4864                 current_shader_params = shader_params;
4865             }
4866 
4867             current_textures = textures;
4868 
4869             // Add instance to current batch
4870             instances.push(instance);
4871         }
4872 
4873         // Flush the last batch
4874         if !instances.is_empty() {
4875             self.draw_instanced_batch(
4876                 &instances,
4877                 VertexArrayKind::Composite,
4878                 &current_textures,
4879                 stats,
4880             );
4881         }
4882     }
4883 
4884     /// Composite picture cache tiles into the framebuffer. This is currently
4885     /// the only way that picture cache tiles get drawn. In future, the tiles
4886     /// will often be handed to the OS compositor, and this method will be
4887     /// rarely used.
composite_simple( &mut self, composite_state: &CompositeState, clear_framebuffer: bool, draw_target: DrawTarget, projection: &default::Transform3D<f32>, results: &mut RenderResults, max_partial_present_rects: usize, draw_previous_partial_present_regions: bool, )4888     fn composite_simple(
4889         &mut self,
4890         composite_state: &CompositeState,
4891         clear_framebuffer: bool,
4892         draw_target: DrawTarget,
4893         projection: &default::Transform3D<f32>,
4894         results: &mut RenderResults,
4895         max_partial_present_rects: usize,
4896         draw_previous_partial_present_regions: bool,
4897     ) {
4898         let _gm = self.gpu_profile.start_marker("framebuffer");
4899         let _timer = self.gpu_profile.start_timer(GPU_TAG_COMPOSITE);
4900 
4901         self.device.bind_draw_target(draw_target);
4902         self.device.enable_depth();
4903         self.device.enable_depth_write();
4904 
4905         // Determine the partial present mode for this frame, which is used during
4906         // framebuffer clears and calculating the clip rect for each tile that is drawn.
4907         let mut partial_present_mode = None;
4908 
4909         if max_partial_present_rects > 0 {
4910             // We can only use partial present if we have valid dirty rects and the
4911             // client hasn't reset partial present state since last frame.
4912             if composite_state.dirty_rects_are_valid && !self.force_redraw {
4913                 let mut combined_dirty_rect = DeviceRect::zero();
4914 
4915                 // Work out how many dirty rects WR produced, and if that's more than
4916                 // what the device supports.
4917                 for tile in composite_state.opaque_tiles.iter().chain(composite_state.alpha_tiles.iter()) {
4918                     let dirty_rect = tile.dirty_rect.translate(tile.rect.origin.to_vector());
4919                     combined_dirty_rect = combined_dirty_rect.union(&dirty_rect);
4920                 }
4921 
4922                 let combined_dirty_rect = combined_dirty_rect.round();
4923                 let combined_dirty_rect_i32 = combined_dirty_rect.to_i32();
4924                 // If nothing has changed, don't return any dirty rects at all (the client
4925                 // can use this as a signal to skip present completely).
4926                 if !combined_dirty_rect.is_empty() {
4927                     results.dirty_rects.push(combined_dirty_rect_i32);
4928                 }
4929 
4930                 // If the implementation requires manually keeping the buffer consistent,
4931                 // combine the previous frame's damage for tile clipping.
4932                 // (Not for the returned region though, that should be from this frame only)
4933                 partial_present_mode = Some(PartialPresentMode::Single {
4934                     dirty_rect: if draw_previous_partial_present_regions {
4935                         combined_dirty_rect.union(&self.prev_dirty_rect)
4936                     } else { combined_dirty_rect },
4937                 });
4938 
4939                 if draw_previous_partial_present_regions {
4940                     self.prev_dirty_rect = combined_dirty_rect;
4941                 }
4942             } else {
4943                 // If we don't have a valid partial present scenario, return a single
4944                 // dirty rect to the client that covers the entire framebuffer.
4945                 let fb_rect = DeviceIntRect::new(
4946                     DeviceIntPoint::zero(),
4947                     draw_target.dimensions(),
4948                 );
4949                 results.dirty_rects.push(fb_rect);
4950 
4951                 if draw_previous_partial_present_regions {
4952                     self.prev_dirty_rect = fb_rect.to_f32();
4953                 }
4954             }
4955 
4956             self.force_redraw = false;
4957         }
4958 
4959         // Clear the framebuffer, if required
4960         if clear_framebuffer {
4961             let clear_color = self.clear_color.map(|color| color.to_array());
4962 
4963             match partial_present_mode {
4964                 Some(PartialPresentMode::Single { dirty_rect }) => {
4965                     // We have a single dirty rect, so clear only that
4966                     self.device.clear_target(clear_color,
4967                                              Some(1.0),
4968                                              Some(draw_target.to_framebuffer_rect(dirty_rect.to_i32())));
4969                 }
4970                 None => {
4971                     // Partial present is disabled, so clear the entire framebuffer
4972                     self.device.clear_target(clear_color,
4973                                              Some(1.0),
4974                                              None);
4975                 }
4976             }
4977         }
4978 
4979         // We are only interested in tiles backed with actual cached pixels so we don't
4980         // count clear tiles here.
4981         let num_tiles = composite_state.opaque_tiles.len()
4982             + composite_state.alpha_tiles.len();
4983         self.profile_counters.total_picture_cache_tiles.set(num_tiles);
4984 
4985         // Draw opaque tiles first, front-to-back to get maxmum
4986         // z-reject efficiency.
4987         if !composite_state.opaque_tiles.is_empty() {
4988             let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
4989             self.device.enable_depth_write();
4990             self.set_blend(false, FramebufferKind::Main);
4991             self.draw_tile_list(
4992                 composite_state.opaque_tiles.iter().rev(),
4993                 &composite_state.external_surfaces,
4994                 projection,
4995                 partial_present_mode,
4996                 &mut results.stats,
4997             );
4998             self.gpu_profile.finish_sampler(opaque_sampler);
4999         }
5000 
5001         if !composite_state.clear_tiles.is_empty() {
5002             let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
5003             self.device.disable_depth_write();
5004             self.set_blend(true, FramebufferKind::Main);
5005             self.device.set_blend_mode_premultiplied_dest_out();
5006             self.draw_tile_list(
5007                 composite_state.clear_tiles.iter(),
5008                 &composite_state.external_surfaces,
5009                 projection,
5010                 partial_present_mode,
5011                 &mut results.stats,
5012             );
5013             self.gpu_profile.finish_sampler(transparent_sampler);
5014         }
5015 
5016         // Draw alpha tiles
5017         if !composite_state.alpha_tiles.is_empty() {
5018             let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
5019             self.device.disable_depth_write();
5020             self.set_blend(true, FramebufferKind::Main);
5021             self.set_blend_mode_premultiplied_alpha(FramebufferKind::Main);
5022             self.draw_tile_list(
5023                 composite_state.alpha_tiles.iter(),
5024                 &composite_state.external_surfaces,
5025                 projection,
5026                 partial_present_mode,
5027                 &mut results.stats,
5028             );
5029             self.gpu_profile.finish_sampler(transparent_sampler);
5030         }
5031     }
5032 
draw_color_target( &mut self, draw_target: DrawTarget, target: &ColorRenderTarget, content_origin: DeviceIntPoint, clear_color: Option<[f32; 4]>, clear_depth: Option<f32>, render_tasks: &RenderTaskGraph, projection: &default::Transform3D<f32>, frame_id: GpuFrameId, stats: &mut RendererStats, )5033     fn draw_color_target(
5034         &mut self,
5035         draw_target: DrawTarget,
5036         target: &ColorRenderTarget,
5037         content_origin: DeviceIntPoint,
5038         clear_color: Option<[f32; 4]>,
5039         clear_depth: Option<f32>,
5040         render_tasks: &RenderTaskGraph,
5041         projection: &default::Transform3D<f32>,
5042         frame_id: GpuFrameId,
5043         stats: &mut RendererStats,
5044     ) {
5045         profile_scope!("draw_color_target");
5046 
5047         self.profile_counters.color_passes.inc();
5048         let _gm = self.gpu_profile.start_marker("color target");
5049 
5050         // sanity check for the depth buffer
5051         if let DrawTarget::Texture { with_depth, .. } = draw_target {
5052             assert!(with_depth >= target.needs_depth());
5053         }
5054 
5055         let framebuffer_kind = if draw_target.is_default() {
5056             FramebufferKind::Main
5057         } else {
5058             FramebufferKind::Other
5059         };
5060 
5061         {
5062             let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
5063             self.device.bind_draw_target(draw_target);
5064             self.device.disable_depth();
5065             self.set_blend(false, framebuffer_kind);
5066 
5067             if clear_depth.is_some() {
5068                 self.device.enable_depth_write();
5069             }
5070 
5071             let clear_rect = match draw_target {
5072                 DrawTarget::NativeSurface { .. } => {
5073                     unreachable!("bug: native compositor surface in child target");
5074                 }
5075                 DrawTarget::Default { rect, total_size, .. } if rect.origin == FramebufferIntPoint::zero() && rect.size == total_size => {
5076                     // whole screen is covered, no need for scissor
5077                     None
5078                 }
5079                 DrawTarget::Default { rect, .. } => {
5080                     Some(rect)
5081                 }
5082                 DrawTarget::Texture { .. } if self.enable_clear_scissor => {
5083                     // TODO(gw): Applying a scissor rect and minimal clear here
5084                     // is a very large performance win on the Intel and nVidia
5085                     // GPUs that I have tested with. It's possible it may be a
5086                     // performance penalty on other GPU types - we should test this
5087                     // and consider different code paths.
5088                     //
5089                     // Note: The above measurements were taken when render
5090                     // target slices were minimum 2048x2048. Now that we size
5091                     // them adaptively, this may be less of a win (except perhaps
5092                     // on a mostly-unused last slice of a large texture array).
5093                     Some(draw_target.to_framebuffer_rect(target.used_rect()))
5094                 }
5095                 DrawTarget::Texture { .. } | DrawTarget::External { .. } => {
5096                     None
5097                 }
5098             };
5099 
5100             self.device.clear_target(
5101                 clear_color,
5102                 clear_depth,
5103                 clear_rect,
5104             );
5105 
5106             if clear_depth.is_some() {
5107                 self.device.disable_depth_write();
5108             }
5109         }
5110 
5111         // Handle any blits from the texture cache to this target.
5112         self.handle_blits(
5113             &target.blits, render_tasks, draw_target, &content_origin,
5114         );
5115 
5116         // Draw any blurs for this target.
5117         // Blurs are rendered as a standard 2-pass
5118         // separable implementation.
5119         // TODO(gw): In the future, consider having
5120         //           fast path blur shaders for common
5121         //           blur radii with fixed weights.
5122         if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
5123             let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
5124 
5125             self.set_blend(false, framebuffer_kind);
5126             self.shaders.borrow_mut().cs_blur_rgba8
5127                 .bind(&mut self.device, projection, &mut self.renderer_errors);
5128 
5129             if !target.vertical_blurs.is_empty() {
5130                 self.draw_instanced_batch(
5131                     &target.vertical_blurs,
5132                     VertexArrayKind::Blur,
5133                     &BatchTextures::no_texture(),
5134                     stats,
5135                 );
5136             }
5137 
5138             if !target.horizontal_blurs.is_empty() {
5139                 self.draw_instanced_batch(
5140                     &target.horizontal_blurs,
5141                     VertexArrayKind::Blur,
5142                     &BatchTextures::no_texture(),
5143                     stats,
5144                 );
5145             }
5146         }
5147 
5148         self.handle_scaling(
5149             &target.scalings,
5150             projection,
5151             stats,
5152         );
5153 
5154         for (ref textures, ref filters) in &target.svg_filters {
5155             self.handle_svg_filters(
5156                 textures,
5157                 filters,
5158                 projection,
5159                 stats,
5160             );
5161         }
5162 
5163         for alpha_batch_container in &target.alpha_batch_containers {
5164             self.draw_alpha_batch_container(
5165                 alpha_batch_container,
5166                 draw_target,
5167                 content_origin,
5168                 framebuffer_kind,
5169                 projection,
5170                 render_tasks,
5171                 stats,
5172             );
5173         }
5174 
5175         // For any registered image outputs on this render target,
5176         // get the texture from caller and blit it.
5177         for output in &target.outputs {
5178             let handler = self.output_image_handler
5179                 .as_mut()
5180                 .expect("Found output image, but no handler set!");
5181             if let Some((texture_id, output_size)) = handler.lock(output.pipeline_id) {
5182                 let fbo_id = match self.output_targets.entry(texture_id) {
5183                     Entry::Vacant(entry) => {
5184                         let fbo_id = self.device.create_fbo_for_external_texture(texture_id);
5185                         entry.insert(FrameOutput {
5186                             fbo_id,
5187                             last_access: frame_id,
5188                         });
5189                         fbo_id
5190                     }
5191                     Entry::Occupied(mut entry) => {
5192                         let target = entry.get_mut();
5193                         target.last_access = frame_id;
5194                         target.fbo_id
5195                     }
5196                 };
5197                 let (src_rect, _) = render_tasks[output.task_id].get_target_rect();
5198                 if !self.device.surface_origin_is_top_left() {
5199                     self.device.blit_render_target_invert_y(
5200                         draw_target.into(),
5201                         draw_target.to_framebuffer_rect(src_rect.translate(-content_origin.to_vector())),
5202                         DrawTarget::External { fbo: fbo_id, size: output_size },
5203                         output_size.into(),
5204                     );
5205                 } else {
5206                     self.device.blit_render_target(
5207                         draw_target.into(),
5208                         draw_target.to_framebuffer_rect(src_rect.translate(-content_origin.to_vector())),
5209                         DrawTarget::External { fbo: fbo_id, size: output_size },
5210                         output_size.into(),
5211                         TextureFilter::Linear,
5212                     );
5213                 }
5214                 handler.unlock(output.pipeline_id);
5215             }
5216         }
5217     }
5218 
5219     /// Draw all the instances in a clip batcher list to the current target.
draw_clip_batch_list( &mut self, list: &ClipBatchList, projection: &default::Transform3D<f32>, stats: &mut RendererStats, )5220     fn draw_clip_batch_list(
5221         &mut self,
5222         list: &ClipBatchList,
5223         projection: &default::Transform3D<f32>,
5224         stats: &mut RendererStats,
5225     ) {
5226         if self.debug_flags.contains(DebugFlags::DISABLE_CLIP_MASKS) {
5227             return;
5228         }
5229 
5230         // draw rounded cornered rectangles
5231         if !list.slow_rectangles.is_empty() {
5232             let _gm2 = self.gpu_profile.start_marker("slow clip rectangles");
5233             self.shaders.borrow_mut().cs_clip_rectangle_slow.bind(
5234                 &mut self.device,
5235                 projection,
5236                 &mut self.renderer_errors,
5237             );
5238             self.draw_instanced_batch(
5239                 &list.slow_rectangles,
5240                 VertexArrayKind::Clip,
5241                 &BatchTextures::no_texture(),
5242                 stats,
5243             );
5244         }
5245         if !list.fast_rectangles.is_empty() {
5246             let _gm2 = self.gpu_profile.start_marker("fast clip rectangles");
5247             self.shaders.borrow_mut().cs_clip_rectangle_fast.bind(
5248                 &mut self.device,
5249                 projection,
5250                 &mut self.renderer_errors,
5251             );
5252             self.draw_instanced_batch(
5253                 &list.fast_rectangles,
5254                 VertexArrayKind::Clip,
5255                 &BatchTextures::no_texture(),
5256                 stats,
5257             );
5258         }
5259         // draw box-shadow clips
5260         for (mask_texture_id, items) in list.box_shadows.iter() {
5261             let _gm2 = self.gpu_profile.start_marker("box-shadows");
5262             let textures = BatchTextures {
5263                 colors: [
5264                     *mask_texture_id,
5265                     TextureSource::Invalid,
5266                     TextureSource::Invalid,
5267                 ],
5268             };
5269             self.shaders.borrow_mut().cs_clip_box_shadow
5270                 .bind(&mut self.device, projection, &mut self.renderer_errors);
5271             self.draw_instanced_batch(
5272                 items,
5273                 VertexArrayKind::Clip,
5274                 &textures,
5275                 stats,
5276             );
5277         }
5278 
5279         // draw image masks
5280         for (mask_texture_id, items) in list.images.iter() {
5281             let _gm2 = self.gpu_profile.start_marker("clip images");
5282             let textures = BatchTextures {
5283                 colors: [
5284                     *mask_texture_id,
5285                     TextureSource::Invalid,
5286                     TextureSource::Invalid,
5287                 ],
5288             };
5289             self.shaders.borrow_mut().cs_clip_image
5290                 .bind(&mut self.device, projection, &mut self.renderer_errors);
5291             self.draw_instanced_batch(
5292                 items,
5293                 VertexArrayKind::Clip,
5294                 &textures,
5295                 stats,
5296             );
5297         }
5298     }
5299 
draw_alpha_target( &mut self, draw_target: DrawTarget, target: &AlphaRenderTarget, projection: &default::Transform3D<f32>, render_tasks: &RenderTaskGraph, stats: &mut RendererStats, )5300     fn draw_alpha_target(
5301         &mut self,
5302         draw_target: DrawTarget,
5303         target: &AlphaRenderTarget,
5304         projection: &default::Transform3D<f32>,
5305         render_tasks: &RenderTaskGraph,
5306         stats: &mut RendererStats,
5307     ) {
5308         profile_scope!("draw_alpha_target");
5309 
5310         self.profile_counters.alpha_passes.inc();
5311         let _gm = self.gpu_profile.start_marker("alpha target");
5312         let alpha_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_ALPHA);
5313 
5314         {
5315             let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
5316             self.device.bind_draw_target(draw_target);
5317             self.device.disable_depth();
5318             self.device.disable_depth_write();
5319             self.set_blend(false, FramebufferKind::Other);
5320 
5321             // TODO(gw): Applying a scissor rect and minimal clear here
5322             // is a very large performance win on the Intel and nVidia
5323             // GPUs that I have tested with. It's possible it may be a
5324             // performance penalty on other GPU types - we should test this
5325             // and consider different code paths.
5326 
5327             let zero_color = [0.0, 0.0, 0.0, 0.0];
5328             for &task_id in &target.zero_clears {
5329                 let (rect, _) = render_tasks[task_id].get_target_rect();
5330                 self.device.clear_target(
5331                     Some(zero_color),
5332                     None,
5333                     Some(draw_target.to_framebuffer_rect(rect)),
5334                 );
5335             }
5336 
5337             let one_color = [1.0, 1.0, 1.0, 1.0];
5338             for &task_id in &target.one_clears {
5339                 let (rect, _) = render_tasks[task_id].get_target_rect();
5340                 self.device.clear_target(
5341                     Some(one_color),
5342                     None,
5343                     Some(draw_target.to_framebuffer_rect(rect)),
5344                 );
5345             }
5346         }
5347 
5348         // Draw any blurs for this target.
5349         // Blurs are rendered as a standard 2-pass
5350         // separable implementation.
5351         // TODO(gw): In the future, consider having
5352         //           fast path blur shaders for common
5353         //           blur radii with fixed weights.
5354         if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
5355             let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
5356 
5357             self.shaders.borrow_mut().cs_blur_a8
5358                 .bind(&mut self.device, projection, &mut self.renderer_errors);
5359 
5360             if !target.vertical_blurs.is_empty() {
5361                 self.draw_instanced_batch(
5362                     &target.vertical_blurs,
5363                     VertexArrayKind::Blur,
5364                     &BatchTextures::no_texture(),
5365                     stats,
5366                 );
5367             }
5368 
5369             if !target.horizontal_blurs.is_empty() {
5370                 self.draw_instanced_batch(
5371                     &target.horizontal_blurs,
5372                     VertexArrayKind::Blur,
5373                     &BatchTextures::no_texture(),
5374                     stats,
5375                 );
5376             }
5377         }
5378 
5379         self.handle_scaling(
5380             &target.scalings,
5381             projection,
5382             stats,
5383         );
5384 
5385         // Draw the clip items into the tiled alpha mask.
5386         {
5387             let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_CLIP);
5388 
5389             // TODO(gw): Consider grouping multiple clip masks per shader
5390             //           invocation here to reduce memory bandwith further?
5391 
5392             // Draw the primary clip mask - since this is the first mask
5393             // for the task, we can disable blending, knowing that it will
5394             // overwrite every pixel in the mask area.
5395             self.set_blend(false, FramebufferKind::Other);
5396             self.draw_clip_batch_list(
5397                 &target.clip_batcher.primary_clips,
5398                 projection,
5399                 stats,
5400             );
5401 
5402             // switch to multiplicative blending for secondary masks, using
5403             // multiplicative blending to accumulate clips into the mask.
5404             self.set_blend(true, FramebufferKind::Other);
5405             self.set_blend_mode_multiply(FramebufferKind::Other);
5406             self.draw_clip_batch_list(
5407                 &target.clip_batcher.secondary_clips,
5408                 projection,
5409                 stats,
5410             );
5411         }
5412 
5413         self.gpu_profile.finish_sampler(alpha_sampler);
5414     }
5415 
draw_texture_cache_target( &mut self, texture: &CacheTextureId, layer: LayerIndex, target: &TextureCacheRenderTarget, render_tasks: &RenderTaskGraph, stats: &mut RendererStats, )5416     fn draw_texture_cache_target(
5417         &mut self,
5418         texture: &CacheTextureId,
5419         layer: LayerIndex,
5420         target: &TextureCacheRenderTarget,
5421         render_tasks: &RenderTaskGraph,
5422         stats: &mut RendererStats,
5423     ) {
5424         profile_scope!("draw_texture_cache_target");
5425 
5426         let texture_source = TextureSource::TextureCache(*texture, Swizzle::default());
5427         let projection = {
5428             let (texture, _) = self.texture_resolver
5429                 .resolve(&texture_source)
5430                 .expect("BUG: invalid target texture");
5431             let target_size = texture.get_dimensions();
5432 
5433             Transform3D::ortho(
5434                 0.0,
5435                 target_size.width as f32,
5436                 0.0,
5437                 target_size.height as f32,
5438                 self.device.ortho_near_plane(),
5439                 self.device.ortho_far_plane(),
5440             )
5441         };
5442 
5443         self.device.disable_depth();
5444         self.device.disable_depth_write();
5445 
5446         self.set_blend(false, FramebufferKind::Other);
5447 
5448         {
5449             let (texture, _) = self.texture_resolver
5450                 .resolve(&texture_source)
5451                 .expect("BUG: invalid target texture");
5452             let draw_target = DrawTarget::from_texture(
5453                 texture,
5454                 layer,
5455                 false,
5456             );
5457             self.device.bind_draw_target(draw_target);
5458 
5459             self.device.disable_depth();
5460             self.device.disable_depth_write();
5461             self.set_blend(false, FramebufferKind::Other);
5462 
5463             for rect in &target.clears {
5464                 self.device.clear_target(
5465                     Some([0.0, 0.0, 0.0, 0.0]),
5466                     None,
5467                     Some(draw_target.to_framebuffer_rect(*rect)),
5468                 );
5469             }
5470 
5471             // Handle any blits to this texture from child tasks.
5472             self.handle_blits(
5473                 &target.blits, render_tasks, draw_target, &DeviceIntPoint::zero(),
5474             );
5475         }
5476 
5477         // Draw any borders for this target.
5478         if !target.border_segments_solid.is_empty() ||
5479            !target.border_segments_complex.is_empty()
5480         {
5481             let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_BORDER);
5482 
5483             self.set_blend(true, FramebufferKind::Other);
5484             self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
5485 
5486             if !target.border_segments_solid.is_empty() {
5487                 self.shaders.borrow_mut().cs_border_solid.bind(
5488                     &mut self.device,
5489                     &projection,
5490                     &mut self.renderer_errors,
5491                 );
5492 
5493                 self.draw_instanced_batch(
5494                     &target.border_segments_solid,
5495                     VertexArrayKind::Border,
5496                     &BatchTextures::no_texture(),
5497                     stats,
5498                 );
5499             }
5500 
5501             if !target.border_segments_complex.is_empty() {
5502                 self.shaders.borrow_mut().cs_border_segment.bind(
5503                     &mut self.device,
5504                     &projection,
5505                     &mut self.renderer_errors,
5506                 );
5507 
5508                 self.draw_instanced_batch(
5509                     &target.border_segments_complex,
5510                     VertexArrayKind::Border,
5511                     &BatchTextures::no_texture(),
5512                     stats,
5513                 );
5514             }
5515 
5516             self.set_blend(false, FramebufferKind::Other);
5517         }
5518 
5519         // Draw any line decorations for this target.
5520         if !target.line_decorations.is_empty() {
5521             let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_LINE_DECORATION);
5522 
5523             self.set_blend(true, FramebufferKind::Other);
5524             self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
5525 
5526             self.shaders.borrow_mut().cs_line_decoration.bind(
5527                 &mut self.device,
5528                 &projection,
5529                 &mut self.renderer_errors,
5530             );
5531 
5532             self.draw_instanced_batch(
5533                 &target.line_decorations,
5534                 VertexArrayKind::LineDecoration,
5535                 &BatchTextures::no_texture(),
5536                 stats,
5537             );
5538 
5539             self.set_blend(false, FramebufferKind::Other);
5540         }
5541 
5542         // Draw any gradients for this target.
5543         if !target.gradients.is_empty() {
5544             let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_GRADIENT);
5545 
5546             self.set_blend(false, FramebufferKind::Other);
5547 
5548             self.shaders.borrow_mut().cs_gradient.bind(
5549                 &mut self.device,
5550                 &projection,
5551                 &mut self.renderer_errors,
5552             );
5553 
5554             self.draw_instanced_batch(
5555                 &target.gradients,
5556                 VertexArrayKind::Gradient,
5557                 &BatchTextures::no_texture(),
5558                 stats,
5559             );
5560         }
5561 
5562         // Draw any blurs for this target.
5563         if !target.horizontal_blurs.is_empty() {
5564             let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
5565 
5566             {
5567                 let mut shaders = self.shaders.borrow_mut();
5568                 match target.target_kind {
5569                     RenderTargetKind::Alpha => &mut shaders.cs_blur_a8,
5570                     RenderTargetKind::Color => &mut shaders.cs_blur_rgba8,
5571                 }.bind(&mut self.device, &projection, &mut self.renderer_errors);
5572             }
5573 
5574             self.draw_instanced_batch(
5575                 &target.horizontal_blurs,
5576                 VertexArrayKind::Blur,
5577                 &BatchTextures::no_texture(),
5578                 stats,
5579             );
5580         }
5581     }
5582 
update_deferred_resolves(&mut self, deferred_resolves: &[DeferredResolve]) -> Option<GpuCacheUpdateList>5583     fn update_deferred_resolves(&mut self, deferred_resolves: &[DeferredResolve]) -> Option<GpuCacheUpdateList> {
5584         // The first thing we do is run through any pending deferred
5585         // resolves, and use a callback to get the UV rect for this
5586         // custom item. Then we patch the resource_rects structure
5587         // here before it's uploaded to the GPU.
5588         if deferred_resolves.is_empty() {
5589             return None;
5590         }
5591 
5592         let handler = self.external_image_handler
5593             .as_mut()
5594             .expect("Found external image, but no handler set!");
5595 
5596         let mut list = GpuCacheUpdateList {
5597             frame_id: FrameId::INVALID,
5598             clear: false,
5599             height: self.gpu_cache_texture.get_height(),
5600             blocks: Vec::new(),
5601             updates: Vec::new(),
5602             debug_commands: Vec::new(),
5603         };
5604 
5605         for deferred_resolve in deferred_resolves {
5606             self.gpu_profile.place_marker("deferred resolve");
5607             let props = &deferred_resolve.image_properties;
5608             let ext_image = props
5609                 .external_image
5610                 .expect("BUG: Deferred resolves must be external images!");
5611             // Provide rendering information for NativeTexture external images.
5612             let image = handler.lock(ext_image.id, ext_image.channel_index, deferred_resolve.rendering);
5613             let texture_target = match ext_image.image_type {
5614                 ExternalImageType::TextureHandle(target) => target,
5615                 ExternalImageType::Buffer => {
5616                     panic!("not a suitable image type in update_deferred_resolves()");
5617                 }
5618             };
5619 
5620             // In order to produce the handle, the external image handler may call into
5621             // the GL context and change some states.
5622             self.device.reset_state();
5623 
5624             let texture = match image.source {
5625                 ExternalImageSource::NativeTexture(texture_id) => {
5626                     ExternalTexture::new(
5627                         texture_id,
5628                         texture_target,
5629                         Swizzle::default(),
5630                         image.uv,
5631                     )
5632                 }
5633                 ExternalImageSource::Invalid => {
5634                     warn!("Invalid ext-image");
5635                     debug!(
5636                         "For ext_id:{:?}, channel:{}.",
5637                         ext_image.id,
5638                         ext_image.channel_index
5639                     );
5640                     // Just use 0 as the gl handle for this failed case.
5641                     ExternalTexture::new(
5642                         0,
5643                         texture_target,
5644                         Swizzle::default(),
5645                         image.uv,
5646                     )
5647                 }
5648                 ExternalImageSource::RawData(_) => {
5649                     panic!("Raw external data is not expected for deferred resolves!");
5650                 }
5651             };
5652 
5653             self.texture_resolver
5654                 .external_images
5655                 .insert((ext_image.id, ext_image.channel_index), texture);
5656 
5657             list.updates.push(GpuCacheUpdate::Copy {
5658                 block_index: list.blocks.len(),
5659                 block_count: BLOCKS_PER_UV_RECT,
5660                 address: deferred_resolve.address,
5661             });
5662             list.blocks.push(image.uv.into());
5663             list.blocks.push([0f32; 4].into());
5664         }
5665 
5666         Some(list)
5667     }
5668 
unlock_external_images(&mut self)5669     fn unlock_external_images(&mut self) {
5670         if !self.texture_resolver.external_images.is_empty() {
5671             let handler = self.external_image_handler
5672                 .as_mut()
5673                 .expect("Found external image, but no handler set!");
5674 
5675             for (ext_data, _) in self.texture_resolver.external_images.drain() {
5676                 handler.unlock(ext_data.0, ext_data.1);
5677             }
5678         }
5679     }
5680 
5681     /// Allocates a texture to be used as the output for a rendering pass.
5682     ///
5683     /// We make an effort to reuse render targe textures across passes and
5684     /// across frames when the format and dimensions match. Because we use
5685     /// immutable storage, we can't resize textures.
5686     ///
5687     /// We could consider approaches to re-use part of a larger target, if
5688     /// available. However, we'd need to be careful about eviction. Currently,
5689     /// render targets are freed if they haven't been used in 30 frames. If we
5690     /// used partial targets, we'd need to track how _much_ of the target has
5691     /// been used in the last 30 frames, since we could otherwise end up
5692     /// keeping an enormous target alive indefinitely by constantly using it
5693     /// in situations where a much smaller target would suffice.
allocate_target_texture<T: RenderTarget>( &mut self, list: &mut RenderTargetList<T>, counters: &mut FrameProfileCounters, ) -> Option<ActiveTexture>5694     fn allocate_target_texture<T: RenderTarget>(
5695         &mut self,
5696         list: &mut RenderTargetList<T>,
5697         counters: &mut FrameProfileCounters,
5698     ) -> Option<ActiveTexture> {
5699         if list.targets.is_empty() {
5700             return None
5701         }
5702 
5703         // Get a bounding rect of all the layers, and round it up to a multiple
5704         // of 256. This improves render target reuse when resizing the window,
5705         // since we don't need to create a new render target for each slightly-
5706         // larger frame.
5707         let mut bounding_rect = DeviceIntRect::zero();
5708         for t in list.targets.iter() {
5709             bounding_rect = t.used_rect().union(&bounding_rect);
5710         }
5711         debug_assert_eq!(bounding_rect.origin, DeviceIntPoint::zero());
5712         let dimensions = DeviceIntSize::new(
5713             (bounding_rect.size.width + 255) & !255,
5714             (bounding_rect.size.height + 255) & !255,
5715         );
5716 
5717         counters.targets_used.inc();
5718 
5719         // Try finding a match in the existing pool. If there's no match, we'll
5720         // create a new texture.
5721         let selector = TargetSelector {
5722             size: dimensions,
5723             num_layers: list.targets.len(),
5724             format: list.format,
5725         };
5726         let index = self.texture_resolver.render_target_pool
5727             .iter()
5728             .position(|texture| {
5729                 selector == TargetSelector {
5730                     size: texture.get_dimensions(),
5731                     num_layers: texture.get_layer_count() as usize,
5732                     format: texture.get_format(),
5733                 }
5734             });
5735 
5736         let rt_info = RenderTargetInfo { has_depth: list.needs_depth() };
5737         let texture = if let Some(idx) = index {
5738             let mut t = self.texture_resolver.render_target_pool.swap_remove(idx);
5739             self.device.reuse_render_target::<u8>(&mut t, rt_info);
5740             t
5741         } else {
5742             counters.targets_created.inc();
5743             self.device.create_texture(
5744                 TextureTarget::Array,
5745                 list.format,
5746                 dimensions.width,
5747                 dimensions.height,
5748                 TextureFilter::Linear,
5749                 Some(rt_info),
5750                 list.targets.len() as _,
5751             )
5752         };
5753 
5754         list.check_ready(&texture);
5755         Some(ActiveTexture {
5756             texture,
5757             saved_index: list.saved_index.clone(),
5758         })
5759     }
5760 
bind_frame_data(&mut self, frame: &mut Frame)5761     fn bind_frame_data(&mut self, frame: &mut Frame) {
5762         profile_scope!("bind_frame_data");
5763 
5764         let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
5765 
5766         self.vertex_data_textures[self.current_vertex_data_textures].update(
5767             &mut self.device,
5768             frame,
5769         );
5770         self.current_vertex_data_textures =
5771             (self.current_vertex_data_textures + 1) % VERTEX_DATA_TEXTURE_COUNT;
5772 
5773         debug_assert!(self.texture_resolver.prev_pass_alpha.is_none());
5774         debug_assert!(self.texture_resolver.prev_pass_color.is_none());
5775     }
5776 
update_native_surfaces(&mut self)5777     fn update_native_surfaces(&mut self) {
5778         profile_scope!("update_native_surfaces");
5779 
5780         match self.compositor_config {
5781             CompositorConfig::Native { ref mut compositor, .. } => {
5782                 for op in self.pending_native_surface_updates.drain(..) {
5783                     match op.details {
5784                         NativeSurfaceOperationDetails::CreateSurface { id, virtual_offset, tile_size, is_opaque } => {
5785                             let _inserted = self.allocated_native_surfaces.insert(id);
5786                             debug_assert!(_inserted, "bug: creating existing surface");
5787                             compositor.create_surface(
5788                                 id,
5789                                 virtual_offset,
5790                                 tile_size,
5791                                 is_opaque,
5792                             );
5793                         }
5794                         NativeSurfaceOperationDetails::DestroySurface { id } => {
5795                             let _existed = self.allocated_native_surfaces.remove(&id);
5796                             debug_assert!(_existed, "bug: removing unknown surface");
5797                             compositor.destroy_surface(id);
5798                         }
5799                         NativeSurfaceOperationDetails::CreateTile { id } => {
5800                             compositor.create_tile(id);
5801                         }
5802                         NativeSurfaceOperationDetails::DestroyTile { id } => {
5803                             compositor.destroy_tile(id);
5804                         }
5805                     }
5806                 }
5807             }
5808             CompositorConfig::Draw { .. } => {
5809                 // Ensure nothing is added in simple composite mode, since otherwise
5810                 // memory will leak as this doesn't get drained
5811                 debug_assert!(self.pending_native_surface_updates.is_empty());
5812             }
5813         }
5814     }
5815 
draw_frame( &mut self, frame: &mut Frame, device_size: Option<DeviceIntSize>, frame_id: GpuFrameId, results: &mut RenderResults, clear_framebuffer: bool, )5816     fn draw_frame(
5817         &mut self,
5818         frame: &mut Frame,
5819         device_size: Option<DeviceIntSize>,
5820         frame_id: GpuFrameId,
5821         results: &mut RenderResults,
5822         clear_framebuffer: bool,
5823     ) {
5824         profile_scope!("draw_frame");
5825 
5826         // These markers seem to crash a lot on Android, see bug 1559834
5827         #[cfg(not(target_os = "android"))]
5828         let _gm = self.gpu_profile.start_marker("draw frame");
5829 
5830         if frame.passes.is_empty() {
5831             frame.has_been_rendered = true;
5832             return;
5833         }
5834 
5835         self.device.disable_depth_write();
5836         self.set_blend(false, FramebufferKind::Other);
5837         self.device.disable_stencil();
5838 
5839         self.bind_frame_data(frame);
5840 
5841         for (_pass_index, pass) in frame.passes.iter_mut().enumerate() {
5842             #[cfg(not(target_os = "android"))]
5843             let _gm = self.gpu_profile.start_marker(&format!("pass {}", _pass_index));
5844 
5845             self.texture_resolver.bind(
5846                 &TextureSource::PrevPassAlpha,
5847                 TextureSampler::PrevPassAlpha,
5848                 &mut self.device,
5849             );
5850             self.texture_resolver.bind(
5851                 &TextureSource::PrevPassColor,
5852                 TextureSampler::PrevPassColor,
5853                 &mut self.device,
5854             );
5855 
5856             match pass.kind {
5857                 RenderPassKind::MainFramebuffer { ref main_target, .. } => {
5858                     profile_scope!("main target");
5859 
5860                     if let Some(device_size) = device_size {
5861                         results.stats.color_target_count += 1;
5862 
5863                         let offset = frame.content_origin.to_f32();
5864                         let size = frame.device_rect.size.to_f32();
5865                         let surface_origin_is_top_left = self.device.surface_origin_is_top_left();
5866                         let (bottom, top) = if surface_origin_is_top_left {
5867                           (offset.y, offset.y + size.height)
5868                         } else {
5869                           (offset.y + size.height, offset.y)
5870                         };
5871 
5872                         let projection = Transform3D::ortho(
5873                             offset.x,
5874                             offset.x + size.width,
5875                             bottom,
5876                             top,
5877                             self.device.ortho_near_plane(),
5878                             self.device.ortho_far_plane(),
5879                         );
5880 
5881                         let fb_scale = Scale::<_, _, FramebufferPixel>::new(1i32);
5882                         let mut fb_rect = frame.device_rect * fb_scale;
5883 
5884                         if !surface_origin_is_top_left {
5885                             fb_rect.origin.y = device_size.height - fb_rect.origin.y - fb_rect.size.height;
5886                         }
5887 
5888                         let draw_target = DrawTarget::Default {
5889                             rect: fb_rect,
5890                             total_size: device_size * fb_scale,
5891                             surface_origin_is_top_left,
5892                         };
5893 
5894                         // Picture caching can be enabled / disabled dynamically from frame to
5895                         // frame. This is determined by what the frame builder selected, and is
5896                         // passed to the renderer via the composite state.
5897                         if frame.composite_state.picture_caching_is_enabled {
5898                             // If we have a native OS compositor, then make use of that interface
5899                             // to specify how to composite each of the picture cache surfaces.
5900                             match self.current_compositor_kind {
5901                                 CompositorKind::Native { .. } => {
5902                                     self.update_external_native_surfaces(
5903                                         &frame.composite_state.external_surfaces,
5904                                         results,
5905                                     );
5906                                     let compositor = self.compositor_config.compositor().unwrap();
5907                                     frame.composite_state.composite_native(&mut **compositor);
5908                                 }
5909                                 CompositorKind::Draw { max_partial_present_rects, draw_previous_partial_present_regions, .. } => {
5910                                     self.composite_simple(
5911                                         &frame.composite_state,
5912                                         clear_framebuffer,
5913                                         draw_target,
5914                                         &projection,
5915                                         results,
5916                                         max_partial_present_rects,
5917                                         draw_previous_partial_present_regions,
5918                                     );
5919                                 }
5920                             }
5921                         } else {
5922                             if clear_framebuffer {
5923                                 let clear_color = self.clear_color.map(|color| color.to_array());
5924                                 self.device.bind_draw_target(draw_target);
5925                                 self.device.enable_depth_write();
5926                                 self.device.clear_target(clear_color,
5927                                                          Some(1.0),
5928                                                          None);
5929                             }
5930 
5931                             // If picture caching is disabled, we will be drawing the entire
5932                             // framebuffer. In that case, we need to push a screen size dirty
5933                             // rect, in case partial present is enabled (an empty array of
5934                             // dirty rects when partial present is enabled is interpreted by
5935                             // Gecko as meaning nothing has changed and a swap is not required).
5936                             results.dirty_rects.push(frame.device_rect);
5937 
5938                             self.draw_color_target(
5939                                 draw_target,
5940                                 main_target,
5941                                 frame.content_origin,
5942                                 None,
5943                                 None,
5944                                 &frame.render_tasks,
5945                                 &projection,
5946                                 frame_id,
5947                                 &mut results.stats,
5948                             );
5949                         }
5950                     }
5951                 }
5952                 RenderPassKind::OffScreen {
5953                     ref mut alpha,
5954                     ref mut color,
5955                     ref mut texture_cache,
5956                     ref mut picture_cache,
5957                 } => {
5958                     profile_scope!("offscreen target");
5959 
5960                     let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters);
5961                     let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters);
5962 
5963                     // If this frame has already been drawn, then any texture
5964                     // cache targets have already been updated and can be
5965                     // skipped this time.
5966                     if !frame.has_been_rendered {
5967                         for (&(texture_id, target_index), target) in texture_cache {
5968                             self.draw_texture_cache_target(
5969                                 &texture_id,
5970                                 target_index,
5971                                 target,
5972                                 &frame.render_tasks,
5973                                 &mut results.stats,
5974                             );
5975                         }
5976 
5977                         if !picture_cache.is_empty() {
5978                             self.profile_counters.color_passes.inc();
5979                         }
5980 
5981                         // Draw picture caching tiles for this pass.
5982                         for picture_target in picture_cache {
5983                             results.stats.color_target_count += 1;
5984 
5985                             let draw_target = match picture_target.surface {
5986                                 ResolvedSurfaceTexture::TextureCache { ref texture, layer } => {
5987                                     let (texture, _) = self.texture_resolver
5988                                         .resolve(texture)
5989                                         .expect("bug");
5990 
5991                                     DrawTarget::from_texture(
5992                                         texture,
5993                                         layer as usize,
5994                                         true,
5995                                     )
5996                                 }
5997                                 ResolvedSurfaceTexture::Native { id, size } => {
5998                                     let surface_info = match self.current_compositor_kind {
5999                                         CompositorKind::Native { .. } => {
6000                                             let compositor = self.compositor_config.compositor().unwrap();
6001                                             compositor.bind(
6002                                                 id,
6003                                                 picture_target.dirty_rect,
6004                                                 picture_target.valid_rect,
6005                                             )
6006                                         }
6007                                         CompositorKind::Draw { .. } => {
6008                                             unreachable!();
6009                                         }
6010                                     };
6011 
6012                                     DrawTarget::NativeSurface {
6013                                         offset: surface_info.origin,
6014                                         external_fbo_id: surface_info.fbo_id,
6015                                         dimensions: size,
6016                                     }
6017                                 }
6018                             };
6019 
6020                             let projection = Transform3D::ortho(
6021                                 0.0,
6022                                 draw_target.dimensions().width as f32,
6023                                 0.0,
6024                                 draw_target.dimensions().height as f32,
6025                                 self.device.ortho_near_plane(),
6026                                 self.device.ortho_far_plane(),
6027                             );
6028 
6029                             self.draw_picture_cache_target(
6030                                 picture_target,
6031                                 draw_target,
6032                                 frame.content_origin,
6033                                 &projection,
6034                                 &frame.render_tasks,
6035                                 &mut results.stats,
6036                             );
6037 
6038                             // Native OS surfaces must be unbound at the end of drawing to them
6039                             if let ResolvedSurfaceTexture::Native { .. } = picture_target.surface {
6040                                 match self.current_compositor_kind {
6041                                     CompositorKind::Native { .. } => {
6042                                         let compositor = self.compositor_config.compositor().unwrap();
6043                                         compositor.unbind();
6044                                     }
6045                                     CompositorKind::Draw { .. } => {
6046                                         unreachable!();
6047                                     }
6048                                 }
6049                             }
6050                         }
6051                     }
6052 
6053                     for (target_index, target) in alpha.targets.iter().enumerate() {
6054                         results.stats.alpha_target_count += 1;
6055                         let draw_target = DrawTarget::from_texture(
6056                             &alpha_tex.as_ref().unwrap().texture,
6057                             target_index,
6058                             false,
6059                         );
6060 
6061                         let projection = Transform3D::ortho(
6062                             0.0,
6063                             draw_target.dimensions().width as f32,
6064                             0.0,
6065                             draw_target.dimensions().height as f32,
6066                             self.device.ortho_near_plane(),
6067                             self.device.ortho_far_plane(),
6068                         );
6069 
6070                         self.draw_alpha_target(
6071                             draw_target,
6072                             target,
6073                             &projection,
6074                             &frame.render_tasks,
6075                             &mut results.stats,
6076                         );
6077                     }
6078 
6079                     for (target_index, target) in color.targets.iter().enumerate() {
6080                         results.stats.color_target_count += 1;
6081                         let draw_target = DrawTarget::from_texture(
6082                             &color_tex.as_ref().unwrap().texture,
6083                             target_index,
6084                             target.needs_depth(),
6085                         );
6086 
6087                         let projection = Transform3D::ortho(
6088                             0.0,
6089                             draw_target.dimensions().width as f32,
6090                             0.0,
6091                             draw_target.dimensions().height as f32,
6092                             self.device.ortho_near_plane(),
6093                             self.device.ortho_far_plane(),
6094                         );
6095 
6096                         let clear_depth = if target.needs_depth() {
6097                             Some(1.0)
6098                         } else {
6099                             None
6100                         };
6101 
6102                         self.draw_color_target(
6103                             draw_target,
6104                             target,
6105                             frame.content_origin,
6106                             Some([0.0, 0.0, 0.0, 0.0]),
6107                             clear_depth,
6108                             &frame.render_tasks,
6109                             &projection,
6110                             frame_id,
6111                             &mut results.stats,
6112                         );
6113                     }
6114 
6115                     // Only end the pass here and invalidate previous textures for
6116                     // off-screen targets. Deferring return of the inputs to the
6117                     // frame buffer until the implicit end_pass in end_frame allows
6118                     // debug draw overlays to be added without triggering a copy
6119                     // resolve stage in mobile / tiled GPUs.
6120                     self.texture_resolver.end_pass(
6121                         &mut self.device,
6122                         alpha_tex,
6123                         color_tex,
6124                     );
6125                 }
6126             }
6127             {
6128                 profile_scope!("gl.flush");
6129                 self.device.gl().flush();
6130             }
6131         }
6132 
6133         if let Some(device_size) = device_size {
6134             self.draw_frame_debug_items(&frame.debug_items);
6135             self.draw_render_target_debug(device_size);
6136             self.draw_texture_cache_debug(device_size);
6137             self.draw_gpu_cache_debug(device_size);
6138             self.draw_zoom_debug(device_size);
6139         }
6140         self.draw_epoch_debug();
6141 
6142         // Garbage collect any frame outputs that weren't used this frame.
6143         let device = &mut self.device;
6144         self.output_targets
6145             .retain(|_, target| if target.last_access != frame_id {
6146                 device.delete_fbo(target.fbo_id);
6147                 false
6148             } else {
6149                 true
6150             });
6151 
6152         frame.has_been_rendered = true;
6153     }
6154 
6155     /// Initialize the PLS block, by reading the current framebuffer color.
init_pixel_local_storage( &mut self, task_rect: DeviceIntRect, projection: &default::Transform3D<f32>, stats: &mut RendererStats, )6156     pub fn init_pixel_local_storage(
6157         &mut self,
6158         task_rect: DeviceIntRect,
6159         projection: &default::Transform3D<f32>,
6160         stats: &mut RendererStats,
6161     ) {
6162         self.device.enable_pixel_local_storage(true);
6163 
6164         self.shaders
6165             .borrow_mut()
6166             .pls_init
6167             .as_mut()
6168             .unwrap()
6169             .bind(
6170                 &mut self.device,
6171                 projection,
6172                 &mut self.renderer_errors,
6173             );
6174 
6175         let instances = [
6176             ResolveInstanceData::new(task_rect),
6177         ];
6178 
6179         self.draw_instanced_batch(
6180             &instances,
6181             VertexArrayKind::Resolve,
6182             &BatchTextures::no_texture(),
6183             stats,
6184         );
6185     }
6186 
6187     /// Resolve the current PLS structure, writing it to a fragment color output.
resolve_pixel_local_storage( &mut self, task_rect: DeviceIntRect, projection: &default::Transform3D<f32>, stats: &mut RendererStats, )6188     pub fn resolve_pixel_local_storage(
6189         &mut self,
6190         task_rect: DeviceIntRect,
6191         projection: &default::Transform3D<f32>,
6192         stats: &mut RendererStats,
6193     ) {
6194         self.shaders
6195             .borrow_mut()
6196             .pls_resolve
6197             .as_mut()
6198             .unwrap()
6199             .bind(
6200                 &mut self.device,
6201                 projection,
6202                 &mut self.renderer_errors,
6203             );
6204 
6205         let instances = [
6206             ResolveInstanceData::new(task_rect),
6207         ];
6208 
6209         self.draw_instanced_batch(
6210             &instances,
6211             VertexArrayKind::Resolve,
6212             &BatchTextures::no_texture(),
6213             stats,
6214         );
6215 
6216         self.device.enable_pixel_local_storage(false);
6217     }
6218 
debug_renderer(&mut self) -> Option<&mut DebugRenderer>6219     pub fn debug_renderer(&mut self) -> Option<&mut DebugRenderer> {
6220         self.debug.get_mut(&mut self.device)
6221     }
6222 
get_debug_flags(&self) -> DebugFlags6223     pub fn get_debug_flags(&self) -> DebugFlags {
6224         self.debug_flags
6225     }
6226 
set_debug_flags(&mut self, flags: DebugFlags)6227     pub fn set_debug_flags(&mut self, flags: DebugFlags) {
6228         if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_TIME_QUERIES) {
6229             if enabled {
6230                 self.gpu_profile.enable_timers();
6231             } else {
6232                 self.gpu_profile.disable_timers();
6233             }
6234         }
6235         if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_SAMPLE_QUERIES) {
6236             if enabled {
6237                 self.gpu_profile.enable_samplers();
6238             } else {
6239                 self.gpu_profile.disable_samplers();
6240             }
6241         }
6242 
6243         self.debug_flags = flags;
6244     }
6245 
draw_frame_debug_items(&mut self, items: &[DebugItem])6246     fn draw_frame_debug_items(&mut self, items: &[DebugItem]) {
6247         if items.is_empty() {
6248             return;
6249         }
6250 
6251         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6252             Some(render) => render,
6253             None => return,
6254         };
6255 
6256         for item in items {
6257             match item {
6258                 DebugItem::Rect { rect, outer_color, inner_color } => {
6259                     debug_renderer.add_quad(
6260                         rect.origin.x,
6261                         rect.origin.y,
6262                         rect.origin.x + rect.size.width,
6263                         rect.origin.y + rect.size.height,
6264                         (*inner_color).into(),
6265                         (*inner_color).into(),
6266                     );
6267 
6268                     debug_renderer.add_rect(
6269                         &rect.to_i32(),
6270                         (*outer_color).into(),
6271                     );
6272                 }
6273                 DebugItem::Text { ref msg, position, color } => {
6274                     debug_renderer.add_text(
6275                         position.x,
6276                         position.y,
6277                         msg,
6278                         (*color).into(),
6279                         None,
6280                     );
6281                 }
6282             }
6283         }
6284     }
6285 
draw_render_target_debug(&mut self, device_size: DeviceIntSize)6286     fn draw_render_target_debug(&mut self, device_size: DeviceIntSize) {
6287         if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
6288             return;
6289         }
6290 
6291         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6292             Some(render) => render,
6293             None => return,
6294         };
6295 
6296         let textures =
6297             self.texture_resolver.render_target_pool.iter().collect::<Vec<&Texture>>();
6298 
6299         Self::do_debug_blit(
6300             &mut self.device,
6301             debug_renderer,
6302             textures,
6303             device_size,
6304             0,
6305             &|_| [0.0, 1.0, 0.0, 1.0], // Use green for all RTs.
6306         );
6307     }
6308 
draw_zoom_debug( &mut self, device_size: DeviceIntSize, )6309     fn draw_zoom_debug(
6310         &mut self,
6311         device_size: DeviceIntSize,
6312     ) {
6313         if !self.debug_flags.contains(DebugFlags::ZOOM_DBG) {
6314             return;
6315         }
6316 
6317         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6318             Some(render) => render,
6319             None => return,
6320         };
6321 
6322         let source_size = DeviceIntSize::new(64, 64);
6323         let target_size = DeviceIntSize::new(1024, 1024);
6324 
6325         let source_origin = DeviceIntPoint::new(
6326             (self.cursor_position.x - source_size.width / 2)
6327                 .min(device_size.width - source_size.width)
6328                 .max(0),
6329             (self.cursor_position.y - source_size.height / 2)
6330                 .min(device_size.height - source_size.height)
6331                 .max(0),
6332         );
6333 
6334         let source_rect = DeviceIntRect::new(
6335             source_origin,
6336             source_size,
6337         );
6338 
6339         let target_rect = DeviceIntRect::new(
6340             DeviceIntPoint::new(
6341                 device_size.width - target_size.width - 64,
6342                 device_size.height - target_size.height - 64,
6343             ),
6344             target_size,
6345         );
6346 
6347         let texture_rect = FramebufferIntRect::new(
6348             FramebufferIntPoint::zero(),
6349             source_rect.size.cast_unit(),
6350         );
6351 
6352         debug_renderer.add_rect(
6353             &target_rect.inflate(1, 1),
6354             debug_colors::RED.into(),
6355         );
6356 
6357         if self.zoom_debug_texture.is_none() {
6358             let texture = self.device.create_texture(
6359                 TextureTarget::Default,
6360                 ImageFormat::BGRA8,
6361                 source_rect.size.width,
6362                 source_rect.size.height,
6363                 TextureFilter::Nearest,
6364                 Some(RenderTargetInfo { has_depth: false }),
6365                 1,
6366             );
6367 
6368             self.zoom_debug_texture = Some(texture);
6369         }
6370 
6371         // Copy frame buffer into the zoom texture
6372         let read_target = DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left());
6373         self.device.blit_render_target(
6374             read_target.into(),
6375             read_target.to_framebuffer_rect(source_rect),
6376             DrawTarget::from_texture(
6377                 self.zoom_debug_texture.as_ref().unwrap(),
6378                 0,
6379                 false,
6380             ),
6381             texture_rect,
6382             TextureFilter::Nearest,
6383         );
6384 
6385         // Draw the zoom texture back to the framebuffer
6386         self.device.blit_render_target(
6387             ReadTarget::from_texture(
6388                 self.zoom_debug_texture.as_ref().unwrap(),
6389                 0,
6390             ),
6391             texture_rect,
6392             read_target,
6393             read_target.to_framebuffer_rect(target_rect),
6394             TextureFilter::Nearest,
6395         );
6396     }
6397 
draw_texture_cache_debug(&mut self, device_size: DeviceIntSize)6398     fn draw_texture_cache_debug(&mut self, device_size: DeviceIntSize) {
6399         if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
6400             return;
6401         }
6402 
6403         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6404             Some(render) => render,
6405             None => return,
6406         };
6407 
6408         let textures =
6409             self.texture_resolver.texture_cache_map.values().collect::<Vec<&Texture>>();
6410 
6411         fn select_color(texture: &Texture) -> [f32; 4] {
6412             if texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE) {
6413                 [1.0, 0.5, 0.0, 1.0] // Orange for shared.
6414             } else {
6415                 [1.0, 0.0, 1.0, 1.0] // Fuchsia for standalone.
6416             }
6417         }
6418 
6419         Self::do_debug_blit(
6420             &mut self.device,
6421             debug_renderer,
6422             textures,
6423             device_size,
6424             if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) { 544 } else { 0 },
6425             &select_color,
6426         );
6427     }
6428 
do_debug_blit( device: &mut Device, debug_renderer: &mut DebugRenderer, mut textures: Vec<&Texture>, device_size: DeviceIntSize, bottom: i32, select_color: &dyn Fn(&Texture) -> [f32; 4], )6429     fn do_debug_blit(
6430         device: &mut Device,
6431         debug_renderer: &mut DebugRenderer,
6432         mut textures: Vec<&Texture>,
6433         device_size: DeviceIntSize,
6434         bottom: i32,
6435         select_color: &dyn Fn(&Texture) -> [f32; 4],
6436     ) {
6437         let mut spacing = 16;
6438         let mut size = 512;
6439 
6440         let fb_width = device_size.width;
6441         let fb_height = device_size.height;
6442         let num_layers: i32 = textures.iter()
6443             .map(|texture| texture.get_layer_count())
6444             .sum();
6445 
6446         if num_layers * (size + spacing) > fb_width {
6447             let factor = fb_width as f32 / (num_layers * (size + spacing)) as f32;
6448             size = (size as f32 * factor) as i32;
6449             spacing = (spacing as f32 * factor) as i32;
6450         }
6451 
6452         // Sort the display by layer size (in bytes), so that left-to-right is
6453         // largest-to-smallest.
6454         //
6455         // Note that the vec here is in increasing order, because the elements
6456         // get drawn right-to-left.
6457         textures.sort_by_key(|t| t.layer_size_in_bytes());
6458 
6459         let mut i = 0;
6460         for texture in textures.iter() {
6461             let y = spacing + bottom;
6462             let dimensions = texture.get_dimensions();
6463             let src_rect = FramebufferIntRect::new(
6464                 FramebufferIntPoint::zero(),
6465                 FramebufferIntSize::new(dimensions.width as i32, dimensions.height as i32),
6466             );
6467 
6468             let layer_count = texture.get_layer_count() as usize;
6469             for layer in 0 .. layer_count {
6470                 let x = fb_width - (spacing + size) * (i as i32 + 1);
6471 
6472                 // If we have more targets than fit on one row in screen, just early exit.
6473                 if x > fb_width {
6474                     return;
6475                 }
6476 
6477                 //TODO: properly use FramebufferPixel coordinates
6478 
6479                 // Draw the info tag.
6480                 let text_margin = 1;
6481                 let text_height = 14; // Visually aproximated.
6482                 let tag_height = text_height + text_margin * 2;
6483                 let tag_rect = rect(x, y, size, tag_height);
6484                 let tag_color = select_color(texture);
6485                 device.clear_target(
6486                     Some(tag_color),
6487                     None,
6488                     Some(tag_rect.cast_unit()),
6489                 );
6490 
6491                 // Draw the dimensions onto the tag.
6492                 let dim = texture.get_dimensions();
6493                 let mut text_rect = tag_rect;
6494                 text_rect.origin.y =
6495                     fb_height - text_rect.origin.y - text_rect.size.height; // Top-relative.
6496                 debug_renderer.add_text(
6497                     (x + text_margin) as f32,
6498                     (fb_height - y - text_margin) as f32, // Top-relative.
6499                     &format!("{}x{}", dim.width, dim.height),
6500                     ColorU::new(0, 0, 0, 255),
6501                     Some(text_rect.to_f32())
6502                 );
6503 
6504                 // Blit the contents of the layer. We need to invert Y because
6505                 // we're blitting from a texture to the main framebuffer, which
6506                 // use different conventions.
6507                 let dest_rect = rect(x, y + tag_height, size, size);
6508                 if !device.surface_origin_is_top_left() {
6509                     device.blit_render_target_invert_y(
6510                         ReadTarget::from_texture(texture, layer),
6511                         src_rect,
6512                         DrawTarget::new_default(device_size, device.surface_origin_is_top_left()),
6513                         FramebufferIntRect::from_untyped(&dest_rect),
6514                     );
6515                 } else {
6516                     device.blit_render_target(
6517                         ReadTarget::from_texture(texture, layer),
6518                         src_rect,
6519                         DrawTarget::new_default(device_size, device.surface_origin_is_top_left()),
6520                         FramebufferIntRect::from_untyped(&dest_rect),
6521                         TextureFilter::Linear,
6522                     );
6523                 }
6524                 i += 1;
6525             }
6526         }
6527     }
6528 
draw_epoch_debug(&mut self)6529     fn draw_epoch_debug(&mut self) {
6530         if !self.debug_flags.contains(DebugFlags::EPOCHS) {
6531             return;
6532         }
6533 
6534         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6535             Some(render) => render,
6536             None => return,
6537         };
6538 
6539         let dy = debug_renderer.line_height();
6540         let x0: f32 = 30.0;
6541         let y0: f32 = 30.0;
6542         let mut y = y0;
6543         let mut text_width = 0.0;
6544         for ((pipeline, document_id), epoch) in  &self.pipeline_info.epochs {
6545             y += dy;
6546             let w = debug_renderer.add_text(
6547                 x0, y,
6548                 &format!("({:?}, {:?}): {:?}", pipeline, document_id, epoch),
6549                 ColorU::new(255, 255, 0, 255),
6550                 None,
6551             ).size.width;
6552             text_width = f32::max(text_width, w);
6553         }
6554 
6555         let margin = 10.0;
6556         debug_renderer.add_quad(
6557             x0 - margin,
6558             y0 - margin,
6559             x0 + text_width + margin,
6560             y + margin,
6561             ColorU::new(25, 25, 25, 200),
6562             ColorU::new(51, 51, 51, 200),
6563         );
6564     }
6565 
draw_gpu_cache_debug(&mut self, device_size: DeviceIntSize)6566     fn draw_gpu_cache_debug(&mut self, device_size: DeviceIntSize) {
6567         if !self.debug_flags.contains(DebugFlags::GPU_CACHE_DBG) {
6568             return;
6569         }
6570 
6571         let debug_renderer = match self.debug.get_mut(&mut self.device) {
6572             Some(render) => render,
6573             None => return,
6574         };
6575 
6576         let (x_off, y_off) = (30f32, 30f32);
6577         let height = self.gpu_cache_texture.texture
6578             .as_ref().map_or(0, |t| t.get_dimensions().height)
6579             .min(device_size.height - (y_off as i32) * 2) as usize;
6580         debug_renderer.add_quad(
6581             x_off,
6582             y_off,
6583             x_off + MAX_VERTEX_TEXTURE_WIDTH as f32,
6584             y_off + height as f32,
6585             ColorU::new(80, 80, 80, 80),
6586             ColorU::new(80, 80, 80, 80),
6587         );
6588 
6589         let upper = self.gpu_cache_debug_chunks.len().min(height);
6590         for chunk in self.gpu_cache_debug_chunks[0..upper].iter().flatten() {
6591             let color = ColorU::new(250, 0, 0, 200);
6592             debug_renderer.add_quad(
6593                 x_off + chunk.address.u as f32,
6594                 y_off + chunk.address.v as f32,
6595                 x_off + chunk.address.u as f32 + chunk.size as f32,
6596                 y_off + chunk.address.v as f32 + 1.0,
6597                 color,
6598                 color,
6599             );
6600         }
6601     }
6602 
6603     /// Pass-through to `Device::read_pixels_into`, used by Gecko's WR bindings.
read_pixels_into(&mut self, rect: FramebufferIntRect, format: ImageFormat, output: &mut [u8])6604     pub fn read_pixels_into(&mut self, rect: FramebufferIntRect, format: ImageFormat, output: &mut [u8]) {
6605         self.device.read_pixels_into(rect, format, output);
6606     }
6607 
read_pixels_rgba8(&mut self, rect: FramebufferIntRect) -> Vec<u8>6608     pub fn read_pixels_rgba8(&mut self, rect: FramebufferIntRect) -> Vec<u8> {
6609         let mut pixels = vec![0; (rect.size.width * rect.size.height * 4) as usize];
6610         self.device.read_pixels_into(rect, ImageFormat::RGBA8, &mut pixels);
6611         pixels
6612     }
6613 
read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>)6614     pub fn read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>) {
6615         let texture = self.gpu_cache_texture.texture.as_ref().unwrap();
6616         let size = device_size_as_framebuffer_size(texture.get_dimensions());
6617         let mut texels = vec![0; (size.width * size.height * 16) as usize];
6618         self.device.begin_frame();
6619         self.device.bind_read_target(ReadTarget::from_texture(texture, 0));
6620         self.device.read_pixels_into(
6621             size.into(),
6622             ImageFormat::RGBAF32,
6623             &mut texels,
6624         );
6625         self.device.reset_read_target();
6626         self.device.end_frame();
6627         (texture.get_dimensions(), texels)
6628     }
6629 
6630     // De-initialize the Renderer safely, assuming the GL is still alive and active.
deinit(mut self)6631     pub fn deinit(mut self) {
6632         //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
6633         self.device.begin_frame();
6634         // If we are using a native compositor, ensure that any remaining native
6635         // surfaces are freed.
6636         if let CompositorConfig::Native { mut compositor, .. } = self.compositor_config {
6637             for id in self.allocated_native_surfaces.drain() {
6638                 compositor.destroy_surface(id);
6639             }
6640             // Destroy the debug overlay surface, if currently allocated.
6641             if self.debug_overlay_state.current_size.is_some() {
6642                 compositor.destroy_surface(NativeSurfaceId::DEBUG_OVERLAY);
6643             }
6644             compositor.deinit();
6645         }
6646         self.gpu_cache_texture.deinit(&mut self.device);
6647         if let Some(dither_matrix_texture) = self.dither_matrix_texture {
6648             self.device.delete_texture(dither_matrix_texture);
6649         }
6650         if let Some(zoom_debug_texture) = self.zoom_debug_texture {
6651             self.device.delete_texture(zoom_debug_texture);
6652         }
6653         for textures in self.vertex_data_textures.drain(..) {
6654             textures.deinit(&mut self.device);
6655         }
6656         self.device.delete_pbo(self.texture_cache_upload_pbo);
6657         self.texture_resolver.deinit(&mut self.device);
6658         self.device.delete_vao(self.vaos.prim_vao);
6659         self.device.delete_vao(self.vaos.resolve_vao);
6660         self.device.delete_vao(self.vaos.clip_vao);
6661         self.device.delete_vao(self.vaos.gradient_vao);
6662         self.device.delete_vao(self.vaos.blur_vao);
6663         self.device.delete_vao(self.vaos.line_vao);
6664         self.device.delete_vao(self.vaos.border_vao);
6665         self.device.delete_vao(self.vaos.scale_vao);
6666         self.device.delete_vao(self.vaos.svg_filter_vao);
6667         self.device.delete_vao(self.vaos.composite_vao);
6668 
6669         self.debug.deinit(&mut self.device);
6670 
6671         for (_, target) in self.output_targets {
6672             self.device.delete_fbo(target.fbo_id);
6673         }
6674         if let Ok(shaders) = Rc::try_unwrap(self.shaders) {
6675             shaders.into_inner().deinit(&mut self.device);
6676         }
6677 
6678         if let Some(async_screenshots) = self.async_screenshots.take() {
6679             async_screenshots.deinit(&mut self.device);
6680         }
6681 
6682         if let Some(async_frame_recorder) = self.async_frame_recorder.take() {
6683             async_frame_recorder.deinit(&mut self.device);
6684         }
6685 
6686         #[cfg(feature = "capture")]
6687         self.device.delete_fbo(self.read_fbo);
6688         #[cfg(feature = "replay")]
6689         for (_, ext) in self.owned_external_images {
6690             self.device.delete_external_texture(ext);
6691         }
6692         self.device.end_frame();
6693     }
6694 
size_of<T>(&self, ptr: *const T) -> usize6695     fn size_of<T>(&self, ptr: *const T) -> usize {
6696         let op = self.size_of_ops.as_ref().unwrap().size_of_op;
6697         unsafe { op(ptr as *const c_void) }
6698     }
6699 
6700     /// Collects a memory report.
report_memory(&self) -> MemoryReport6701     pub fn report_memory(&self) -> MemoryReport {
6702         let mut report = MemoryReport::default();
6703 
6704         // GPU cache CPU memory.
6705         if let GpuCacheBus::PixelBuffer{ref rows, ..} = self.gpu_cache_texture.bus {
6706             for row in rows.iter() {
6707                 report.gpu_cache_cpu_mirror += self.size_of(&*row.cpu_blocks as *const _);
6708             }
6709         }
6710 
6711         // GPU cache GPU memory.
6712         report.gpu_cache_textures +=
6713             self.gpu_cache_texture.texture.as_ref().map_or(0, |t| t.size_in_bytes());
6714 
6715         // Render task CPU memory.
6716         for (_id, doc) in &self.active_documents {
6717             report.render_tasks += self.size_of(doc.frame.render_tasks.tasks.as_ptr());
6718             report.render_tasks += self.size_of(doc.frame.render_tasks.task_data.as_ptr());
6719         }
6720 
6721         // Vertex data GPU memory.
6722         for textures in &self.vertex_data_textures {
6723             report.vertex_data_textures += textures.size_in_bytes();
6724         }
6725 
6726         // Texture cache and render target GPU memory.
6727         report += self.texture_resolver.report_memory();
6728 
6729         // Textures held internally within the device layer.
6730         report += self.device.report_memory();
6731 
6732         report
6733     }
6734 
6735     // Sets the blend mode. Blend is unconditionally set if the "show overdraw" debugging mode is
6736     // enabled.
set_blend(&mut self, mut blend: bool, framebuffer_kind: FramebufferKind)6737     fn set_blend(&mut self, mut blend: bool, framebuffer_kind: FramebufferKind) {
6738         if framebuffer_kind == FramebufferKind::Main &&
6739                 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6740             blend = true
6741         }
6742         self.device.set_blend(blend)
6743     }
6744 
set_blend_mode_multiply(&mut self, framebuffer_kind: FramebufferKind)6745     fn set_blend_mode_multiply(&mut self, framebuffer_kind: FramebufferKind) {
6746         if framebuffer_kind == FramebufferKind::Main &&
6747                 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6748             self.device.set_blend_mode_show_overdraw();
6749         } else {
6750             self.device.set_blend_mode_multiply();
6751         }
6752     }
6753 
set_blend_mode_premultiplied_alpha(&mut self, framebuffer_kind: FramebufferKind)6754     fn set_blend_mode_premultiplied_alpha(&mut self, framebuffer_kind: FramebufferKind) {
6755         if framebuffer_kind == FramebufferKind::Main &&
6756                 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6757             self.device.set_blend_mode_show_overdraw();
6758         } else {
6759             self.device.set_blend_mode_premultiplied_alpha();
6760         }
6761     }
6762 
set_blend_mode_subpixel_with_bg_color_pass1(&mut self, framebuffer_kind: FramebufferKind)6763     fn set_blend_mode_subpixel_with_bg_color_pass1(&mut self, framebuffer_kind: FramebufferKind) {
6764         if framebuffer_kind == FramebufferKind::Main &&
6765                 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6766             self.device.set_blend_mode_show_overdraw();
6767         } else {
6768             self.device.set_blend_mode_subpixel_with_bg_color_pass1();
6769         }
6770     }
6771 
set_blend_mode_subpixel_with_bg_color_pass2(&mut self, framebuffer_kind: FramebufferKind)6772     fn set_blend_mode_subpixel_with_bg_color_pass2(&mut self, framebuffer_kind: FramebufferKind) {
6773         if framebuffer_kind == FramebufferKind::Main &&
6774                 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6775             self.device.set_blend_mode_show_overdraw();
6776         } else {
6777             self.device.set_blend_mode_subpixel_with_bg_color_pass2();
6778         }
6779     }
6780 
6781     /// Clears all the layers of a texture with a given color.
clear_texture(&mut self, texture: &Texture, color: [f32; 4])6782     fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
6783         for i in 0..texture.get_layer_count() {
6784             self.device.bind_draw_target(DrawTarget::from_texture(
6785                 &texture,
6786                 i as usize,
6787                 false,
6788             ));
6789             self.device.clear_target(Some(color), None, None);
6790         }
6791     }
6792 }
6793 
6794 pub trait ThreadListener {
thread_started(&self, thread_name: &str)6795     fn thread_started(&self, thread_name: &str);
thread_stopped(&self, thread_name: &str)6796     fn thread_stopped(&self, thread_name: &str);
6797 }
6798 
6799 /// Allows callers to hook in at certain points of the async scene build. These
6800 /// functions are all called from the scene builder thread.
6801 pub trait SceneBuilderHooks {
6802     /// This is called exactly once, when the scene builder thread is started
6803     /// and before it processes anything.
register(&self)6804     fn register(&self);
6805     /// This is called before each scene build starts.
pre_scene_build(&self)6806     fn pre_scene_build(&self);
6807     /// This is called before each scene swap occurs.
pre_scene_swap(&self, scenebuild_time: u64)6808     fn pre_scene_swap(&self, scenebuild_time: u64);
6809     /// This is called after each scene swap occurs. The PipelineInfo contains
6810     /// the updated epochs and pipelines removed in the new scene compared to
6811     /// the old scene.
post_scene_swap(&self, document_id: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64)6812     fn post_scene_swap(&self, document_id: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64);
6813     /// This is called after a resource update operation on the scene builder
6814     /// thread, in the case where resource updates were applied without a scene
6815     /// build.
post_resource_update(&self, document_ids: &Vec<DocumentId>)6816     fn post_resource_update(&self, document_ids: &Vec<DocumentId>);
6817     /// This is called after a scene build completes without any changes being
6818     /// made. We guarantee that each pre_scene_build call will be matched with
6819     /// exactly one of post_scene_swap, post_resource_update or
6820     /// post_empty_scene_build.
post_empty_scene_build(&self)6821     fn post_empty_scene_build(&self);
6822     /// This is a generic callback which provides an opportunity to run code
6823     /// on the scene builder thread. This is called as part of the main message
6824     /// loop of the scene builder thread, but outside of any specific message
6825     /// handler.
poke(&self)6826     fn poke(&self);
6827     /// This is called exactly once, when the scene builder thread is about to
6828     /// terminate.
deregister(&self)6829     fn deregister(&self);
6830 }
6831 
6832 /// Allows callers to hook into the main render_backend loop and provide
6833 /// additional frame ops for generate_frame transactions. These functions
6834 /// are all called from the render backend thread.
6835 pub trait AsyncPropertySampler {
6836     /// This is called exactly once, when the render backend thread is started
6837     /// and before it processes anything.
register(&self)6838     fn register(&self);
6839     /// This is called for each transaction with the generate_frame flag set
6840     /// (i.e. that will trigger a render). The list of frame messages returned
6841     /// are processed as though they were part of the original transaction.
sample(&self, document_id: DocumentId, doc: &FastHashMap<PipelineId, Epoch>) -> Vec<FrameMsg>6842     fn sample(&self, document_id: DocumentId,
6843               doc: &FastHashMap<PipelineId, Epoch>) -> Vec<FrameMsg>;
6844     /// This is called exactly once, when the render backend thread is about to
6845     /// terminate.
deregister(&self)6846     fn deregister(&self);
6847 }
6848 
6849 bitflags! {
6850     /// Flags that control how shaders are pre-cached, if at all.
6851     #[derive(Default)]
6852     pub struct ShaderPrecacheFlags: u32 {
6853         /// Needed for const initialization
6854         const EMPTY                 = 0;
6855 
6856         /// Only start async compile
6857         const ASYNC_COMPILE         = 1 << 2;
6858 
6859         /// Do a full compile/link during startup
6860         const FULL_COMPILE          = 1 << 3;
6861     }
6862 }
6863 
6864 pub struct RendererOptions {
6865     pub device_pixel_ratio: f32,
6866     pub resource_override_path: Option<PathBuf>,
6867     /// Whether to use shaders that have been optimized at build time.
6868     pub use_optimized_shaders: bool,
6869     pub enable_aa: bool,
6870     pub enable_dithering: bool,
6871     pub max_recorded_profiles: usize,
6872     pub precache_flags: ShaderPrecacheFlags,
6873     /// Enable sub-pixel anti-aliasing if a fast implementation is available.
6874     pub enable_subpixel_aa: bool,
6875     /// Enable sub-pixel anti-aliasing if it requires a slow implementation.
6876     pub force_subpixel_aa: bool,
6877     pub clear_color: Option<ColorF>,
6878     pub enable_clear_scissor: bool,
6879     pub max_texture_size: Option<i32>,
6880     pub max_glyph_cache_size: Option<usize>,
6881     pub upload_method: UploadMethod,
6882     pub workers: Option<Arc<ThreadPool>>,
6883     pub enable_multithreading: bool,
6884     pub blob_image_handler: Option<Box<dyn BlobImageHandler>>,
6885     pub thread_listener: Option<Box<dyn ThreadListener + Send + Sync>>,
6886     pub size_of_op: Option<VoidPtrToSizeFn>,
6887     pub enclosing_size_of_op: Option<VoidPtrToSizeFn>,
6888     pub cached_programs: Option<Rc<ProgramCache>>,
6889     pub debug_flags: DebugFlags,
6890     pub renderer_id: Option<u64>,
6891     pub scene_builder_hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
6892     pub sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
6893     pub chase_primitive: ChasePrimitive,
6894     pub support_low_priority_transactions: bool,
6895     pub namespace_alloc_by_client: bool,
6896     pub enable_picture_caching: bool,
6897     pub testing: bool,
6898     /// Set to true if this GPU supports hardware fast clears as a performance
6899     /// optimization. Likely requires benchmarking on various GPUs to see if
6900     /// it is a performance win. The default is false, which tends to be best
6901     /// performance on lower end / integrated GPUs.
6902     pub gpu_supports_fast_clears: bool,
6903     pub allow_dual_source_blending: bool,
6904     pub allow_advanced_blend_equation: bool,
6905     /// If true, allow WR to use pixel local storage if the device supports it.
6906     /// For now, this defaults to false since the code is still experimental
6907     /// and not complete. This option will probably be removed once support is
6908     /// complete, and WR can implicitly choose whether to make use of PLS.
6909     pub allow_pixel_local_storage_support: bool,
6910     /// If true, allow textures to be initialized with glTexStorage.
6911     /// This affects VRAM consumption and data upload paths.
6912     pub allow_texture_storage_support: bool,
6913     /// If true, we allow the data uploaded in a different format from the
6914     /// one expected by the driver, pretending the format is matching, and
6915     /// swizzling the components on all the shader sampling.
6916     pub allow_texture_swizzling: bool,
6917     /// Number of batches to look back in history for adding the current
6918     /// transparent instance into.
6919     pub batch_lookback_count: usize,
6920     /// Start the debug server for this renderer.
6921     pub start_debug_server: bool,
6922     /// Output the source of the shader with the given name.
6923     pub dump_shader_source: Option<String>,
6924     pub surface_origin_is_top_left: bool,
6925     /// The configuration options defining how WR composites the final scene.
6926     pub compositor_config: CompositorConfig,
6927     pub enable_gpu_markers: bool,
6928     /// If true, panic whenever a GL error occurs. This has a significant
6929     /// performance impact, so only use when debugging specific problems!
6930     pub panic_on_gl_error: bool,
6931 }
6932 
6933 impl Default for RendererOptions {
default() -> Self6934     fn default() -> Self {
6935         RendererOptions {
6936             device_pixel_ratio: 1.0,
6937             resource_override_path: None,
6938             use_optimized_shaders: false,
6939             enable_aa: true,
6940             enable_dithering: false,
6941             debug_flags: DebugFlags::empty(),
6942             max_recorded_profiles: 0,
6943             precache_flags: ShaderPrecacheFlags::empty(),
6944             enable_subpixel_aa: false,
6945             force_subpixel_aa: false,
6946             clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
6947             enable_clear_scissor: true,
6948             max_texture_size: None,
6949             max_glyph_cache_size: None,
6950             // This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL,
6951             // but we are unable to make this decision here, so picking the reasonable medium.
6952             upload_method: UploadMethod::PixelBuffer(VertexUsageHint::Stream),
6953             workers: None,
6954             enable_multithreading: true,
6955             blob_image_handler: None,
6956             thread_listener: None,
6957             size_of_op: None,
6958             enclosing_size_of_op: None,
6959             renderer_id: None,
6960             cached_programs: None,
6961             scene_builder_hooks: None,
6962             sampler: None,
6963             chase_primitive: ChasePrimitive::Nothing,
6964             support_low_priority_transactions: false,
6965             namespace_alloc_by_client: false,
6966             enable_picture_caching: false,
6967             testing: false,
6968             gpu_supports_fast_clears: false,
6969             allow_dual_source_blending: true,
6970             allow_advanced_blend_equation: false,
6971             allow_pixel_local_storage_support: false,
6972             allow_texture_storage_support: true,
6973             allow_texture_swizzling: true,
6974             batch_lookback_count: DEFAULT_BATCH_LOOKBACK_COUNT,
6975             // For backwards compatibility we set this to true by default, so
6976             // that if the debugger feature is enabled, the debug server will
6977             // be started automatically. Users can explicitly disable this as
6978             // needed.
6979             start_debug_server: true,
6980             dump_shader_source: None,
6981             surface_origin_is_top_left: false,
6982             compositor_config: CompositorConfig::default(),
6983             enable_gpu_markers: true,
6984             panic_on_gl_error: false,
6985         }
6986     }
6987 }
6988 
6989 pub trait DebugServer {
send(&mut self, _message: String)6990     fn send(&mut self, _message: String);
6991 }
6992 
6993 struct NoopDebugServer;
6994 
6995 impl NoopDebugServer {
new(_: Sender<ApiMsg>) -> Self6996     fn new(_: Sender<ApiMsg>) -> Self {
6997         NoopDebugServer
6998     }
6999 }
7000 
7001 impl DebugServer for NoopDebugServer {
send(&mut self, _: String)7002     fn send(&mut self, _: String) {}
7003 }
7004 
7005 #[cfg(feature = "debugger")]
new_debug_server(enable: bool, api_tx: Sender<ApiMsg>) -> Box<dyn DebugServer>7006 fn new_debug_server(enable: bool, api_tx: Sender<ApiMsg>) -> Box<dyn DebugServer> {
7007     if enable {
7008         Box::new(debug_server::DebugServerImpl::new(api_tx))
7009     } else {
7010         Box::new(NoopDebugServer::new(api_tx))
7011     }
7012 }
7013 
7014 #[cfg(not(feature = "debugger"))]
new_debug_server(_enable: bool, api_tx: Sender<ApiMsg>) -> Box<dyn DebugServer>7015 fn new_debug_server(_enable: bool, api_tx: Sender<ApiMsg>) -> Box<dyn DebugServer> {
7016     Box::new(NoopDebugServer::new(api_tx))
7017 }
7018 
7019 /// Some basic statistics about the rendered scene, used in Gecko, as
7020 /// well as in wrench reftests to ensure that tests are batching and/or
7021 /// allocating on render targets as we expect them to.
7022 #[repr(C)]
7023 #[derive(Debug, Default)]
7024 pub struct RendererStats {
7025     pub total_draw_calls: usize,
7026     pub alpha_target_count: usize,
7027     pub color_target_count: usize,
7028     pub texture_upload_kb: usize,
7029     pub resource_upload_time: u64,
7030     pub gpu_cache_upload_time: u64,
7031 }
7032 
7033 /// Return type from render(), which contains some repr(C) statistics as well as
7034 /// some non-repr(C) data.
7035 #[derive(Debug, Default)]
7036 pub struct RenderResults {
7037     /// Statistics about the frame that was rendered.
7038     pub stats: RendererStats,
7039 
7040     /// A list of dirty world rects. This is only currently
7041     /// useful to test infrastructure.
7042     /// TODO(gw): This needs to be refactored / removed.
7043     pub recorded_dirty_regions: Vec<RecordedDirtyRegion>,
7044 
7045     /// A list of the device dirty rects that were updated
7046     /// this frame.
7047     /// TODO(gw): This is an initial interface, likely to change in future.
7048     /// TODO(gw): The dirty rects here are currently only useful when scrolling
7049     ///           is not occurring. They are still correct in the case of
7050     ///           scrolling, but will be very large (until we expose proper
7051     ///           OS compositor support where the dirty rects apply to a
7052     ///           specific picture cache slice / OS compositor surface).
7053     pub dirty_rects: Vec<DeviceIntRect>,
7054 }
7055 
7056 #[cfg(any(feature = "capture", feature = "replay"))]
7057 #[cfg_attr(feature = "capture", derive(Serialize))]
7058 #[cfg_attr(feature = "replay", derive(Deserialize))]
7059 struct PlainTexture {
7060     data: String,
7061     size: (DeviceIntSize, i32),
7062     format: ImageFormat,
7063     filter: TextureFilter,
7064     has_depth: bool,
7065 }
7066 
7067 
7068 #[cfg(any(feature = "capture", feature = "replay"))]
7069 #[cfg_attr(feature = "capture", derive(Serialize))]
7070 #[cfg_attr(feature = "replay", derive(Deserialize))]
7071 struct PlainRenderer {
7072     device_size: Option<DeviceIntSize>,
7073     gpu_cache: PlainTexture,
7074     gpu_cache_frame_id: FrameId,
7075     textures: FastHashMap<CacheTextureId, PlainTexture>,
7076 }
7077 
7078 #[cfg(any(feature = "capture", feature = "replay"))]
7079 #[cfg_attr(feature = "capture", derive(Serialize))]
7080 #[cfg_attr(feature = "replay", derive(Deserialize))]
7081 struct PlainExternalResources {
7082     images: Vec<ExternalCaptureImage>
7083 }
7084 
7085 #[cfg(feature = "replay")]
7086 enum CapturedExternalImageData {
7087     NativeTexture(gl::GLuint),
7088     Buffer(Arc<Vec<u8>>),
7089 }
7090 
7091 #[cfg(feature = "replay")]
7092 struct DummyExternalImageHandler {
7093     data: FastHashMap<(ExternalImageId, u8), (CapturedExternalImageData, TexelRect)>,
7094 }
7095 
7096 #[cfg(feature = "replay")]
7097 impl ExternalImageHandler for DummyExternalImageHandler {
lock(&mut self, key: ExternalImageId, channel_index: u8, _rendering: ImageRendering) -> ExternalImage7098     fn lock(&mut self, key: ExternalImageId, channel_index: u8, _rendering: ImageRendering) -> ExternalImage {
7099         let (ref captured_data, ref uv) = self.data[&(key, channel_index)];
7100         ExternalImage {
7101             uv: *uv,
7102             source: match *captured_data {
7103                 CapturedExternalImageData::NativeTexture(tid) => ExternalImageSource::NativeTexture(tid),
7104                 CapturedExternalImageData::Buffer(ref arc) => ExternalImageSource::RawData(&*arc),
7105             }
7106         }
7107     }
unlock(&mut self, _key: ExternalImageId, _channel_index: u8)7108     fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
7109 }
7110 
7111 #[cfg(feature = "replay")]
7112 struct VoidHandler;
7113 
7114 #[cfg(feature = "replay")]
7115 impl OutputImageHandler for VoidHandler {
lock(&mut self, _: PipelineId) -> Option<(u32, FramebufferIntSize)>7116     fn lock(&mut self, _: PipelineId) -> Option<(u32, FramebufferIntSize)> {
7117         None
7118     }
unlock(&mut self, _: PipelineId)7119     fn unlock(&mut self, _: PipelineId) {
7120         unreachable!()
7121     }
7122 }
7123 
7124 #[derive(Default)]
7125 pub struct PipelineInfo {
7126     pub epochs: FastHashMap<(PipelineId, DocumentId), Epoch>,
7127     pub removed_pipelines: Vec<(PipelineId, DocumentId)>,
7128 }
7129 
7130 impl Renderer {
7131     #[cfg(feature = "capture")]
save_texture( texture: &Texture, name: &str, root: &PathBuf, device: &mut Device ) -> PlainTexture7132     fn save_texture(
7133         texture: &Texture, name: &str, root: &PathBuf, device: &mut Device
7134     ) -> PlainTexture {
7135         use std::fs;
7136         use std::io::Write;
7137 
7138         let short_path = format!("textures/{}.raw", name);
7139 
7140         let bytes_per_pixel = texture.get_format().bytes_per_pixel();
7141         let read_format = texture.get_format();
7142         let rect_size = texture.get_dimensions();
7143 
7144         let mut file = fs::File::create(root.join(&short_path))
7145             .expect(&format!("Unable to create {}", short_path));
7146         let bytes_per_layer = (rect_size.width * rect_size.height * bytes_per_pixel) as usize;
7147         let mut data = vec![0; bytes_per_layer];
7148 
7149         //TODO: instead of reading from an FBO with `read_pixels*`, we could
7150         // read from textures directly with `get_tex_image*`.
7151 
7152         for layer_id in 0 .. texture.get_layer_count() {
7153             let rect = device_size_as_framebuffer_size(rect_size).into();
7154 
7155             device.attach_read_texture(texture, layer_id);
7156             #[cfg(feature = "png")]
7157             {
7158                 let mut png_data;
7159                 let (data_ref, format) = match texture.get_format() {
7160                     ImageFormat::RGBAF32 => {
7161                         png_data = vec![0; (rect_size.width * rect_size.height * 4) as usize];
7162                         device.read_pixels_into(rect, ImageFormat::RGBA8, &mut png_data);
7163                         (&png_data, ImageFormat::RGBA8)
7164                     }
7165                     fm => (&data, fm),
7166                 };
7167                 CaptureConfig::save_png(
7168                     root.join(format!("textures/{}-{}.png", name, layer_id)),
7169                     rect_size, format,
7170                     None,
7171                     data_ref,
7172                 );
7173             }
7174             device.read_pixels_into(rect, read_format, &mut data);
7175             file.write_all(&data)
7176                 .unwrap();
7177         }
7178 
7179         PlainTexture {
7180             data: short_path,
7181             size: (rect_size, texture.get_layer_count()),
7182             format: texture.get_format(),
7183             filter: texture.get_filter(),
7184             has_depth: texture.supports_depth(),
7185         }
7186     }
7187 
7188     #[cfg(feature = "replay")]
load_texture( target: TextureTarget, plain: &PlainTexture, rt_info: Option<RenderTargetInfo>, root: &PathBuf, device: &mut Device ) -> (Texture, Vec<u8>)7189     fn load_texture(
7190         target: TextureTarget,
7191         plain: &PlainTexture,
7192         rt_info: Option<RenderTargetInfo>,
7193         root: &PathBuf,
7194         device: &mut Device
7195     ) -> (Texture, Vec<u8>)
7196     {
7197         use std::fs::File;
7198         use std::io::Read;
7199 
7200         let mut texels = Vec::new();
7201         File::open(root.join(&plain.data))
7202             .expect(&format!("Unable to open texture at {}", plain.data))
7203             .read_to_end(&mut texels)
7204             .unwrap();
7205 
7206         let texture = device.create_texture(
7207             target,
7208             plain.format,
7209             plain.size.0.width,
7210             plain.size.0.height,
7211             plain.filter,
7212             rt_info,
7213             plain.size.1,
7214         );
7215         device.upload_texture_immediate(&texture, &texels);
7216 
7217         (texture, texels)
7218     }
7219 
7220     #[cfg(feature = "capture")]
save_capture( &mut self, config: CaptureConfig, deferred_images: Vec<ExternalCaptureImage>, )7221     fn save_capture(
7222         &mut self,
7223         config: CaptureConfig,
7224         deferred_images: Vec<ExternalCaptureImage>,
7225     ) {
7226         use std::fs;
7227         use std::io::Write;
7228         use api::{CaptureBits, ExternalImageData};
7229 
7230         let root = config.resource_root();
7231 
7232         self.device.begin_frame();
7233         let _gm = self.gpu_profile.start_marker("read GPU data");
7234         self.device.bind_read_target_impl(self.read_fbo);
7235 
7236         if config.bits.contains(CaptureBits::EXTERNAL_RESOURCES) && !deferred_images.is_empty() {
7237             info!("saving external images");
7238             let mut arc_map = FastHashMap::<*const u8, String>::default();
7239             let mut tex_map = FastHashMap::<u32, String>::default();
7240             let handler = self.external_image_handler
7241                 .as_mut()
7242                 .expect("Unable to lock the external image handler!");
7243             for def in &deferred_images {
7244                 info!("\t{}", def.short_path);
7245                 let ExternalImageData { id, channel_index, image_type } = def.external;
7246                 // The image rendering parameter is irrelevant because no filtering happens during capturing.
7247                 let ext_image = handler.lock(id, channel_index, ImageRendering::Auto);
7248                 let (data, short_path) = match ext_image.source {
7249                     ExternalImageSource::RawData(data) => {
7250                         let arc_id = arc_map.len() + 1;
7251                         match arc_map.entry(data.as_ptr()) {
7252                             Entry::Occupied(e) => {
7253                                 (None, e.get().clone())
7254                             }
7255                             Entry::Vacant(e) => {
7256                                 let short_path = format!("externals/d{}.raw", arc_id);
7257                                 (Some(data.to_vec()), e.insert(short_path).clone())
7258                             }
7259                         }
7260                     }
7261                     ExternalImageSource::NativeTexture(gl_id) => {
7262                         let tex_id = tex_map.len() + 1;
7263                         match tex_map.entry(gl_id) {
7264                             Entry::Occupied(e) => {
7265                                 (None, e.get().clone())
7266                             }
7267                             Entry::Vacant(e) => {
7268                                 let target = match image_type {
7269                                     ExternalImageType::TextureHandle(target) => target,
7270                                     ExternalImageType::Buffer => unreachable!(),
7271                                 };
7272                                 info!("\t\tnative texture of target {:?}", target);
7273                                 let layer_index = 0; //TODO: what about layered textures?
7274                                 self.device.attach_read_texture_external(gl_id, target, layer_index);
7275                                 let data = self.device.read_pixels(&def.descriptor);
7276                                 let short_path = format!("externals/t{}.raw", tex_id);
7277                                 (Some(data), e.insert(short_path).clone())
7278                             }
7279                         }
7280                     }
7281                     ExternalImageSource::Invalid => {
7282                         info!("\t\tinvalid source!");
7283                         (None, String::new())
7284                     }
7285                 };
7286                 if let Some(bytes) = data {
7287                     fs::File::create(root.join(&short_path))
7288                         .expect(&format!("Unable to create {}", short_path))
7289                         .write_all(&bytes)
7290                         .unwrap();
7291                     #[cfg(feature = "png")]
7292                     CaptureConfig::save_png(
7293                         root.join(&short_path).with_extension("png"),
7294                         def.descriptor.size,
7295                         def.descriptor.format,
7296                         def.descriptor.stride,
7297                         &bytes,
7298                     );
7299                 }
7300                 let plain = PlainExternalImage {
7301                     data: short_path,
7302                     external: def.external,
7303                     uv: ext_image.uv,
7304                 };
7305                 config.serialize_for_resource(&plain, &def.short_path);
7306             }
7307             for def in &deferred_images {
7308                 handler.unlock(def.external.id, def.external.channel_index);
7309             }
7310             let plain_external = PlainExternalResources {
7311                 images: deferred_images,
7312             };
7313             config.serialize_for_resource(&plain_external, "external_resources");
7314         }
7315 
7316         if config.bits.contains(CaptureBits::FRAME) {
7317             let path_textures = root.join("textures");
7318             if !path_textures.is_dir() {
7319                 fs::create_dir(&path_textures).unwrap();
7320             }
7321 
7322             info!("saving GPU cache");
7323             self.update_gpu_cache(); // flush pending updates
7324             let mut plain_self = PlainRenderer {
7325                 device_size: self.device_size,
7326                 gpu_cache: Self::save_texture(
7327                     &self.gpu_cache_texture.texture.as_ref().unwrap(),
7328                     "gpu", &root, &mut self.device,
7329                 ),
7330                 gpu_cache_frame_id: self.gpu_cache_frame_id,
7331                 textures: FastHashMap::default(),
7332             };
7333 
7334             info!("saving cached textures");
7335             for (id, texture) in &self.texture_resolver.texture_cache_map {
7336                 let file_name = format!("cache-{}", plain_self.textures.len() + 1);
7337                 info!("\t{}", file_name);
7338                 let plain = Self::save_texture(texture, &file_name, &root, &mut self.device);
7339                 plain_self.textures.insert(*id, plain);
7340             }
7341 
7342             config.serialize_for_resource(&plain_self, "renderer");
7343         }
7344 
7345         self.device.reset_read_target();
7346         self.device.end_frame();
7347         info!("done.");
7348     }
7349 
7350     #[cfg(feature = "replay")]
load_capture( &mut self, config: CaptureConfig, plain_externals: Vec<PlainExternalImage>, )7351     fn load_capture(
7352         &mut self,
7353         config: CaptureConfig,
7354         plain_externals: Vec<PlainExternalImage>,
7355     ) {
7356         use std::fs::File;
7357         use std::io::Read;
7358         use std::slice;
7359 
7360         info!("loading external buffer-backed images");
7361         assert!(self.texture_resolver.external_images.is_empty());
7362         let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
7363         let mut image_handler = DummyExternalImageHandler {
7364             data: FastHashMap::default(),
7365         };
7366 
7367         let root = config.resource_root();
7368 
7369         // Note: this is a `SCENE` level population of the external image handlers
7370         // It would put both external buffers and texture into the map.
7371         // But latter are going to be overwritten later in this function
7372         // if we are in the `FRAME` level.
7373         for plain_ext in plain_externals {
7374             let data = match raw_map.entry(plain_ext.data) {
7375                 Entry::Occupied(e) => e.get().clone(),
7376                 Entry::Vacant(e) => {
7377                     let mut buffer = Vec::new();
7378                     File::open(root.join(e.key()))
7379                         .expect(&format!("Unable to open {}", e.key()))
7380                         .read_to_end(&mut buffer)
7381                         .unwrap();
7382                     e.insert(Arc::new(buffer)).clone()
7383                 }
7384             };
7385             let ext = plain_ext.external;
7386             let value = (CapturedExternalImageData::Buffer(data), plain_ext.uv);
7387             image_handler.data.insert((ext.id, ext.channel_index), value);
7388         }
7389 
7390         if let Some(external_resources) = config.deserialize_for_resource::<PlainExternalResources, _>("external_resources") {
7391             info!("loading external texture-backed images");
7392             let mut native_map = FastHashMap::<String, gl::GLuint>::default();
7393             for ExternalCaptureImage { short_path, external, descriptor } in external_resources.images {
7394                 let target = match external.image_type {
7395                     ExternalImageType::TextureHandle(target) => target,
7396                     ExternalImageType::Buffer => continue,
7397                 };
7398                 let plain_ext = config.deserialize_for_resource::<PlainExternalImage, _>(&short_path)
7399                     .expect(&format!("Unable to read {}.ron", short_path));
7400                 let key = (external.id, external.channel_index);
7401 
7402                 let tid = match native_map.entry(plain_ext.data) {
7403                     Entry::Occupied(e) => e.get().clone(),
7404                     Entry::Vacant(e) => {
7405                         //TODO: provide a way to query both the layer count and the filter from external images
7406                         let (layer_count, filter) = (1, TextureFilter::Linear);
7407                         let plain_tex = PlainTexture {
7408                             data: e.key().clone(),
7409                             size: (descriptor.size, layer_count),
7410                             format: descriptor.format,
7411                             filter,
7412                             has_depth: false,
7413                         };
7414                         let t = Self::load_texture(
7415                             target,
7416                             &plain_tex,
7417                             None,
7418                             &root,
7419                             &mut self.device
7420                         );
7421                         let extex = t.0.into_external();
7422                         self.owned_external_images.insert(key, extex.clone());
7423                         e.insert(extex.internal_id()).clone()
7424                     }
7425                 };
7426 
7427                 let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv);
7428                 image_handler.data.insert(key, value);
7429             }
7430         }
7431 
7432         if let Some(renderer) = config.deserialize_for_resource::<PlainRenderer, _>("renderer") {
7433             info!("loading cached textures");
7434             self.device_size = renderer.device_size;
7435             self.device.begin_frame();
7436 
7437             for (_id, texture) in self.texture_resolver.texture_cache_map.drain() {
7438                 self.device.delete_texture(texture);
7439             }
7440             for (id, texture) in renderer.textures {
7441                 info!("\t{}", texture.data);
7442                 let t = Self::load_texture(
7443                     TextureTarget::Array,
7444                     &texture,
7445                     Some(RenderTargetInfo { has_depth: texture.has_depth }),
7446                     &root,
7447                     &mut self.device
7448                 );
7449                 self.texture_resolver.texture_cache_map.insert(id, t.0);
7450             }
7451 
7452             info!("loading gpu cache");
7453             if let Some(t) = self.gpu_cache_texture.texture.take() {
7454                 self.device.delete_texture(t);
7455             }
7456             let (t, gpu_cache_data) = Self::load_texture(
7457                 TextureTarget::Default,
7458                 &renderer.gpu_cache,
7459                 Some(RenderTargetInfo { has_depth: false }),
7460                 &root,
7461                 &mut self.device,
7462             );
7463             self.gpu_cache_texture.texture = Some(t);
7464             match self.gpu_cache_texture.bus {
7465                 GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
7466                     let dim = self.gpu_cache_texture.texture.as_ref().unwrap().get_dimensions();
7467                     let blocks = unsafe {
7468                         slice::from_raw_parts(
7469                             gpu_cache_data.as_ptr() as *const GpuBlockData,
7470                             gpu_cache_data.len() / mem::size_of::<GpuBlockData>(),
7471                         )
7472                     };
7473                     // fill up the CPU cache from the contents we just loaded
7474                     rows.clear();
7475                     rows.extend((0 .. dim.height).map(|_| CacheRow::new()));
7476                     let chunks = blocks.chunks(MAX_VERTEX_TEXTURE_WIDTH);
7477                     debug_assert_eq!(chunks.len(), rows.len());
7478                     for (row, chunk) in rows.iter_mut().zip(chunks) {
7479                         row.cpu_blocks.copy_from_slice(chunk);
7480                     }
7481                 }
7482                 GpuCacheBus::Scatter { .. } => {}
7483             }
7484             self.gpu_cache_frame_id = renderer.gpu_cache_frame_id;
7485 
7486             self.device.end_frame();
7487         } else {
7488             info!("loading cached textures");
7489             self.device.begin_frame();
7490             for (_id, texture) in self.texture_resolver.texture_cache_map.drain() {
7491                 self.device.delete_texture(texture);
7492             }
7493 
7494             info!("loading gpu cache");
7495             if let Some(t) = self.gpu_cache_texture.texture.take() {
7496                 self.device.delete_texture(t);
7497             }
7498             self.device.end_frame();
7499         }
7500 
7501         self.output_image_handler = Some(Box::new(VoidHandler) as Box<_>);
7502         self.external_image_handler = Some(Box::new(image_handler) as Box<_>);
7503         info!("done.");
7504     }
7505 }
7506 
get_vao(vertex_array_kind: VertexArrayKind, vaos: &RendererVAOs) -> &VAO7507 fn get_vao(vertex_array_kind: VertexArrayKind, vaos: &RendererVAOs) -> &VAO {
7508     match vertex_array_kind {
7509         VertexArrayKind::Primitive => &vaos.prim_vao,
7510         VertexArrayKind::Clip => &vaos.clip_vao,
7511         VertexArrayKind::Blur => &vaos.blur_vao,
7512         VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(),
7513         VertexArrayKind::Border => &vaos.border_vao,
7514         VertexArrayKind::Scale => &vaos.scale_vao,
7515         VertexArrayKind::LineDecoration => &vaos.line_vao,
7516         VertexArrayKind::Gradient => &vaos.gradient_vao,
7517         VertexArrayKind::Resolve => &vaos.resolve_vao,
7518         VertexArrayKind::SvgFilter => &vaos.svg_filter_vao,
7519         VertexArrayKind::Composite => &vaos.composite_vao,
7520     }
7521 }
7522 #[derive(Clone, Copy, PartialEq)]
7523 enum FramebufferKind {
7524     Main,
7525     Other,
7526 }
7527 
should_skip_batch(kind: &BatchKind, flags: DebugFlags) -> bool7528 fn should_skip_batch(kind: &BatchKind, flags: DebugFlags) -> bool {
7529     match kind {
7530         BatchKind::TextRun(_) => {
7531             flags.contains(DebugFlags::DISABLE_TEXT_PRIMS)
7532         }
7533         BatchKind::Brush(BrushBatchKind::ConicGradient) |
7534         BatchKind::Brush(BrushBatchKind::RadialGradient) |
7535         BatchKind::Brush(BrushBatchKind::LinearGradient) => {
7536             flags.contains(DebugFlags::DISABLE_GRADIENT_PRIMS)
7537         }
7538         _ => false,
7539     }
7540 }
7541 
7542 impl CompositeState {
7543     /// Use the client provided native compositor interface to add all picture
7544     /// cache tiles to the OS compositor
composite_native( &self, compositor: &mut dyn Compositor, )7545     fn composite_native(
7546         &self,
7547         compositor: &mut dyn Compositor,
7548     ) {
7549         // Add each surface to the visual tree. z-order is implicit based on
7550         // order added. Offset and clip rect apply to all tiles within this
7551         // surface.
7552         for surface in &self.descriptor.surfaces {
7553             compositor.add_surface(
7554                 surface.surface_id.expect("bug: no native surface allocated"),
7555                 surface.offset.to_i32(),
7556                 surface.clip_rect.to_i32(),
7557             );
7558         }
7559     }
7560 }
7561