Skip to main content

webrender/renderer/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
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
37use api::{ColorF, ColorU, MixBlendMode, TextureCacheCategory};
38use api::{DocumentId, Epoch, ExternalImageHandler, RenderReasons};
39use api::{PipelineId, ImageRendering, Checkpoint, NotificationRequest, ImageBufferKind};
40use api::{FramePublishId, ImageFormat};
41#[cfg(any(feature = "capture", feature = "replay"))]
42use api::{ExternalImageSource, ExternalImageType};
43#[cfg(feature = "replay")]
44use api::{ExternalImage, ExternalImageId};
45use api::units::*;
46use api::channel::{Sender, Receiver};
47pub use api::DebugFlags;
48use core::time::Duration;
49
50use crate::pattern::PatternKind;
51use crate::render_api::{DebugCommand, ApiMsg, MemoryReport};
52use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList};
53use crate::batch::ClipMaskInstanceList;
54#[cfg(any(feature = "capture", feature = "replay"))]
55use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
56use crate::composite::{CompositeState, CompositeTileSurface, CompositorSurfaceTransform};
57use crate::composite::{CompositorKind, Compositor, NativeTileId};
58use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation, ClipRadius};
59#[cfg(feature = "debugger")]
60use api::debugger::{CompositorDebugInfo, DebuggerTextureContent};
61use crate::debug_colors;
62use crate::device::{DepthFunction, Device, DrawTarget, ExternalTexture, GpuFrameId, UploadPBOPool};
63use crate::device::{ReadTarget, ShaderError, Texture, TextureFilter, TextureFlags, TextureSlot, Texel};
64use crate::device::query::{GpuSampler, GpuTimer};
65#[cfg(feature = "capture")]
66use crate::device::FBOId;
67use crate::debug_item::DebugItem;
68use crate::frame_builder::Frame;
69use glyph_rasterizer::GlyphFormat;
70use crate::gpu_types::{ScalingInstance, SVGFEFilterInstance, CopyInstance, PrimitiveInstanceData};
71use crate::gpu_types::{BlurInstance, ClearInstance};
72use crate::internal_types::{TextureSource, TextureSourceExternal, FrameVec};
73#[cfg(any(feature = "capture", feature = "replay"))]
74use crate::internal_types::DebugOutput;
75use crate::internal_types::{CacheTextureId, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
76use crate::internal_types::{TextureCacheAllocInfo, TextureCacheAllocationKind, TextureUpdateList};
77use crate::internal_types::{RenderTargetInfo, Swizzle, DeferredResolveIndex};
78use crate::picture::ResolvedSurfaceTexture;
79use crate::profiler::{self, RenderCommandLog, GpuProfileTag, TransactionProfile};
80use crate::profiler::{Profiler, add_event_marker, add_text_marker, thread_is_being_profiled};
81use crate::device::query::GpuProfiler;
82use crate::render_target::ResolveOp;
83use crate::render_task_graph::RenderTaskGraph;
84use crate::render_task::{RenderTask, RenderTaskKind, ReadbackTask};
85use crate::screen_capture::AsyncScreenshotGrabber;
86use crate::render_target::{RenderTarget, PictureCacheTarget, PictureCacheTargetKind};
87use crate::render_target::{RenderTargetKind, BlitJob};
88use crate::telemetry::Telemetry;
89use crate::tile_cache::PictureCacheDebugInfo;
90use crate::util::drain_filter;
91#[cfg(feature = "debugger")]
92use crate::debugger::{Debugger, DebugQueryKind};
93use upload::{upload_to_texture_cache, UploadTexturePool};
94use init::*;
95
96use euclid::{rect, Transform3D, Scale, default};
97use gleam::gl;
98use malloc_size_of::MallocSizeOfOps;
99
100#[cfg(feature = "replay")]
101use std::sync::Arc;
102
103use std::{
104    cell::RefCell,
105    collections::VecDeque,
106    f32,
107    ffi::c_void,
108    mem,
109    num::NonZeroUsize,
110    path::PathBuf,
111    rc::Rc,
112};
113#[cfg(any(feature = "capture", feature = "replay"))]
114use std::collections::hash_map::Entry;
115
116mod composite;
117mod debug;
118mod external_image;
119mod gpu_buffer;
120mod shade;
121mod vertex;
122mod upload;
123pub(crate) mod init;
124
125use composite::LayerCompositorFrameState;
126
127pub use debug::DebugRenderer;
128pub use shade::{PendingShadersToPrecache, Shaders, SharedShaders};
129pub use vertex::{desc, VertexArrayKind, MAX_VERTEX_TEXTURE_WIDTH};
130pub use gpu_buffer::{GpuBuffer, GpuBufferF, GpuBufferBuilderF, GpuBufferI, GpuBufferBuilderI};
131pub use gpu_buffer::{GpuBufferHandle, GpuBufferAddress, GpuBufferBuilder, GpuBufferWriterF};
132pub use gpu_buffer::{GpuBufferBlockF, GpuBufferDataF, GpuBufferDataI, GpuBufferWriterI};
133
134/// The size of the array of each type of vertex data texture that
135/// is round-robin-ed each frame during bind_frame_data. Doing this
136/// helps avoid driver stalls while updating the texture in some
137/// drivers. The size of these textures are typically very small
138/// (e.g. < 16 kB) so it's not a huge waste of memory. Despite that,
139/// this is a short-term solution - we want to find a better way
140/// to provide this frame data, which will likely involve some
141/// combination of UBO/SSBO usage. Although this only affects some
142/// platforms, it's enabled on all platforms to reduce testing
143/// differences between platforms.
144pub const VERTEX_DATA_TEXTURE_COUNT: usize = 3;
145
146/// Number of GPU blocks per UV rectangle provided for an image.
147pub const BLOCKS_PER_UV_RECT: usize = 2;
148
149const GPU_TAG_BRUSH_OPACITY: GpuProfileTag = GpuProfileTag {
150    label: "B_Opacity",
151    color: debug_colors::DARKMAGENTA,
152};
153const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
154    label: "B_YuvImage",
155    color: debug_colors::DARKGREEN,
156};
157const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag {
158    label: "B_MixBlend",
159    color: debug_colors::MAGENTA,
160};
161const GPU_TAG_BRUSH_BLEND: GpuProfileTag = GpuProfileTag {
162    label: "B_Blend",
163    color: debug_colors::ORANGE,
164};
165const GPU_TAG_BRUSH_IMAGE: GpuProfileTag = GpuProfileTag {
166    label: "B_Image",
167    color: debug_colors::SPRINGGREEN,
168};
169const GPU_TAG_BRUSH_SOLID: GpuProfileTag = GpuProfileTag {
170    label: "B_Solid",
171    color: debug_colors::RED,
172};
173const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
174    label: "C_Clip",
175    color: debug_colors::PURPLE,
176};
177const GPU_TAG_CACHE_BORDER: GpuProfileTag = GpuProfileTag {
178    label: "C_Border",
179    color: debug_colors::CORNSILK,
180};
181const GPU_TAG_CACHE_LINE_DECORATION: GpuProfileTag = GpuProfileTag {
182    label: "C_LineDecoration",
183    color: debug_colors::YELLOWGREEN,
184};
185const GPU_TAG_GRADIENT: GpuProfileTag = GpuProfileTag {
186    label: "C_Gradient",
187    color: debug_colors::BROWN,
188};
189const GPU_TAG_REPEAT: GpuProfileTag = GpuProfileTag {
190    label: "Repeat",
191    color: debug_colors::CHARTREUSE,
192};
193const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
194    label: "target init",
195    color: debug_colors::SLATEGREY,
196};
197const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag {
198    label: "data init",
199    color: debug_colors::LIGHTGREY,
200};
201const GPU_TAG_PRIM_SPLIT_COMPOSITE: GpuProfileTag = GpuProfileTag {
202    label: "SplitComposite",
203    color: debug_colors::DARKBLUE,
204};
205const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag {
206    label: "TextRun",
207    color: debug_colors::BLUE,
208};
209const GPU_TAG_PRIMITIVE: GpuProfileTag = GpuProfileTag {
210    label: "Primitive",
211    color: debug_colors::RED,
212};
213const GPU_TAG_INDIRECT_PRIM: GpuProfileTag = GpuProfileTag {
214    label: "Primitive (indirect)",
215    color: debug_colors::YELLOWGREEN,
216};
217const GPU_TAG_INDIRECT_MASK: GpuProfileTag = GpuProfileTag {
218    label: "Mask (indirect)",
219    color: debug_colors::IVORY,
220};
221const GPU_TAG_BLUR: GpuProfileTag = GpuProfileTag {
222    label: "Blur",
223    color: debug_colors::VIOLET,
224};
225const GPU_TAG_BLIT: GpuProfileTag = GpuProfileTag {
226    label: "Blit",
227    color: debug_colors::LIME,
228};
229const GPU_TAG_SCALE: GpuProfileTag = GpuProfileTag {
230    label: "Scale",
231    color: debug_colors::GHOSTWHITE,
232};
233const GPU_SAMPLER_TAG_ALPHA: GpuProfileTag = GpuProfileTag {
234    label: "Alpha targets",
235    color: debug_colors::BLACK,
236};
237pub const GPU_SAMPLER_TAG_OPAQUE: GpuProfileTag = GpuProfileTag {
238    label: "Opaque pass",
239    color: debug_colors::BLACK,
240};
241pub const GPU_SAMPLER_TAG_TRANSPARENT: GpuProfileTag = GpuProfileTag {
242    label: "Transparent pass",
243    color: debug_colors::BLACK,
244};
245const GPU_TAG_SVG_FILTER_NODES: GpuProfileTag = GpuProfileTag {
246    label: "SvgFilterNodes",
247    color: debug_colors::LEMONCHIFFON,
248};
249pub const GPU_TAG_COMPOSITE: GpuProfileTag = GpuProfileTag {
250    label: "Composite",
251    color: debug_colors::TOMATO,
252};
253
254
255/// The clear color used for the texture cache when the debug display is enabled.
256/// We use a shade of blue so that we can still identify completely blue items in
257/// the texture cache.
258pub const TEXTURE_CACHE_DBG_CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.8, 1.0];
259
260impl BatchKind {
261    fn sampler_tag(&self) -> GpuProfileTag {
262        match *self {
263            BatchKind::SplitComposite => GPU_TAG_PRIM_SPLIT_COMPOSITE,
264            BatchKind::Brush(kind) => {
265                match kind {
266                    BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
267                    BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
268                    BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
269                    BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
270                    BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
271                    BrushBatchKind::Opacity => GPU_TAG_BRUSH_OPACITY,
272                }
273            }
274            BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN,
275            BatchKind::Quad(PatternKind::ColorOrTexture) => GPU_TAG_PRIMITIVE,
276            BatchKind::Quad(PatternKind::TextureExternal) => GPU_TAG_PRIMITIVE,
277            BatchKind::Quad(PatternKind::TextureExternalBT709) => GPU_TAG_PRIMITIVE,
278            BatchKind::Quad(PatternKind::TextureRect) => GPU_TAG_PRIMITIVE,
279            BatchKind::Quad(PatternKind::Gradient) => GPU_TAG_GRADIENT,
280            BatchKind::Quad(PatternKind::Repeat) => GPU_TAG_REPEAT,
281            BatchKind::Quad(PatternKind::BoxShadow) => GPU_TAG_PRIMITIVE,
282            BatchKind::Quad(PatternKind::Mask) => GPU_TAG_INDIRECT_MASK,
283        }
284    }
285}
286
287fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
288    if before & select != after & select {
289        Some(after.contains(select))
290    } else {
291        None
292    }
293}
294
295#[repr(C)]
296#[derive(Copy, Clone, Debug)]
297pub enum ShaderColorMode {
298    Alpha = 0,
299    SubpixelDualSource = 1,
300    BitmapShadow = 2,
301    ColorBitmap = 3,
302    Image = 4,
303    MultiplyDualSource = 5,
304}
305
306impl From<GlyphFormat> for ShaderColorMode {
307    fn from(format: GlyphFormat) -> ShaderColorMode {
308        match format {
309            GlyphFormat::Alpha |
310            GlyphFormat::TransformedAlpha |
311            GlyphFormat::Bitmap => ShaderColorMode::Alpha,
312            GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => {
313                panic!("Subpixel glyph formats must be handled separately.");
314            }
315            GlyphFormat::ColorBitmap => ShaderColorMode::ColorBitmap,
316        }
317    }
318}
319
320/// Enumeration of the texture samplers used across the various WebRender shaders.
321///
322/// Each variant corresponds to a uniform declared in shader source. We only bind
323/// the variants we need for a given shader, so not every variant is bound for every
324/// batch.
325#[derive(Debug, Copy, Clone, PartialEq, Eq)]
326pub(crate) enum TextureSampler {
327    Color0,
328    Color1,
329    Color2,
330    TransformPalette,
331    RenderTasks,
332    Dither,
333    PrimitiveHeadersF,
334    PrimitiveHeadersI,
335    ClipMask,
336    GpuBufferF,
337    GpuBufferI,
338}
339
340impl TextureSampler {
341    pub(crate) fn color(n: usize) -> TextureSampler {
342        match n {
343            0 => TextureSampler::Color0,
344            1 => TextureSampler::Color1,
345            2 => TextureSampler::Color2,
346            _ => {
347                panic!("There are only 3 color samplers.");
348            }
349        }
350    }
351}
352
353impl Into<TextureSlot> for TextureSampler {
354    fn into(self) -> TextureSlot {
355        match self {
356            TextureSampler::Color0 => TextureSlot(0),
357            TextureSampler::Color1 => TextureSlot(1),
358            TextureSampler::Color2 => TextureSlot(2),
359            TextureSampler::TransformPalette => TextureSlot(3),
360            TextureSampler::RenderTasks => TextureSlot(4),
361            TextureSampler::Dither => TextureSlot(5),
362            TextureSampler::PrimitiveHeadersF => TextureSlot(6),
363            TextureSampler::PrimitiveHeadersI => TextureSlot(7),
364            TextureSampler::ClipMask => TextureSlot(8),
365            TextureSampler::GpuBufferF => TextureSlot(9),
366            TextureSampler::GpuBufferI => TextureSlot(10),
367        }
368    }
369}
370
371#[derive(Clone, Debug, PartialEq)]
372pub enum GraphicsApi {
373    OpenGL,
374}
375
376#[derive(Clone, Debug)]
377pub struct GraphicsApiInfo {
378    pub kind: GraphicsApi,
379    pub renderer: String,
380    pub version: String,
381}
382
383#[derive(Debug)]
384pub struct GpuProfile {
385    pub frame_id: GpuFrameId,
386    pub paint_time_ns: u64,
387}
388
389impl GpuProfile {
390    fn new(frame_id: GpuFrameId, timers: &[GpuTimer]) -> GpuProfile {
391        let mut paint_time_ns = 0;
392        for timer in timers {
393            paint_time_ns += timer.time_ns;
394        }
395        GpuProfile {
396            frame_id,
397            paint_time_ns,
398        }
399    }
400}
401
402#[derive(Debug)]
403pub struct CpuProfile {
404    pub frame_id: GpuFrameId,
405    pub backend_time_ns: u64,
406    pub composite_time_ns: u64,
407    pub draw_calls: usize,
408}
409
410impl CpuProfile {
411    fn new(
412        frame_id: GpuFrameId,
413        backend_time_ns: u64,
414        composite_time_ns: u64,
415        draw_calls: usize,
416    ) -> CpuProfile {
417        CpuProfile {
418            frame_id,
419            backend_time_ns,
420            composite_time_ns,
421            draw_calls,
422        }
423    }
424}
425
426/// The selected partial present mode for a given frame.
427#[derive(Debug, Copy, Clone)]
428pub(super) enum PartialPresentMode {
429    /// The device supports fewer dirty rects than the number of dirty rects
430    /// that WR produced. In this case, the WR dirty rects are union'ed into
431    /// a single dirty rect, that is provided to the caller.
432    Single {
433        dirty_rect: DeviceRect,
434    },
435}
436
437struct CacheTexture {
438    texture: Texture,
439    category: TextureCacheCategory,
440}
441
442/// Helper struct for resolving device Textures for use during rendering passes.
443///
444/// Manages the mapping between the at-a-distance texture handles used by the
445/// `RenderBackend` (which does not directly interface with the GPU) and actual
446/// device texture handles.
447struct TextureResolver {
448    /// A map to resolve texture cache IDs to native textures.
449    texture_cache_map: FastHashMap<CacheTextureId, CacheTexture>,
450
451    /// Map of external image IDs to native textures.
452    external_images: FastHashMap<DeferredResolveIndex, ExternalTexture>,
453
454    /// A special 1x1 dummy texture used for shaders that expect to work with
455    /// the output of the previous pass but are actually running in the first
456    /// pass.
457    dummy_cache_texture: Texture,
458}
459
460impl TextureResolver {
461    fn new(device: &mut Device) -> TextureResolver {
462        let dummy_cache_texture = device
463            .create_texture(
464                ImageBufferKind::Texture2D,
465                ImageFormat::RGBA8,
466                1,
467                1,
468                TextureFilter::Linear,
469                None,
470            );
471        device.upload_texture_immediate(
472            &dummy_cache_texture,
473            &[0xff, 0xff, 0xff, 0xff],
474        );
475
476        TextureResolver {
477            texture_cache_map: FastHashMap::default(),
478            external_images: FastHashMap::default(),
479            dummy_cache_texture,
480        }
481    }
482
483    fn deinit(self, device: &mut Device) {
484        device.delete_texture(self.dummy_cache_texture);
485
486        for (_id, item) in self.texture_cache_map {
487            device.delete_texture(item.texture);
488        }
489    }
490
491    fn begin_frame(&mut self) {
492    }
493
494    fn end_pass(
495        &mut self,
496        device: &mut Device,
497        textures_to_invalidate: &[CacheTextureId],
498    ) {
499        // For any texture that is no longer needed, immediately
500        // invalidate it so that tiled GPUs don't need to resolve it
501        // back to memory.
502        for texture_id in textures_to_invalidate {
503            let render_target = &self.texture_cache_map[texture_id].texture;
504            device.invalidate_render_target(render_target);
505        }
506    }
507
508    // Bind a source texture to the device.
509    fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) -> Swizzle {
510        match *texture_id {
511            TextureSource::Invalid => {
512                Swizzle::default()
513            }
514            TextureSource::Dummy => {
515                let swizzle = Swizzle::default();
516                device.bind_texture(sampler, &self.dummy_cache_texture, swizzle);
517                swizzle
518            }
519            TextureSource::External(TextureSourceExternal { ref index, .. }) => {
520                let texture = self.external_images
521                    .get(index)
522                    .expect("BUG: External image should be resolved by now");
523                device.bind_external_texture(sampler, texture);
524                Swizzle::default()
525            }
526            TextureSource::TextureCache(index, swizzle) => {
527                let texture = &self.texture_cache_map[&index].texture;
528                device.bind_texture(sampler, texture, swizzle);
529                swizzle
530            }
531        }
532    }
533
534    // Get the real (OpenGL) texture ID for a given source texture.
535    // For a texture cache texture, the IDs are stored in a vector
536    // map for fast access.
537    fn resolve(&self, texture_id: &TextureSource) -> Option<(&Texture, Swizzle)> {
538        match *texture_id {
539            TextureSource::Invalid => None,
540            TextureSource::Dummy => {
541                Some((&self.dummy_cache_texture, Swizzle::default()))
542            }
543            TextureSource::External(..) => {
544                panic!("BUG: External textures cannot be resolved, they can only be bound.");
545            }
546            TextureSource::TextureCache(index, swizzle) => {
547                Some((&self.texture_cache_map[&index].texture, swizzle))
548            }
549        }
550    }
551
552    // Retrieve the deferred / resolved UV rect if an external texture, otherwise
553    // return the default supplied UV rect.
554    fn get_uv_rect(
555        &self,
556        source: &TextureSource,
557        default_value: TexelRect,
558    ) -> TexelRect {
559        match source {
560            TextureSource::External(TextureSourceExternal { ref index, .. }) => {
561                let texture = self.external_images
562                    .get(index)
563                    .expect("BUG: External image should be resolved by now");
564                texture.get_uv_rect()
565            }
566            _ => {
567                default_value
568            }
569        }
570    }
571
572    /// Returns the size of the texture in pixels
573    fn get_texture_size(&self, texture: &TextureSource) -> DeviceIntSize {
574        match *texture {
575            TextureSource::Invalid => DeviceIntSize::zero(),
576            TextureSource::TextureCache(id, _) => {
577                self.texture_cache_map[&id].texture.get_dimensions()
578            },
579            TextureSource::External(TextureSourceExternal { index, .. }) => {
580                // If UV coords are normalized then this value will be incorrect. However, the
581                // texture size is currently only used to set the uTextureSize uniform, so that
582                // shaders without access to textureSize() can normalize unnormalized UVs. Which
583                // means this is not a problem.
584                let uv_rect = self.external_images[&index].get_uv_rect();
585                (uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32()
586            },
587            TextureSource::Dummy => DeviceIntSize::new(1, 1),
588        }
589    }
590
591    fn report_memory(&self) -> MemoryReport {
592        let mut report = MemoryReport::default();
593
594        // We're reporting GPU memory rather than heap-allocations, so we don't
595        // use size_of_op.
596        for item in self.texture_cache_map.values() {
597            let counter = match item.category {
598                TextureCacheCategory::Atlas => &mut report.atlas_textures,
599                TextureCacheCategory::Standalone => &mut report.standalone_textures,
600                TextureCacheCategory::PictureTile => &mut report.picture_tile_textures,
601                TextureCacheCategory::RenderTarget => &mut report.render_target_textures,
602            };
603            *counter += item.texture.size_in_bytes();
604        }
605
606        report
607    }
608
609    fn update_profile(&self, profile: &mut TransactionProfile) {
610        let mut external_image_bytes = 0;
611        for img in self.external_images.values() {
612            let uv_rect = img.get_uv_rect();
613            // If UV coords are normalized then this value will be incorrect. This is unfortunate
614            // but doesn't impact end users at all.
615            let size = (uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32();
616
617            // Assume 4 bytes per pixels which is true most of the time but
618            // not always.
619            let bpp = 4;
620            external_image_bytes += size.area() as usize * bpp;
621        }
622
623        profile.set(profiler::EXTERNAL_IMAGE_BYTES, profiler::bytes_to_mb(external_image_bytes));
624    }
625
626    fn get_cache_texture_mut(&mut self, id: &CacheTextureId) -> &mut Texture {
627        &mut self.texture_cache_map
628            .get_mut(id)
629            .expect("bug: texture not allocated")
630            .texture
631    }
632}
633
634#[derive(Debug, Copy, Clone, PartialEq)]
635#[cfg_attr(feature = "capture", derive(Serialize))]
636#[cfg_attr(feature = "replay", derive(Deserialize))]
637pub enum BlendMode {
638    None,
639    Alpha,
640    PremultipliedAlpha,
641    PremultipliedDestOut,
642    SubpixelDualSource,
643    Advanced(MixBlendMode),
644    MultiplyDualSource,
645    Screen,
646    Exclusion,
647    PlusLighter,
648}
649
650impl BlendMode {
651    /// Decides when a given mix-blend-mode can be implemented in terms of
652    /// simple blending, dual-source blending, advanced blending, or not at
653    /// all based on available capabilities.
654    pub fn from_mix_blend_mode(
655        mode: MixBlendMode,
656        advanced_blend: bool,
657        coherent: bool,
658        dual_source: bool,
659    ) -> Option<BlendMode> {
660        // If we emulate a mix-blend-mode via simple or dual-source blending,
661        // care must be taken to output alpha As + Ad*(1-As) regardless of what
662        // the RGB output is to comply with the mix-blend-mode spec.
663        Some(match mode {
664            // If we have coherent advanced blend, just use that.
665            _ if advanced_blend && coherent => BlendMode::Advanced(mode),
666            // Screen can be implemented as Cs + Cd - Cs*Cd => Cs + Cd*(1-Cs)
667            MixBlendMode::Screen => BlendMode::Screen,
668            // Exclusion can be implemented as Cs + Cd - 2*Cs*Cd => Cs*(1-Cd) + Cd*(1-Cs)
669            MixBlendMode::Exclusion => BlendMode::Exclusion,
670            // PlusLighter is basically a clamped add.
671            MixBlendMode::PlusLighter => BlendMode::PlusLighter,
672            // Multiply can be implemented as Cs*Cd + Cs*(1-Ad) + Cd*(1-As) => Cs*(1-Ad) + Cd*(1 - SRC1=(As-Cs))
673            MixBlendMode::Multiply if dual_source => BlendMode::MultiplyDualSource,
674            // Otherwise, use advanced blend without coherency if available.
675            _ if advanced_blend => BlendMode::Advanced(mode),
676            // If advanced blend is not available, then we have to use brush_mix_blend.
677            _ => return None,
678        })
679    }
680}
681
682/// Information about the state of the debugging / profiler overlay in native compositing mode.
683struct DebugOverlayState {
684    /// True if any of the current debug flags will result in drawing a debug overlay.
685    is_enabled: bool,
686
687    /// The current size of the debug overlay surface. None implies that the
688    /// debug surface isn't currently allocated.
689    current_size: Option<DeviceIntSize>,
690
691    layer_index: usize,
692}
693
694impl DebugOverlayState {
695    fn new() -> Self {
696        DebugOverlayState {
697            is_enabled: false,
698            current_size: None,
699            layer_index: 0,
700        }
701    }
702}
703
704/// Tracks buffer damage rects over a series of frames.
705#[derive(Debug, Default)]
706pub(crate) struct BufferDamageTracker {
707    damage_rects: [DeviceRect; 4],
708    current_offset: usize,
709}
710
711impl BufferDamageTracker {
712    /// Sets the damage rect for the current frame. Should only be called *after*
713    /// get_damage_rect() has been called to get the current backbuffer's damage rect.
714    fn push_dirty_rect(&mut self, rect: &DeviceRect) {
715        self.damage_rects[self.current_offset] = rect.clone();
716        self.current_offset = match self.current_offset {
717            0 => self.damage_rects.len() - 1,
718            n => n - 1,
719        }
720    }
721
722    /// Gets the damage rect for the current backbuffer, given the backbuffer's age.
723    /// (The number of frames since it was previously the backbuffer.)
724    /// Returns an empty rect if the buffer is valid, and None if the entire buffer is invalid.
725    fn get_damage_rect(&self, buffer_age: usize) -> Option<DeviceRect> {
726        match buffer_age {
727            // 0 means this is a new buffer, so is completely invalid.
728            0 => None,
729            // 1 means this backbuffer was also the previous frame's backbuffer
730            // (so must have been copied to the frontbuffer). It is therefore entirely valid.
731            1 => Some(DeviceRect::zero()),
732            // We must calculate the union of the damage rects since this buffer was previously
733            // the backbuffer.
734            n if n <= self.damage_rects.len() + 1 => {
735                Some(
736                    self.damage_rects.iter()
737                        .cycle()
738                        .skip(self.current_offset + 1)
739                        .take(n - 1)
740                        .fold(DeviceRect::zero(), |acc, r| acc.union(r))
741                )
742            }
743            // The backbuffer is older than the number of frames for which we track,
744            // so we treat it as entirely invalid.
745            _ => None,
746        }
747    }
748}
749
750/// The renderer is responsible for submitting to the GPU the work prepared by the
751/// RenderBackend.
752///
753/// We have a separate `Renderer` instance for each instance of WebRender (generally
754/// one per OS window), and all instances share the same thread.
755pub struct Renderer {
756    result_rx: Receiver<ResultMsg>,
757    api_tx: Sender<ApiMsg>,
758    pub device: Device,
759    pending_texture_updates: Vec<TextureUpdateList>,
760    /// True if there are any TextureCacheUpdate pending.
761    pending_texture_cache_updates: bool,
762    pending_native_surface_updates: Vec<NativeSurfaceOperation>,
763    pending_shader_updates: Vec<PathBuf>,
764    active_documents: FastHashMap<DocumentId, RenderedDocument>,
765
766    shaders: Rc<RefCell<Shaders>>,
767
768    max_recorded_profiles: usize,
769
770    clear_color: ColorF,
771    enable_clear_scissor: bool,
772    enable_advanced_blend_barriers: bool,
773    clear_caches_with_quads: bool,
774    clear_alpha_targets_with_quads: bool,
775
776    debug: debug::LazyInitializedDebugRenderer,
777    debug_flags: DebugFlags,
778    profile: TransactionProfile,
779    frame_counter: u64,
780    resource_upload_time: f64,
781    profiler: Profiler,
782    command_log: Option<RenderCommandLog>,
783    #[cfg(feature = "debugger")]
784    debugger: Debugger,
785
786    last_time: u64,
787
788    pub gpu_profiler: GpuProfiler,
789    vaos: vertex::RendererVAOs,
790
791    gpu_buffer_texture_f: Option<Texture>,
792    gpu_buffer_texture_f_too_large: i32,
793    gpu_buffer_texture_i: Option<Texture>,
794    gpu_buffer_texture_i_too_large: i32,
795    vertex_data_textures: Vec<vertex::VertexDataTextures>,
796    current_vertex_data_textures: usize,
797
798    pipeline_info: PipelineInfo,
799
800    // Manages and resolves source textures IDs to real texture IDs.
801    texture_resolver: TextureResolver,
802
803    texture_upload_pbo_pool: UploadPBOPool,
804    staging_texture_pool: UploadTexturePool,
805
806    dither_matrix_texture: Option<Texture>,
807
808    /// Optional trait object that allows the client
809    /// application to provide external buffers for image data.
810    external_image_handler: Option<Box<dyn ExternalImageHandler>>,
811
812    /// Optional function pointers for measuring memory used by a given
813    /// heap-allocated pointer.
814    size_of_ops: Option<MallocSizeOfOps>,
815
816    pub renderer_errors: Vec<RendererError>,
817
818    pub(in crate) async_frame_recorder: Option<AsyncScreenshotGrabber>,
819    pub(in crate) async_screenshots: Option<AsyncScreenshotGrabber>,
820
821    /// List of profile results from previous frames. Can be retrieved
822    /// via get_frame_profiles().
823    cpu_profiles: VecDeque<CpuProfile>,
824    gpu_profiles: VecDeque<GpuProfile>,
825
826    /// Notification requests to be fulfilled after rendering.
827    notifications: Vec<NotificationRequest>,
828
829    device_size: Option<DeviceIntSize>,
830
831    /// A lazily created texture for the zoom debugging widget.
832    zoom_debug_texture: Option<Texture>,
833
834    /// The current mouse position. This is used for debugging
835    /// functionality only, such as the debug zoom widget.
836    cursor_position: DeviceIntPoint,
837
838    /// Guards to check if we might be rendering a frame with expired texture
839    /// cache entries.
840    shared_texture_cache_cleared: bool,
841
842    /// The set of documents which we've seen a publish for since last render.
843    documents_seen: FastHashSet<DocumentId>,
844
845    #[cfg(feature = "capture")]
846    read_fbo: FBOId,
847    #[cfg(feature = "replay")]
848    owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
849
850    /// The compositing config, affecting how WR composites into the final scene.
851    compositor_config: CompositorConfig,
852    current_compositor_kind: CompositorKind,
853
854    /// Maintains a set of allocated native composite surfaces. This allows any
855    /// currently allocated surfaces to be cleaned up as soon as deinit() is
856    /// called (the normal bookkeeping for native surfaces exists in the
857    /// render backend thread).
858    allocated_native_surfaces: FastHashSet<NativeSurfaceId>,
859
860    /// If true, partial present state has been reset and everything needs to
861    /// be drawn on the next render.
862    force_redraw: bool,
863
864    /// State related to the debug / profiling overlays
865    debug_overlay_state: DebugOverlayState,
866
867    /// Tracks the dirty rectangles from previous frames. Used on platforms
868    /// that require keeping the front buffer fully correct when doing
869    /// partial present (e.g. unix desktop with EGL_EXT_buffer_age).
870    buffer_damage_tracker: BufferDamageTracker,
871
872    max_primitive_instance_count: usize,
873    enable_instancing: bool,
874
875    /// Count consecutive oom frames to detectif we are stuck unable to render
876    /// in a loop.
877    consecutive_oom_frames: u32,
878
879    /// update() defers processing of ResultMsg, if frame_publish_id of
880    /// ResultMsg::PublishDocument exceeds target_frame_publish_id.
881    target_frame_publish_id: Option<FramePublishId>,
882
883    /// Hold a next ResultMsg that will be handled by update().
884    pending_result_msg: Option<ResultMsg>,
885
886    /// Hold previous frame compositing state with layer compositor.
887    layer_compositor_frame_state_in_prev_frame: Option<LayerCompositorFrameState>,
888
889    /// Hold DebugItems of DebugFlags::EXTERNAL_COMPOSITE_BORDERS for debug overlay
890    external_composite_debug_items: Vec<DebugItem>,
891}
892
893#[derive(Debug)]
894pub enum RendererError {
895    Shader(ShaderError),
896    Thread(std::io::Error),
897    MaxTextureSize,
898    SoftwareRasterizer,
899    OutOfMemory,
900}
901
902impl From<ShaderError> for RendererError {
903    fn from(err: ShaderError) -> Self {
904        RendererError::Shader(err)
905    }
906}
907
908impl From<std::io::Error> for RendererError {
909    fn from(err: std::io::Error) -> Self {
910        RendererError::Thread(err)
911    }
912}
913
914impl Renderer {
915    pub fn device_size(&self) -> Option<DeviceIntSize> {
916        self.device_size
917    }
918
919    /// Update the current position of the debug cursor.
920    pub fn set_cursor_position(
921        &mut self,
922        position: DeviceIntPoint,
923    ) {
924        self.cursor_position = position;
925    }
926
927    pub fn get_max_texture_size(&self) -> i32 {
928        self.device.max_texture_size()
929    }
930
931    pub fn get_graphics_api_info(&self) -> GraphicsApiInfo {
932        GraphicsApiInfo {
933            kind: GraphicsApi::OpenGL,
934            version: self.device.gl().get_string(gl::VERSION),
935            renderer: self.device.gl().get_string(gl::RENDERER),
936        }
937    }
938
939    pub fn preferred_color_format(&self) -> ImageFormat {
940        self.device.preferred_color_formats().external
941    }
942
943    pub fn required_texture_stride_alignment(&self, format: ImageFormat) -> usize {
944        self.device.required_pbo_stride().num_bytes(format).get()
945    }
946
947    pub fn set_clear_color(&mut self, color: ColorF) {
948        self.clear_color = color;
949    }
950
951    pub fn flush_pipeline_info(&mut self) -> PipelineInfo {
952        mem::replace(&mut self.pipeline_info, PipelineInfo::default())
953    }
954
955    /// Returns the Epoch of the current frame in a pipeline.
956    pub fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option<Epoch> {
957        self.pipeline_info.epochs.get(&(pipeline_id, document_id)).cloned()
958    }
959
960    fn get_next_result_msg(&mut self) -> Option<ResultMsg> {
961        if self.pending_result_msg.is_none() {
962            if let Ok(msg) = self.result_rx.try_recv() {
963                self.pending_result_msg = Some(msg);
964            }
965        }
966
967        match (&self.pending_result_msg, &self.target_frame_publish_id) {
968          (Some(ResultMsg::PublishDocument(frame_publish_id, _, _, _)), Some(target_id)) => {
969            if frame_publish_id > target_id {
970              return None;
971            }
972          }
973          _ => {}
974        }
975
976        self.pending_result_msg.take()
977    }
978
979    /// Processes the result queue.
980    ///
981    /// Should be called before `render()`, as texture cache updates are done here.
982    pub fn update(&mut self) {
983        profile_scope!("update");
984
985        // Pull any pending results and return the most recent.
986        while let Some(msg) = self.get_next_result_msg() {
987            match msg {
988                ResultMsg::PublishPipelineInfo(mut pipeline_info) => {
989                    for ((pipeline_id, document_id), epoch) in pipeline_info.epochs {
990                        self.pipeline_info.epochs.insert((pipeline_id, document_id), epoch);
991                    }
992                    self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..));
993                }
994                ResultMsg::PublishDocument(
995                    _,
996                    document_id,
997                    mut doc,
998                    resource_update_list,
999                ) => {
1000                    // Add a new document to the active set
1001
1002                    // If the document we are replacing must be drawn (in order to
1003                    // update the texture cache), issue a render just to
1004                    // off-screen targets, ie pass None to render_impl. We do this
1005                    // because a) we don't need to render to the main framebuffer
1006                    // so it is cheaper not to, and b) doing so without a
1007                    // subsequent present would break partial present.
1008                    let prev_frame_memory = if let Some(mut prev_doc) = self.active_documents.remove(&document_id) {
1009                        doc.profile.merge(&mut prev_doc.profile);
1010
1011                        if prev_doc.frame.must_be_drawn() {
1012                            prev_doc.render_reasons |= RenderReasons::TEXTURE_CACHE_FLUSH;
1013                            self.render_impl(
1014                                document_id,
1015                                &mut prev_doc,
1016                                None,
1017                                0,
1018                            ).ok();
1019                        }
1020
1021                        Some(prev_doc.frame.allocator_memory)
1022                    } else {
1023                        None
1024                    };
1025
1026                    if let Some(memory) = prev_frame_memory {
1027                        // We just dropped the frame a few lives above. There should be no
1028                        // live allocations left in the frame's memory.
1029                        memory.assert_memory_reusable();
1030                    }
1031
1032                    self.active_documents.insert(document_id, doc);
1033
1034                    // IMPORTANT: The pending texture cache updates must be applied
1035                    //            *after* the previous frame has been rendered above
1036                    //            (if neceessary for a texture cache update). For
1037                    //            an example of why this is required:
1038                    //            1) Previous frame contains a render task that
1039                    //               targets Texture X.
1040                    //            2) New frame contains a texture cache update which
1041                    //               frees Texture X.
1042                    //            3) bad stuff happens.
1043
1044                    //TODO: associate `document_id` with target window
1045                    self.pending_texture_cache_updates |= !resource_update_list.texture_updates.updates.is_empty();
1046                    self.pending_texture_updates.push(resource_update_list.texture_updates);
1047                    self.pending_native_surface_updates.extend(resource_update_list.native_surface_updates);
1048                    self.documents_seen.insert(document_id);
1049                }
1050                ResultMsg::UpdateResources {
1051                    resource_updates,
1052                    memory_pressure,
1053                } => {
1054                    if memory_pressure {
1055                        // If a memory pressure event arrives _after_ a new scene has
1056                        // been published that writes persistent targets (i.e. cached
1057                        // render tasks to the texture cache, or picture cache tiles)
1058                        // but _before_ the next update/render loop, those targets
1059                        // will not be updated due to the active_documents list being
1060                        // cleared at the end of this message. To work around that,
1061                        // if any of the existing documents have not rendered yet, and
1062                        // have picture/texture cache targets, force a render so that
1063                        // those targets are updated.
1064                        let active_documents = mem::replace(
1065                            &mut self.active_documents,
1066                            FastHashMap::default(),
1067                        );
1068                        for (doc_id, mut doc) in active_documents {
1069                            if doc.frame.must_be_drawn() {
1070                                // As this render will not be presented, we must pass None to
1071                                // render_impl. This avoids interfering with partial present
1072                                // logic, as well as being more efficient.
1073                                self.render_impl(
1074                                    doc_id,
1075                                    &mut doc,
1076                                    None,
1077                                    0,
1078                                ).ok();
1079                            }
1080                        }
1081                    }
1082
1083                    self.pending_texture_cache_updates |= !resource_updates.texture_updates.updates.is_empty();
1084                    self.pending_texture_updates.push(resource_updates.texture_updates);
1085                    self.pending_native_surface_updates.extend(resource_updates.native_surface_updates);
1086                    self.device.begin_frame();
1087
1088                    self.update_texture_cache();
1089                    self.update_native_surfaces();
1090
1091                    // Flush the render target pool on memory pressure.
1092                    //
1093                    // This needs to be separate from the block below because
1094                    // the device module asserts if we delete textures while
1095                    // not in a frame.
1096                    if memory_pressure {
1097                        self.texture_upload_pbo_pool.on_memory_pressure(&mut self.device);
1098                        self.staging_texture_pool.delete_textures(&mut self.device);
1099                        if let Some(texture) = self.gpu_buffer_texture_f.take() {
1100                            self.device.delete_texture(texture);
1101                        }
1102                        if let Some(texture) = self.gpu_buffer_texture_i.take() {
1103                            self.device.delete_texture(texture);
1104                        }
1105                    }
1106
1107                    self.device.end_frame();
1108                }
1109                ResultMsg::RenderDocumentOffscreen(document_id, mut offscreen_doc, resources) => {
1110                    // Flush pending operations if needed (See comment in the match arm for
1111                    // PublishPipelineInfo).
1112
1113                    // Borrow-ck dance.
1114                    let prev_doc = self.active_documents.remove(&document_id);
1115                    if let Some(mut prev_doc) = prev_doc {
1116                        if prev_doc.frame.must_be_drawn() {
1117                            prev_doc.render_reasons |= RenderReasons::TEXTURE_CACHE_FLUSH;
1118                            self.render_impl(
1119                                document_id,
1120                                &mut prev_doc,
1121                                None,
1122                                0,
1123                            ).ok();
1124                        }
1125
1126                        self.active_documents.insert(document_id, prev_doc);
1127                    }
1128
1129                    // Now update resources and render the offscreen frame.
1130
1131                    self.pending_texture_cache_updates |= !resources.texture_updates.updates.is_empty();
1132                    self.pending_texture_updates.push(resources.texture_updates);
1133                    self.pending_native_surface_updates.extend(resources.native_surface_updates);
1134
1135                    self.render_impl(
1136                        document_id,
1137                        &mut offscreen_doc,
1138                        None,
1139                        0,
1140                    ).unwrap();
1141                }
1142                ResultMsg::AppendNotificationRequests(mut notifications) => {
1143                    // We need to know specifically if there are any pending
1144                    // TextureCacheUpdate updates in any of the entries in
1145                    // pending_texture_updates. They may simply be nops, which do not
1146                    // need to prevent issuing the notification, and if so, may not
1147                    // cause a timely frame render to occur to wake up any listeners.
1148                    if !self.pending_texture_cache_updates {
1149                        drain_filter(
1150                            &mut notifications,
1151                            |n| { n.when() == Checkpoint::FrameTexturesUpdated },
1152                            |n| { n.notify(); },
1153                        );
1154                    }
1155                    self.notifications.append(&mut notifications);
1156                }
1157                ResultMsg::ForceRedraw => {
1158                    self.force_redraw = true;
1159                }
1160                ResultMsg::RefreshShader(path) => {
1161                    self.pending_shader_updates.push(path);
1162                }
1163                ResultMsg::SetParameter(ref param) => {
1164                    self.device.set_parameter(param);
1165                    self.profiler.set_parameter(param);
1166                }
1167                ResultMsg::DebugOutput(output) => match output {
1168                    #[cfg(feature = "capture")]
1169                    DebugOutput::SaveCapture(config, deferred) => {
1170                        self.save_capture(config, deferred);
1171                    }
1172                    #[cfg(feature = "replay")]
1173                    DebugOutput::LoadCapture(config, plain_externals) => {
1174                        self.active_documents.clear();
1175                        self.load_capture(config, plain_externals);
1176                    }
1177                },
1178                ResultMsg::DebugCommand(command) => {
1179                    self.handle_debug_command(command);
1180                }
1181            }
1182        }
1183    }
1184
1185    /// update() defers processing of ResultMsg, if frame_publish_id of
1186    /// ResultMsg::PublishDocument exceeds target_frame_publish_id.
1187    pub fn set_target_frame_publish_id(&mut self, publish_id: FramePublishId) {
1188        self.target_frame_publish_id = Some(publish_id);
1189    }
1190
1191    fn handle_debug_command(&mut self, command: DebugCommand) {
1192        match command {
1193            DebugCommand::SetPictureTileSize(_) |
1194            DebugCommand::SetMaximumSurfaceSize(_) |
1195            DebugCommand::GenerateFrame => {
1196                panic!("Should be handled by render backend");
1197            }
1198            #[cfg(feature = "debugger")]
1199            DebugCommand::Query(ref query) => {
1200                match query.kind {
1201                    DebugQueryKind::SpatialTree { .. } => {
1202                        panic!("Should be handled by render backend");
1203                    }
1204                    DebugQueryKind::CompositorConfig { .. } => {
1205                        let result = match self.active_documents.iter().last() {
1206                            Some((_, doc)) => {
1207                                doc.frame.composite_state.print_to_string()
1208                            }
1209                            None => {
1210                                "No active documents".into()
1211                            }
1212                        };
1213                        query.result.send(result).ok();
1214                    }
1215                    DebugQueryKind::CompositorView { .. } => {
1216                        let result = match self.active_documents.iter().last() {
1217                            Some((_, doc)) => {
1218                                let info = CompositorDebugInfo::from(&doc.frame.composite_state);
1219                                serde_json::to_string(&info).unwrap()
1220                            }
1221                            None => {
1222                                "No active documents".into()
1223                            }
1224                        };
1225                        query.result.send(result).ok();
1226                    }
1227                    DebugQueryKind::Textures { category } => {
1228                        let mut texture_list = Vec::new();
1229
1230                        self.device.begin_frame();
1231                        self.device.bind_read_target_impl(self.read_fbo, DeviceIntPoint::zero());
1232
1233                        for (id, item) in &self.texture_resolver.texture_cache_map {
1234                            if category.is_some() && category != Some(item.category) {
1235                                continue;
1236                            }
1237
1238                            let size = item.texture.get_dimensions();
1239                            let format = item.texture.get_format();
1240                            let buffer_size = (size.area() * format.bytes_per_pixel()) as usize;
1241                            let mut data = vec![0u8; buffer_size];
1242                            let rect = size.cast_unit().into();
1243                            self.device.attach_read_texture(&item.texture);
1244                            self.device.read_pixels_into(rect, format, &mut data);
1245
1246                            let category_str = match item.category {
1247                                TextureCacheCategory::Atlas => "atlas",
1248                                TextureCacheCategory::Standalone => "standalone",
1249                                TextureCacheCategory::PictureTile => "tile",
1250                                TextureCacheCategory::RenderTarget => "target",
1251                            };
1252
1253                            let texture_msg = DebuggerTextureContent {
1254                                name: format!("{category_str}-{:02}", id.0),
1255                                category: item.category,
1256                                width: size.width as u32,
1257                                height: size.height as u32,
1258                                format,
1259                                data,
1260                            };
1261                            texture_list.push(texture_msg);
1262                        }
1263                        self.device.reset_read_target();
1264                        self.device.end_frame();
1265
1266                        query.result.send(serde_json::to_string(&texture_list).unwrap()).ok();
1267                    }
1268                }
1269            }
1270            DebugCommand::SaveCapture(..) |
1271            DebugCommand::LoadCapture(..) |
1272            DebugCommand::StartCaptureSequence(..) |
1273            DebugCommand::StopCaptureSequence => {
1274                panic!("Capture commands are not welcome here! Did you build with 'capture' feature?")
1275            }
1276            DebugCommand::ClearCaches(_)
1277            | DebugCommand::SimulateLongSceneBuild(_)
1278            | DebugCommand::EnableNativeCompositor(_)
1279            | DebugCommand::SetBatchingLookback(_) => {}
1280            DebugCommand::SetFlags(flags) => {
1281                self.set_debug_flags(flags);
1282            }
1283            DebugCommand::GetDebugFlags(tx) => {
1284                tx.send(self.debug_flags).unwrap();
1285            }
1286            DebugCommand::SetRenderCommandLog(enabled) => {
1287                if enabled && self.command_log.is_none() {
1288                    self.command_log = Some(RenderCommandLog::new());
1289                } else if !enabled {
1290                    self.command_log = None;
1291                }
1292            }
1293            #[cfg(feature = "debugger")]
1294            DebugCommand::AddDebugClient(client) => {
1295                self.debugger.add_client(
1296                    client,
1297                    self.debug_flags,
1298                    &self.profiler,
1299                );
1300            }
1301        }
1302    }
1303
1304    /// Set a callback for handling external images.
1305    pub fn set_external_image_handler(&mut self, handler: Box<dyn ExternalImageHandler>) {
1306        self.external_image_handler = Some(handler);
1307    }
1308
1309    /// Retrieve (and clear) the current list of recorded frame profiles.
1310    pub fn get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>) {
1311        let cpu_profiles = self.cpu_profiles.drain(..).collect();
1312        let gpu_profiles = self.gpu_profiles.drain(..).collect();
1313        (cpu_profiles, gpu_profiles)
1314    }
1315
1316    /// Reset the current partial present state. This forces the entire framebuffer
1317    /// to be refreshed next time `render` is called.
1318    pub fn force_redraw(&mut self) {
1319        self.force_redraw = true;
1320    }
1321
1322    /// Renders the current frame.
1323    ///
1324    /// A Frame is supplied by calling [`generate_frame()`][webrender_api::Transaction::generate_frame].
1325    /// buffer_age is the age of the current backbuffer. It is only relevant if partial present
1326    /// is active, otherwise 0 should be passed here.
1327    pub fn render(
1328        &mut self,
1329        device_size: DeviceIntSize,
1330        buffer_age: usize,
1331    ) -> Result<RenderResults, Vec<RendererError>> {
1332        self.device_size = Some(device_size);
1333
1334        // TODO(gw): We want to make the active document that is
1335        //           being rendered configurable via the public
1336        //           API in future. For now, just select the last
1337        //           added document as the active one to render
1338        //           (Gecko only ever creates a single document
1339        //           per renderer right now).
1340        let doc_id = self.active_documents.keys().last().cloned();
1341
1342        let result = match doc_id {
1343            Some(doc_id) => {
1344                // Remove the doc from the map to appease the borrow checker
1345                let mut doc = self.active_documents
1346                    .remove(&doc_id)
1347                    .unwrap();
1348
1349                let size = if !device_size.is_empty() {
1350                    Some(device_size)
1351                } else {
1352                    None
1353                };
1354
1355                let result = self.render_impl(
1356                    doc_id,
1357                    &mut doc,
1358                    size,
1359                    buffer_age,
1360                );
1361
1362                self.active_documents.insert(doc_id, doc);
1363
1364                result
1365            }
1366            None => {
1367                self.last_time = zeitstempel::now();
1368                Ok(RenderResults::default())
1369            }
1370        };
1371
1372        drain_filter(
1373            &mut self.notifications,
1374            |n| { n.when() == Checkpoint::FrameRendered },
1375            |n| { n.notify(); },
1376        );
1377
1378        let mut oom = false;
1379        if let Err(ref errors) = result {
1380            for error in errors {
1381                if matches!(error, &RendererError::OutOfMemory) {
1382                    oom = true;
1383                    break;
1384                }
1385            }
1386        }
1387
1388        if oom {
1389            let _ = self.api_tx.send(ApiMsg::MemoryPressure);
1390            // Ensure we don't get stuck in a loop.
1391            self.consecutive_oom_frames += 1;
1392            assert!(self.consecutive_oom_frames < 5, "Renderer out of memory");
1393        } else {
1394            self.consecutive_oom_frames = 0;
1395        }
1396
1397        // This is the end of the rendering pipeline. If some notifications are is still there,
1398        // just clear them and they will autimatically fire the Checkpoint::TransactionDropped
1399        // event. Otherwise they would just pile up in this vector forever.
1400        self.notifications.clear();
1401
1402        self.external_composite_debug_items = Vec::new();
1403
1404        tracy_frame_marker!();
1405
1406        result
1407    }
1408
1409    /// Update the state of any debug / profiler overlays. This is currently only needed
1410    /// when running with the native compositor enabled.
1411    fn update_debug_overlay(
1412        &mut self,
1413        framebuffer_size: DeviceIntSize,
1414        has_debug_items: bool,
1415    ) {
1416        // If any of the following debug flags are set, something will be drawn on the debug overlay.
1417        self.debug_overlay_state.is_enabled = has_debug_items || self.debug_flags.intersects(
1418            DebugFlags::PROFILER_DBG |
1419            DebugFlags::RENDER_TARGET_DBG |
1420            DebugFlags::TEXTURE_CACHE_DBG |
1421            DebugFlags::EPOCHS |
1422            DebugFlags::PICTURE_CACHING_DBG |
1423            DebugFlags::PICTURE_BORDERS |
1424            DebugFlags::ZOOM_DBG |
1425            DebugFlags::WINDOW_VISIBILITY_DBG |
1426            DebugFlags::EXTERNAL_COMPOSITE_BORDERS
1427        );
1428
1429        // Update the debug overlay surface, if we are running in native compositor mode.
1430        if let CompositorKind::Native { .. } = self.current_compositor_kind {
1431            let compositor = self.compositor_config.compositor().unwrap();
1432
1433            // If there is a current surface, destroy it if we don't need it for this frame, or if
1434            // the size has changed.
1435            if let Some(current_size) = self.debug_overlay_state.current_size {
1436                if !self.debug_overlay_state.is_enabled || current_size != framebuffer_size {
1437                    compositor.destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
1438                    self.debug_overlay_state.current_size = None;
1439                }
1440            }
1441
1442            // Allocate a new surface, if we need it and there isn't one.
1443            if self.debug_overlay_state.is_enabled && self.debug_overlay_state.current_size.is_none() {
1444                compositor.create_surface(
1445                    &mut self.device,
1446                    NativeSurfaceId::DEBUG_OVERLAY,
1447                    DeviceIntPoint::zero(),
1448                    framebuffer_size,
1449                    false,
1450                );
1451                compositor.create_tile(
1452                    &mut self.device,
1453                    NativeTileId::DEBUG_OVERLAY,
1454                );
1455                self.debug_overlay_state.current_size = Some(framebuffer_size);
1456            }
1457        }
1458    }
1459
1460    /// Bind a draw target for the debug / profiler overlays, if required.
1461    fn bind_debug_overlay(&mut self, device_size: DeviceIntSize) -> Option<DrawTarget> {
1462        // Debug overlay setup are only required in native compositing mode
1463        if self.debug_overlay_state.is_enabled {
1464            match self.current_compositor_kind {
1465                CompositorKind::Native { .. } => {
1466                    let compositor = self.compositor_config.compositor().unwrap();
1467                    let surface_size = self.debug_overlay_state.current_size.unwrap();
1468
1469                    // Ensure old surface is invalidated before binding
1470                    compositor.invalidate_tile(
1471                        &mut self.device,
1472                        NativeTileId::DEBUG_OVERLAY,
1473                        DeviceIntRect::from_size(surface_size),
1474                    );
1475                    // Bind the native surface
1476                    let surface_info = compositor.bind(
1477                        &mut self.device,
1478                        NativeTileId::DEBUG_OVERLAY,
1479                        DeviceIntRect::from_size(surface_size),
1480                        DeviceIntRect::from_size(surface_size),
1481                    );
1482
1483                    // Bind the native surface to current FBO target
1484                    let draw_target = DrawTarget::NativeSurface {
1485                        offset: surface_info.origin,
1486                        external_fbo_id: surface_info.fbo_id,
1487                        dimensions: surface_size,
1488                    };
1489                    self.device.bind_draw_target(draw_target);
1490
1491                    // When native compositing, clear the debug overlay each frame.
1492                    self.device.clear_target(
1493                        Some([0.0, 0.0, 0.0, 0.0]),
1494                        None, // debug renderer does not use depth
1495                        None,
1496                    );
1497
1498                    Some(draw_target)
1499                }
1500                CompositorKind::Layer { .. } => {
1501                    let compositor = self.compositor_config.layer_compositor().unwrap();
1502                    compositor.bind_layer(self.debug_overlay_state.layer_index, &[]);
1503
1504                    self.device.clear_target(
1505                        Some([0.0, 0.0, 0.0, 0.0]),
1506                        None, // debug renderer does not use depth
1507                        None,
1508                    );
1509
1510                    Some(DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left()))
1511                }
1512                CompositorKind::Draw { .. } => {
1513                    // If we're not using the native compositor, then the default
1514                    // frame buffer is already bound. Create a DrawTarget for it and
1515                    // return it.
1516                    Some(DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left()))
1517                }
1518            }
1519        } else {
1520            None
1521        }
1522    }
1523
1524    /// Unbind the draw target for debug / profiler overlays, if required.
1525    fn unbind_debug_overlay(&mut self) {
1526        // Debug overlay setup are only required in native compositing mode
1527        if self.debug_overlay_state.is_enabled {
1528            match self.current_compositor_kind {
1529                CompositorKind::Native { .. } => {
1530                    let compositor = self.compositor_config.compositor().unwrap();
1531                    // Unbind the draw target and add it to the visual tree to be composited
1532                    compositor.unbind(&mut self.device);
1533
1534                    let clip_rect = DeviceIntRect::from_size(
1535                        self.debug_overlay_state.current_size.unwrap(),
1536                    );
1537
1538                    compositor.add_surface(
1539                        &mut self.device,
1540                        NativeSurfaceId::DEBUG_OVERLAY,
1541                        CompositorSurfaceTransform::identity(),
1542                        clip_rect,
1543                        ImageRendering::Auto,
1544                        clip_rect,
1545                        ClipRadius::EMPTY,
1546                    );
1547                }
1548                CompositorKind::Draw { .. } => {}
1549                CompositorKind::Layer { .. } => {
1550                    let compositor = self.compositor_config.layer_compositor().unwrap();
1551                    compositor.present_layer(self.debug_overlay_state.layer_index, &[]);
1552                }
1553            }
1554        }
1555    }
1556
1557    // If device_size is None, don't render to the main frame buffer. This is useful to
1558    // update texture cache render tasks but avoid doing a full frame render. If the
1559    // render is not going to be presented, then this must be set to None, as performing a
1560    // composite without a present will confuse partial present.
1561    fn render_impl(
1562        &mut self,
1563        doc_id: DocumentId,
1564        active_doc: &mut RenderedDocument,
1565        mut device_size: Option<DeviceIntSize>,
1566        buffer_age: usize,
1567    ) -> Result<RenderResults, Vec<RendererError>> {
1568        profile_scope!("render");
1569        let mut results = RenderResults::default();
1570        self.profile.end_time_if_started(profiler::FRAME_SEND_TIME);
1571        self.profile.start_time(profiler::RENDERER_TIME);
1572
1573        if let Some(log) = &mut self.command_log {
1574            log.clear();
1575        }
1576
1577        self.staging_texture_pool.begin_frame();
1578
1579        let compositor_kind = active_doc.frame.composite_state.compositor_kind;
1580        // CompositorKind is updated
1581        if self.current_compositor_kind != compositor_kind {
1582            let enable = match (self.current_compositor_kind, compositor_kind) {
1583                (CompositorKind::Native { .. }, CompositorKind::Draw { .. }) => {
1584                    if self.debug_overlay_state.current_size.is_some() {
1585                        self.compositor_config
1586                            .compositor()
1587                            .unwrap()
1588                            .destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
1589                        self.debug_overlay_state.current_size = None;
1590                    }
1591                    false
1592                }
1593                (CompositorKind::Draw { .. }, CompositorKind::Native { .. }) => {
1594                    true
1595                }
1596                (current_compositor_kind, active_doc_compositor_kind) => {
1597                    warn!("Compositor mismatch, assuming this is Wrench running. Current {:?}, active {:?}",
1598                        current_compositor_kind, active_doc_compositor_kind);
1599                    false
1600                }
1601            };
1602
1603            if let Some(config) = self.compositor_config.compositor() {
1604                config.enable_native_compositor(&mut self.device, enable);
1605            }
1606            self.current_compositor_kind = compositor_kind;
1607        }
1608
1609        // The texture resolver scope should be outside of any rendering, including
1610        // debug rendering. This ensures that when we return render targets to the
1611        // pool via glInvalidateFramebuffer, we don't do any debug rendering after
1612        // that point. Otherwise, the bind / invalidate / bind logic trips up the
1613        // render pass logic in tiled / mobile GPUs, resulting in an extra copy /
1614        // resolve step when the debug overlay is enabled.
1615        self.texture_resolver.begin_frame();
1616
1617        if let Some(device_size) = device_size {
1618            self.update_gpu_profile(device_size);
1619        }
1620
1621        let cpu_frame_id = {
1622            let _gm = self.gpu_profiler.start_marker("begin frame");
1623            let frame_id = self.device.begin_frame();
1624            self.gpu_profiler.begin_frame(frame_id);
1625
1626            self.device.disable_scissor();
1627            self.device.disable_depth();
1628            self.set_blend(false, FramebufferKind::Main);
1629            //self.update_shaders();
1630
1631            self.update_texture_cache();
1632            self.update_native_surfaces();
1633
1634            frame_id
1635        };
1636
1637        if !active_doc.frame.present {
1638            // Setting device_size to None is what ensures compositing/presenting
1639            // the frame is skipped in the rest of this module.
1640            device_size = None;
1641        }
1642
1643        if let Some(device_size) = device_size {
1644            // Inform the client that we are starting a composition transaction if native
1645            // compositing is enabled. This needs to be done early in the frame, so that
1646            // we can create debug overlays after drawing the main surfaces.
1647            if let CompositorKind::Native { .. } = self.current_compositor_kind {
1648                let compositor = self.compositor_config.compositor().unwrap();
1649                compositor.begin_frame(&mut self.device);
1650            }
1651
1652            // Update the state of the debug overlay surface, ensuring that
1653            // the compositor mode has a suitable surface to draw to, if required.
1654            self.update_debug_overlay(device_size, !active_doc.frame.debug_items.is_empty());
1655        }
1656
1657        let frame = &mut active_doc.frame;
1658        let profile = &mut active_doc.profile;
1659        assert!(self.current_compositor_kind == frame.composite_state.compositor_kind);
1660
1661        if self.shared_texture_cache_cleared {
1662            assert!(self.documents_seen.contains(&doc_id),
1663                    "Cleared texture cache without sending new document frame.");
1664        }
1665
1666        external_image::update_deferred_resolves(
1667            self.external_image_handler.as_mut(),
1668            &mut self.texture_resolver.external_images,
1669            &mut self.gpu_profiler,
1670            &mut self.device,
1671            &frame.deferred_resolves,
1672            &mut frame.gpu_buffer_f,
1673        );
1674
1675        // Now that external images are resolved, copy their (potentially Y-flipped) uv
1676        // rects into the quad segment blocks that reference them.
1677        frame.gpu_buffer_f.apply_deferred_uv_copies();
1678
1679        self.draw_frame(
1680            frame,
1681            device_size,
1682            buffer_age,
1683            &mut results,
1684        );
1685
1686        // TODO(nical): do this automatically by selecting counters in the wr profiler
1687        // Profile marker for the number of invalidated picture cache
1688        if thread_is_being_profiled() {
1689            let duration = Duration::new(0,0);
1690            if let Some(n) = self.profile.get(profiler::RENDERED_PICTURE_TILES) {
1691                let message = (n as usize).to_string();
1692                add_text_marker("NumPictureCacheInvalidated", &message, duration);
1693            }
1694        }
1695
1696        if device_size.is_some() {
1697            self.draw_frame_debug_items(&frame.debug_items);
1698        }
1699
1700        self.profile.merge(profile);
1701
1702        external_image::unlock_external_images(
1703            self.external_image_handler.as_mut(),
1704            &mut self.texture_resolver.external_images,
1705            &frame.deferred_resolves,
1706        );
1707
1708        let _gm = self.gpu_profiler.start_marker("end frame");
1709        self.gpu_profiler.end_frame();
1710
1711        let t = self.profile.end_time(profiler::RENDERER_TIME);
1712        self.profile.end_time_if_started(profiler::TOTAL_FRAME_CPU_TIME);
1713
1714        let current_time = zeitstempel::now();
1715        if device_size.is_some() {
1716            let time = profiler::ns_to_ms(current_time - self.last_time);
1717            self.profile.set(profiler::FRAME_TIME, time);
1718        }
1719
1720        let debug_overlay = device_size.and_then(|device_size| {
1721            // Bind a surface to draw the debug / profiler information to.
1722            self.bind_debug_overlay(device_size).map(|draw_target| {
1723                self.draw_render_target_debug(&draw_target);
1724                self.draw_texture_cache_debug(&draw_target);
1725                self.draw_zoom_debug(device_size);
1726                self.draw_epoch_debug();
1727                self.draw_window_visibility_debug();
1728                self.draw_external_composite_borders_debug();
1729                draw_target
1730            })
1731        });
1732
1733        Telemetry::record_renderer_time(Duration::from_micros((t * 1000.00) as u64));
1734        if self.profile.get(profiler::SHADER_BUILD_TIME).is_none() {
1735          Telemetry::record_renderer_time_no_sc(Duration::from_micros((t * 1000.00) as u64));
1736        }
1737
1738        if self.max_recorded_profiles > 0 {
1739            while self.cpu_profiles.len() >= self.max_recorded_profiles {
1740                self.cpu_profiles.pop_front();
1741            }
1742            let cpu_profile = CpuProfile::new(
1743                cpu_frame_id,
1744                (self.profile.get_or(profiler::FRAME_BUILDING_TIME, 0.0) * 1000000.0) as u64,
1745                (self.profile.get_or(profiler::RENDERER_TIME, 0.0) * 1000000.0) as u64,
1746                self.profile.get_or(profiler::DRAW_CALLS, 0.0) as usize,
1747            );
1748            self.cpu_profiles.push_back(cpu_profile);
1749        }
1750
1751        if thread_is_being_profiled() {
1752            let duration = Duration::new(0,0);
1753            let message = (self.profile.get_or(profiler::DRAW_CALLS, 0.0) as usize).to_string();
1754            add_text_marker("NumDrawCalls", &message, duration);
1755        }
1756
1757        let report = self.texture_resolver.report_memory();
1758        self.profile.set(profiler::RENDER_TARGET_MEM, profiler::bytes_to_mb(report.render_target_textures));
1759        self.profile.set(profiler::PICTURE_TILES_MEM, profiler::bytes_to_mb(report.picture_tile_textures));
1760        self.profile.set(profiler::ATLAS_TEXTURES_MEM, profiler::bytes_to_mb(report.atlas_textures));
1761        self.profile.set(profiler::STANDALONE_TEXTURES_MEM, profiler::bytes_to_mb(report.standalone_textures));
1762
1763        self.profile.set(profiler::DEPTH_TARGETS_MEM, profiler::bytes_to_mb(self.device.depth_targets_memory()));
1764
1765        self.profile.set(profiler::TEXTURES_CREATED, self.device.textures_created);
1766        self.profile.set(profiler::TEXTURES_DELETED, self.device.textures_deleted);
1767
1768        results.stats.texture_upload_mb = self.profile.get_or(profiler::TEXTURE_UPLOADS_MEM, 0.0);
1769        self.frame_counter += 1;
1770        results.stats.resource_upload_time = self.resource_upload_time;
1771        self.resource_upload_time = 0.0;
1772
1773        if let Some(stats) = active_doc.frame_stats.take() {
1774          // Copy the full frame stats to RendererStats
1775          results.stats.merge(&stats);
1776
1777          self.profiler.update_frame_stats(stats);
1778        }
1779
1780        // Turn the render reasons bitflags into something we can see in the profiler.
1781        // For now this is just a binary yes/no for each bit, which means that when looking
1782        // at "Render reasons" in the profiler HUD the average view indicates the proportion
1783        // of frames that had the bit set over a half second window whereas max shows whether
1784        // the bit as been set at least once during that time window.
1785        // We could implement better ways to visualize this information.
1786        let add_markers = thread_is_being_profiled();
1787        for i in 0..RenderReasons::NUM_BITS {
1788            let counter = profiler::RENDER_REASON_FIRST + i as usize;
1789            let mut val = 0.0;
1790            let reason_bit = RenderReasons::from_bits_truncate(1 << i);
1791            if active_doc.render_reasons.contains(reason_bit) {
1792                val = 1.0;
1793                if add_markers {
1794                    let event_str = format!("Render reason {:?}", reason_bit);
1795                    add_event_marker(&event_str);
1796                }
1797            }
1798            self.profile.set(counter, val);
1799        }
1800        active_doc.render_reasons = RenderReasons::empty();
1801
1802
1803        self.texture_resolver.update_profile(&mut self.profile);
1804
1805        // Note: this clears the values in self.profile.
1806        self.profiler.set_counters(&mut self.profile);
1807
1808        // If debugger is enabled, collect any profiler updates before value is overwritten
1809        // during update below.
1810        #[cfg(feature = "debugger")]
1811        self.debugger.update(
1812            self.debug_flags,
1813            &self.profiler,
1814            &self.command_log,
1815        );
1816
1817        // Note: profile counters must be set before this or they will count for next frame.
1818        self.profiler.update();
1819
1820        if self.debug_flags.intersects(DebugFlags::PROFILER_DBG | DebugFlags::PROFILER_CAPTURE) {
1821            if let Some(device_size) = device_size {
1822                //TODO: take device/pixel ratio into equation?
1823                if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
1824                    self.profiler.draw_profile(
1825                        self.frame_counter,
1826                        debug_renderer,
1827                        device_size,
1828                    );
1829                }
1830            }
1831        }
1832
1833        if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
1834            self.device.echo_driver_messages();
1835        }
1836
1837        if let Some(debug_renderer) = self.debug.try_get_mut() {
1838            let small_screen = self.debug_flags.contains(DebugFlags::SMALL_SCREEN);
1839            let scale = if small_screen { 1.6 } else { 1.0 };
1840            // TODO(gw): Tidy this up so that compositor config integrates better
1841            //           with the (non-compositor) surface y-flip options.
1842            let surface_origin_is_top_left = match self.current_compositor_kind {
1843                CompositorKind::Native { .. } => true,
1844                CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => self.device.surface_origin_is_top_left(),
1845            };
1846            // If there is a debug overlay, render it. Otherwise, just clear
1847            // the debug renderer.
1848            debug_renderer.render(
1849                &mut self.device,
1850                debug_overlay.and(device_size),
1851                scale,
1852                surface_origin_is_top_left,
1853            );
1854        }
1855
1856        self.staging_texture_pool.end_frame(&mut self.device);
1857        self.texture_upload_pbo_pool.end_frame(&mut self.device);
1858        self.device.end_frame();
1859
1860        if debug_overlay.is_some() {
1861            self.last_time = current_time;
1862
1863            // Unbind the target for the debug overlay. No debug or profiler drawing
1864            // can occur afer this point.
1865            self.unbind_debug_overlay();
1866        }
1867
1868        if device_size.is_some() {
1869            // Inform the client that we are finished this composition transaction if native
1870            // compositing is enabled. This must be called after any debug / profiling compositor
1871            // surfaces have been drawn and added to the visual tree.
1872            match self.current_compositor_kind {
1873                CompositorKind::Layer { .. } => {
1874                    let compositor = self.compositor_config.layer_compositor().unwrap();
1875                    compositor.end_frame();
1876                }
1877                CompositorKind::Native { .. } => {
1878                    profile_scope!("compositor.end_frame");
1879                    let compositor = self.compositor_config.compositor().unwrap();
1880                    compositor.end_frame(&mut self.device);
1881                }
1882                CompositorKind::Draw { .. } => {}
1883            }
1884        }
1885
1886        self.documents_seen.clear();
1887        self.shared_texture_cache_cleared = false;
1888
1889        self.check_gl_errors();
1890
1891        if self.renderer_errors.is_empty() {
1892            Ok(results)
1893        } else {
1894            Err(mem::replace(&mut self.renderer_errors, Vec::new()))
1895        }
1896    }
1897
1898    fn update_gpu_profile(&mut self, device_size: DeviceIntSize) {
1899        let _gm = self.gpu_profiler.start_marker("build samples");
1900        // Block CPU waiting for last frame's GPU profiles to arrive.
1901        // In general this shouldn't block unless heavily GPU limited.
1902        let (gpu_frame_id, timers, samplers) = self.gpu_profiler.build_samples();
1903
1904        if self.max_recorded_profiles > 0 {
1905            while self.gpu_profiles.len() >= self.max_recorded_profiles {
1906                self.gpu_profiles.pop_front();
1907            }
1908
1909            self.gpu_profiles.push_back(GpuProfile::new(gpu_frame_id, &timers));
1910        }
1911
1912        self.profiler.set_gpu_time_queries(timers);
1913
1914        if !samplers.is_empty() {
1915            let screen_fraction = 1.0 / device_size.to_f32().area();
1916
1917            fn accumulate_sampler_value(description: &str, samplers: &[GpuSampler]) -> f32 {
1918                let mut accum = 0.0;
1919                for sampler in samplers {
1920                    if sampler.tag.label != description {
1921                        continue;
1922                    }
1923
1924                    accum += sampler.count as f32;
1925                }
1926
1927                accum
1928            }
1929
1930            let alpha_targets = accumulate_sampler_value(&"Alpha targets", &samplers) * screen_fraction;
1931            let transparent_pass = accumulate_sampler_value(&"Transparent pass", &samplers) * screen_fraction;
1932            let opaque_pass = accumulate_sampler_value(&"Opaque pass", &samplers) * screen_fraction;
1933            self.profile.set(profiler::ALPHA_TARGETS_SAMPLERS, alpha_targets);
1934            self.profile.set(profiler::TRANSPARENT_PASS_SAMPLERS, transparent_pass);
1935            self.profile.set(profiler::OPAQUE_PASS_SAMPLERS, opaque_pass);
1936            self.profile.set(profiler::TOTAL_SAMPLERS, alpha_targets + transparent_pass + opaque_pass);
1937        }
1938    }
1939
1940    fn update_texture_cache(&mut self) {
1941        profile_scope!("update_texture_cache");
1942
1943        let _gm = self.gpu_profiler.start_marker("texture cache update");
1944        let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
1945        self.pending_texture_cache_updates = false;
1946
1947        self.profile.start_time(profiler::TEXTURE_CACHE_UPDATE_TIME);
1948
1949        let mut create_cache_texture_time = 0;
1950        let mut delete_cache_texture_time = 0;
1951
1952        for update_list in pending_texture_updates.drain(..) {
1953            // Handle copies from one texture to another.
1954            for ((src_tex, dst_tex), copies) in &update_list.copies {
1955
1956                let dest_texture = &self.texture_resolver.texture_cache_map[&dst_tex].texture;
1957                let dst_texture_size = dest_texture.get_dimensions().to_f32();
1958
1959                let mut copy_instances = Vec::new();
1960                for copy in copies {
1961                    copy_instances.push(CopyInstance {
1962                        src_rect: copy.src_rect.to_f32(),
1963                        dst_rect: copy.dst_rect.to_f32(),
1964                        dst_texture_size,
1965                    });
1966                }
1967
1968                let draw_target = DrawTarget::from_texture(dest_texture, false);
1969                self.device.bind_draw_target(draw_target);
1970
1971                self.shaders
1972                    .borrow_mut()
1973                    .ps_copy()
1974                    .bind(
1975                        &mut self.device,
1976                        &Transform3D::identity(),
1977                        None,
1978                        &mut self.renderer_errors,
1979                        &mut self.profile,
1980                        &mut self.command_log,
1981                    );
1982
1983                self.draw_instanced_batch(
1984                    &copy_instances,
1985                    VertexArrayKind::Copy,
1986                    &BatchTextures::composite_rgb(
1987                        TextureSource::TextureCache(*src_tex, Swizzle::default())
1988                    ),
1989                    &mut RendererStats::default(),
1990                );
1991            }
1992
1993            // Find any textures that will need to be deleted in this group of allocations.
1994            let mut pending_deletes = Vec::new();
1995            for allocation in &update_list.allocations {
1996                let old = self.texture_resolver.texture_cache_map.remove(&allocation.id);
1997                match allocation.kind {
1998                    TextureCacheAllocationKind::Alloc(_) => {
1999                        assert!(old.is_none(), "Renderer and backend disagree!");
2000                    }
2001                    TextureCacheAllocationKind::Reset(_) |
2002                    TextureCacheAllocationKind::Free => {
2003                        assert!(old.is_some(), "Renderer and backend disagree!");
2004                    }
2005                }
2006                if let Some(old) = old {
2007
2008                    // Regenerate the cache allocation info so we can search through deletes for reuse.
2009                    let size = old.texture.get_dimensions();
2010                    let info = TextureCacheAllocInfo {
2011                        width: size.width,
2012                        height: size.height,
2013                        format: old.texture.get_format(),
2014                        filter: old.texture.get_filter(),
2015                        target: old.texture.get_target(),
2016                        is_shared_cache: old.texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE),
2017                        has_depth: old.texture.supports_depth(),
2018                        category: old.category,
2019                    };
2020                    pending_deletes.push((old.texture, info));
2021                }
2022            }
2023            // Look for any alloc or reset that has matching alloc info and save it from being deleted.
2024            let mut reused_textures = VecDeque::with_capacity(pending_deletes.len());
2025            for allocation in &update_list.allocations {
2026                match allocation.kind {
2027                    TextureCacheAllocationKind::Alloc(ref info) |
2028                    TextureCacheAllocationKind::Reset(ref info) => {
2029                        reused_textures.push_back(
2030                            pending_deletes.iter()
2031                                .position(|(_, old_info)| *old_info == *info)
2032                                .map(|index| pending_deletes.swap_remove(index).0)
2033                        );
2034                    }
2035                    TextureCacheAllocationKind::Free => {}
2036                }
2037            }
2038
2039            // Now that we've saved as many deletions for reuse as we can, actually delete whatever is left.
2040            if !pending_deletes.is_empty() {
2041                let delete_texture_start = zeitstempel::now();
2042                for (texture, _) in pending_deletes {
2043                    add_event_marker("TextureCacheFree");
2044                    self.device.delete_texture(texture);
2045                }
2046                delete_cache_texture_time += zeitstempel::now() - delete_texture_start;
2047            }
2048
2049            for allocation in update_list.allocations {
2050                match allocation.kind {
2051                    TextureCacheAllocationKind::Alloc(_) => add_event_marker("TextureCacheAlloc"),
2052                    TextureCacheAllocationKind::Reset(_) => add_event_marker("TextureCacheReset"),
2053                    TextureCacheAllocationKind::Free => {}
2054                };
2055                match allocation.kind {
2056                    TextureCacheAllocationKind::Alloc(ref info) |
2057                    TextureCacheAllocationKind::Reset(ref info) => {
2058                        let create_cache_texture_start = zeitstempel::now();
2059                        // Create a new native texture, as requested by the texture cache.
2060                        // If we managed to reuse a deleted texture, then prefer that instead.
2061                        //
2062                        // Ensure no PBO is bound when creating the texture storage,
2063                        // or GL will attempt to read data from there.
2064                        let mut texture = reused_textures.pop_front().unwrap_or(None).unwrap_or_else(|| {
2065                            self.device.create_texture(
2066                                info.target,
2067                                info.format,
2068                                info.width,
2069                                info.height,
2070                                info.filter,
2071                                // This needs to be a render target because some render
2072                                // tasks get rendered into the texture cache.
2073                                Some(RenderTargetInfo { has_depth: info.has_depth }),
2074                            )
2075                        });
2076
2077                        if info.is_shared_cache {
2078                            texture.flags_mut()
2079                                .insert(TextureFlags::IS_SHARED_TEXTURE_CACHE);
2080
2081                            // On Mali-Gxx devices we use batched texture uploads as it performs much better.
2082                            // However, due to another driver bug we must ensure the textures are fully cleared,
2083                            // otherwise we get visual artefacts when blitting to the texture cache.
2084                            if self.device.use_batched_texture_uploads() &&
2085                                !self.device.get_capabilities().supports_render_target_partial_update
2086                            {
2087                                self.clear_texture(&texture, [0.0; 4]);
2088                            }
2089
2090                            // Textures in the cache generally don't need to be cleared,
2091                            // but we do so if the debug display is active to make it
2092                            // easier to identify unallocated regions.
2093                            if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
2094                                self.clear_texture(&texture, TEXTURE_CACHE_DBG_CLEAR_COLOR);
2095                            }
2096                        }
2097
2098                        create_cache_texture_time += zeitstempel::now() - create_cache_texture_start;
2099
2100                        self.texture_resolver.texture_cache_map.insert(allocation.id, CacheTexture {
2101                            texture,
2102                            category: info.category,
2103                        });
2104                    }
2105                    TextureCacheAllocationKind::Free => {}
2106                };
2107            }
2108
2109            upload_to_texture_cache(self, update_list.updates);
2110
2111            self.check_gl_errors();
2112        }
2113
2114        if create_cache_texture_time > 0 {
2115            self.profile.set(
2116                profiler::CREATE_CACHE_TEXTURE_TIME,
2117                profiler::ns_to_ms(create_cache_texture_time)
2118            );
2119        }
2120        if delete_cache_texture_time > 0 {
2121            self.profile.set(
2122                profiler::DELETE_CACHE_TEXTURE_TIME,
2123                profiler::ns_to_ms(delete_cache_texture_time)
2124            )
2125        }
2126
2127        let t = self.profile.end_time(profiler::TEXTURE_CACHE_UPDATE_TIME);
2128        self.resource_upload_time += t;
2129        Telemetry::record_texture_cache_update_time(Duration::from_micros((t * 1000.00) as u64));
2130
2131        drain_filter(
2132            &mut self.notifications,
2133            |n| { n.when() == Checkpoint::FrameTexturesUpdated },
2134            |n| { n.notify(); },
2135        );
2136    }
2137
2138    fn check_gl_errors(&mut self) {
2139        let err = self.device.gl().get_error();
2140        if err == gl::OUT_OF_MEMORY {
2141            self.renderer_errors.push(RendererError::OutOfMemory);
2142        }
2143
2144        // Probably should check for other errors?
2145    }
2146
2147    fn bind_textures(&mut self, textures: &BatchTextures) {
2148        for i in 0 .. 3 {
2149            self.texture_resolver.bind(
2150                &textures.input.colors[i],
2151                TextureSampler::color(i),
2152                &mut self.device,
2153            );
2154        }
2155
2156        self.texture_resolver.bind(
2157            &textures.clip_mask,
2158            TextureSampler::ClipMask,
2159            &mut self.device,
2160        );
2161
2162        // TODO: this probably isn't the best place for this.
2163        if let Some(ref texture) = self.dither_matrix_texture {
2164            self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
2165        }
2166    }
2167
2168    fn draw_instanced_batch<T: Clone>(
2169        &mut self,
2170        data: &[T],
2171        vertex_array_kind: VertexArrayKind,
2172        textures: &BatchTextures,
2173        stats: &mut RendererStats,
2174    ) {
2175        if let Some(history) = &mut self.command_log {
2176            history.draw(data.len() as u32);
2177        }
2178
2179        self.bind_textures(textures);
2180
2181        // If we end up with an empty draw call here, that means we have
2182        // probably introduced unnecessary batch breaks during frame
2183        // building - so we should be catching this earlier and removing
2184        // the batch.
2185        debug_assert!(!data.is_empty());
2186
2187        let vao = &self.vaos[vertex_array_kind];
2188        self.device.bind_vao(vao);
2189
2190        let chunk_size = if self.debug_flags.contains(DebugFlags::DISABLE_BATCHING) {
2191            1
2192        } else if vertex_array_kind == VertexArrayKind::Primitive {
2193            self.max_primitive_instance_count
2194        } else {
2195            data.len()
2196        };
2197
2198        for chunk in data.chunks(chunk_size) {
2199            if self.enable_instancing {
2200                self.device
2201                    .update_vao_instances(vao, chunk, ONE_TIME_USAGE_HINT, None);
2202                self.device
2203                    .draw_indexed_triangles_instanced_u16(6, chunk.len() as i32);
2204            } else {
2205                self.device
2206                    .update_vao_instances(vao, chunk, ONE_TIME_USAGE_HINT, NonZeroUsize::new(4));
2207                self.device
2208                    .draw_indexed_triangles(6 * chunk.len() as i32);
2209            }
2210            self.profile.inc(profiler::DRAW_CALLS);
2211            stats.total_draw_calls += 1;
2212        }
2213
2214        self.profile.add(profiler::VERTICES, 6 * data.len());
2215    }
2216
2217    fn handle_readback_composite(
2218        &mut self,
2219        draw_target: DrawTarget,
2220        uses_scissor: bool,
2221        backdrop: &RenderTask,
2222        readback: &RenderTask,
2223    ) {
2224        // Extract the rectangle in the backdrop surface's device space of where
2225        // we need to read from.
2226        let readback_origin = match readback.kind {
2227            RenderTaskKind::Readback(ReadbackTask { readback_origin: Some(o), .. }) => o,
2228            RenderTaskKind::Readback(ReadbackTask { readback_origin: None, .. }) => {
2229                // If this is a dummy readback, just early out. We know that the
2230                // clear of the target will ensure the task rect is already zero alpha,
2231                // so it won't affect the rendering output.
2232                return;
2233            }
2234            _ => unreachable!(),
2235        };
2236
2237        if uses_scissor {
2238            self.device.disable_scissor();
2239        }
2240
2241        let texture_source = TextureSource::TextureCache(
2242            readback.get_target_texture(),
2243            Swizzle::default(),
2244        );
2245        let (cache_texture, _) = self.texture_resolver
2246            .resolve(&texture_source).expect("bug: no source texture");
2247
2248        // Before submitting the composite batch, do the
2249        // framebuffer readbacks that are needed for each
2250        // composite operation in this batch.
2251        let readback_rect = readback.get_target_rect();
2252        let backdrop_rect = backdrop.get_target_rect();
2253        let (backdrop_screen_origin, _) = match backdrop.kind {
2254            RenderTaskKind::Picture(ref task_info) => (task_info.content_origin, task_info.device_pixel_scale),
2255            _ => panic!("bug: composite on non-picture?"),
2256        };
2257
2258        // Bind the FBO to blit the backdrop to.
2259        // Called per-instance in case the FBO changes. The device will skip
2260        // the GL call if the requested target is already bound.
2261        let cache_draw_target = DrawTarget::from_texture(
2262            cache_texture,
2263            false,
2264        );
2265
2266        // Get the rect that we ideally want, in space of the parent surface
2267        let wanted_rect = DeviceRect::from_origin_and_size(
2268            readback_origin,
2269            readback_rect.size().to_f32(),
2270        );
2271
2272        // Get the rect that is available on the parent surface. It may be smaller
2273        // than desired because this is a picture cache tile covering only part of
2274        // the wanted rect and/or because the parent surface was clipped.
2275        let avail_rect = DeviceRect::from_origin_and_size(
2276            backdrop_screen_origin,
2277            backdrop_rect.size().to_f32(),
2278        );
2279
2280        if let Some(int_rect) = wanted_rect.intersection(&avail_rect) {
2281            // If there is a valid intersection, work out the correct origins and
2282            // sizes of the copy rects, and do the blit.
2283            let copy_size = int_rect.size().to_i32();
2284
2285            let src_origin = backdrop_rect.min.to_f32() +
2286                int_rect.min.to_vector() -
2287                backdrop_screen_origin.to_vector();
2288
2289            let src = DeviceIntRect::from_origin_and_size(
2290                src_origin.to_i32(),
2291                copy_size,
2292            );
2293
2294            let dest_origin = readback_rect.min.to_f32() +
2295                int_rect.min.to_vector() -
2296                readback_origin.to_vector();
2297
2298            let dest = DeviceIntRect::from_origin_and_size(
2299                dest_origin.to_i32(),
2300                copy_size,
2301            );
2302
2303            // Should always be drawing to picture cache tiles or off-screen surface!
2304            debug_assert!(!draw_target.is_default());
2305            let device_to_framebuffer = Scale::new(1i32);
2306
2307            self.device.blit_render_target(
2308                draw_target.into(),
2309                src * device_to_framebuffer,
2310                cache_draw_target,
2311                dest * device_to_framebuffer,
2312                TextureFilter::Linear,
2313            );
2314        }
2315
2316        // Restore draw target to current pass render target, and reset
2317        // the read target.
2318        self.device.bind_draw_target(draw_target);
2319        self.device.reset_read_target();
2320
2321        if uses_scissor {
2322            self.device.enable_scissor();
2323        }
2324    }
2325
2326    fn handle_resolves(
2327        &mut self,
2328        resolve_ops: &[ResolveOp],
2329        render_tasks: &RenderTaskGraph,
2330        draw_target: DrawTarget,
2331    ) {
2332        if resolve_ops.is_empty() {
2333            return;
2334        }
2335
2336        let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLIT);
2337
2338        for resolve_op in resolve_ops {
2339            self.handle_resolve(
2340                resolve_op,
2341                render_tasks,
2342                draw_target,
2343            );
2344        }
2345
2346        self.device.reset_read_target();
2347    }
2348
2349    fn handle_prims(
2350        &mut self,
2351        draw_target: &DrawTarget,
2352        prim_instances: &[FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>],
2353        prim_instances_with_scissor: &FastHashMap<(DeviceIntRect, PatternKind), FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>>,
2354        projection: &default::Transform3D<f32>,
2355        stats: &mut RendererStats,
2356    ) {
2357        self.device.disable_depth_write();
2358
2359        let has_prim_instances = prim_instances.iter().any(|map| !map.is_empty());
2360        if has_prim_instances || !prim_instances_with_scissor.is_empty() {
2361            let _timer = self.gpu_profiler.start_timer(GPU_TAG_INDIRECT_PRIM);
2362
2363            self.set_blend(false, FramebufferKind::Other);
2364
2365            for (pattern_idx, prim_instances_map) in prim_instances.iter().enumerate() {
2366                if prim_instances_map.is_empty() {
2367                    continue;
2368                }
2369                let pattern = PatternKind::from_u32(pattern_idx as u32);
2370
2371                self.shaders.borrow_mut().get_quad_shader(pattern).bind(
2372                    &mut self.device,
2373                    projection,
2374                    None,
2375                    &mut self.renderer_errors,
2376                    &mut self.profile,
2377                    &mut self.command_log,
2378                );
2379
2380                for (texture_source, prim_instances) in prim_instances_map {
2381                    let texture_bindings = BatchTextures::composite_rgb(*texture_source);
2382
2383                    self.draw_instanced_batch(
2384                        prim_instances,
2385                        VertexArrayKind::Primitive,
2386                        &texture_bindings,
2387                        stats,
2388                    );
2389                }
2390            }
2391
2392            if !prim_instances_with_scissor.is_empty() {
2393                self.set_blend(true, FramebufferKind::Other);
2394                self.device.set_blend_mode_premultiplied_alpha();
2395                self.device.enable_scissor();
2396
2397                let mut prev_pattern = None;
2398
2399                for ((scissor_rect, pattern), prim_instances_map) in prim_instances_with_scissor {
2400                    if prev_pattern != Some(*pattern) {
2401                        prev_pattern = Some(*pattern);
2402                        self.shaders.borrow_mut().get_quad_shader(*pattern).bind(
2403                            &mut self.device,
2404                            projection,
2405                            None,
2406                            &mut self.renderer_errors,
2407                            &mut self.profile,
2408                            &mut self.command_log,
2409                        );
2410                    }
2411
2412                    self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2413
2414                    for (texture_source, prim_instances) in prim_instances_map {
2415                        let texture_bindings = BatchTextures::composite_rgb(*texture_source);
2416
2417                        self.draw_instanced_batch(
2418                            prim_instances,
2419                            VertexArrayKind::Primitive,
2420                            &texture_bindings,
2421                            stats,
2422                        );
2423                    }
2424                }
2425
2426                self.device.disable_scissor();
2427            }
2428        }
2429    }
2430
2431    fn handle_clips(
2432        &mut self,
2433        draw_target: &DrawTarget,
2434        masks: &ClipMaskInstanceList,
2435        projection: &default::Transform3D<f32>,
2436        stats: &mut RendererStats,
2437    ) {
2438        self.device.disable_depth_write();
2439
2440        {
2441            let _timer = self.gpu_profiler.start_timer(GPU_TAG_INDIRECT_MASK);
2442
2443            self.set_blend(true, FramebufferKind::Other);
2444            self.set_blend_mode_multiply(FramebufferKind::Other);
2445
2446            if !masks.mask_instances_fast.is_empty() {
2447                self.shaders.borrow_mut().ps_mask_fast().bind(
2448                    &mut self.device,
2449                    projection,
2450                    None,
2451                    &mut self.renderer_errors,
2452                    &mut self.profile,
2453                    &mut self.command_log,
2454                );
2455
2456                self.draw_instanced_batch(
2457                    &masks.mask_instances_fast,
2458                    VertexArrayKind::Mask,
2459                    &BatchTextures::empty(),
2460                    stats,
2461                );
2462            }
2463
2464            if !masks.mask_instances_fast_with_scissor.is_empty() {
2465                self.shaders.borrow_mut().ps_mask_fast().bind(
2466                    &mut self.device,
2467                    projection,
2468                    None,
2469                    &mut self.renderer_errors,
2470                    &mut self.profile,
2471                    &mut self.command_log,
2472                );
2473
2474                self.device.enable_scissor();
2475
2476                for (scissor_rect, instances) in &masks.mask_instances_fast_with_scissor {
2477                    self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2478
2479                    self.draw_instanced_batch(
2480                        instances,
2481                        VertexArrayKind::Mask,
2482                        &BatchTextures::empty(),
2483                        stats,
2484                    );
2485                }
2486
2487                self.device.disable_scissor();
2488            }
2489
2490            if !masks.image_mask_instances.is_empty() {
2491                self.shaders.borrow_mut().ps_quad_textured().bind(
2492                    &mut self.device,
2493                    projection,
2494                    None,
2495                    &mut self.renderer_errors,
2496                    &mut self.profile,
2497                    &mut self.command_log,
2498                );
2499
2500                for (texture, prim_instances) in &masks.image_mask_instances {
2501                    self.draw_instanced_batch(
2502                        prim_instances,
2503                        VertexArrayKind::Primitive,
2504                        &BatchTextures::composite_rgb(*texture),
2505                        stats,
2506                    );
2507                }
2508            }
2509
2510            if !masks.image_mask_instances_with_scissor.is_empty() {
2511                self.device.enable_scissor();
2512
2513                self.shaders.borrow_mut().ps_quad_textured().bind(
2514                    &mut self.device,
2515                    projection,
2516                    None,
2517                    &mut self.renderer_errors,
2518                    &mut self.profile,
2519                    &mut self.command_log,
2520                );
2521
2522                for ((scissor_rect, texture), prim_instances) in &masks.image_mask_instances_with_scissor {
2523                    self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2524
2525                    self.draw_instanced_batch(
2526                        prim_instances,
2527                        VertexArrayKind::Primitive,
2528                        &BatchTextures::composite_rgb(*texture),
2529                        stats,
2530                    );
2531                }
2532
2533                self.device.disable_scissor();
2534            }
2535
2536            if !masks.mask_instances_slow.is_empty() {
2537                self.shaders.borrow_mut().ps_mask().bind(
2538                    &mut self.device,
2539                    projection,
2540                    None,
2541                    &mut self.renderer_errors,
2542                    &mut self.profile,
2543                    &mut self.command_log,
2544                );
2545
2546                self.draw_instanced_batch(
2547                    &masks.mask_instances_slow,
2548                    VertexArrayKind::Mask,
2549                    &BatchTextures::empty(),
2550                    stats,
2551                );
2552            }
2553
2554            if !masks.mask_instances_slow_with_scissor.is_empty() {
2555                self.shaders.borrow_mut().ps_mask().bind(
2556                    &mut self.device,
2557                    projection,
2558                    None,
2559                    &mut self.renderer_errors,
2560                    &mut self.profile,
2561                    &mut self.command_log,
2562                );
2563
2564                self.device.enable_scissor();
2565
2566                for (scissor_rect, instances) in &masks.mask_instances_slow_with_scissor {
2567                    self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2568
2569                    self.draw_instanced_batch(
2570                        instances,
2571                        VertexArrayKind::Mask,
2572                        &BatchTextures::empty(),
2573                        stats,
2574                    );
2575                }
2576
2577                self.device.disable_scissor();
2578            }
2579        }
2580    }
2581
2582    fn handle_blits(
2583        &mut self,
2584        blits: &[BlitJob],
2585        render_tasks: &RenderTaskGraph,
2586        draw_target: DrawTarget,
2587    ) {
2588        if blits.is_empty() {
2589            return;
2590        }
2591
2592        let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLIT);
2593
2594        // TODO(gw): For now, we don't bother batching these by source texture.
2595        //           If if ever shows up as an issue, we can easily batch them.
2596        for blit in blits {
2597            let (source, source_rect) = {
2598                // A blit from the child render task into this target.
2599                // TODO(gw): Support R8 format here once we start
2600                //           creating mips for alpha masks.
2601                let task = &render_tasks[blit.source];
2602                let source_rect = blit.source_rect.translate(task.get_target_rect().min.to_vector());
2603                let source_texture = task.get_texture_source();
2604
2605                (source_texture, source_rect)
2606            };
2607
2608            let (texture, swizzle) = self.texture_resolver
2609                .resolve(&source)
2610                .expect("BUG: invalid source texture");
2611
2612            if swizzle != Swizzle::default() {
2613                error!("Swizzle {:?} can't be handled by a blit", swizzle);
2614            }
2615
2616            let read_target = DrawTarget::from_texture(
2617                texture,
2618                false,
2619            );
2620
2621            self.device.blit_render_target(
2622                read_target.into(),
2623                read_target.to_framebuffer_rect(source_rect),
2624                draw_target,
2625                draw_target.to_framebuffer_rect(blit.target_rect),
2626                TextureFilter::Linear,
2627            );
2628        }
2629    }
2630
2631    fn handle_scaling(
2632        &mut self,
2633        scalings: &FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
2634        projection: &default::Transform3D<f32>,
2635        stats: &mut RendererStats,
2636    ) {
2637        if scalings.is_empty() {
2638            return
2639        }
2640
2641        let _timer = self.gpu_profiler.start_timer(GPU_TAG_SCALE);
2642        for (source, instances) in scalings {
2643            let buffer_kind = source.image_buffer_kind();
2644
2645            // When the source texture is an external texture, the UV rect is not known
2646            // when the external surface descriptor is created, because external textures
2647            // are not resolved until the lock() callback is invoked at the start of the
2648            // frame render. We must therefore override the source rects now.
2649            let uv_override_instances;
2650            let instances = match source {
2651                TextureSource::External(..) => {
2652                    uv_override_instances = instances.iter().map(|instance| {
2653                        let mut new_instance = instance.clone();
2654                        let texel_rect: TexelRect = self.texture_resolver.get_uv_rect(
2655                            &source,
2656                            instance.source_rect.cast().into()
2657                        ).into();
2658                        new_instance.source_rect = DeviceRect::new(texel_rect.uv0, texel_rect.uv1);
2659                        new_instance
2660                    }).collect::<Vec<_>>();
2661                    uv_override_instances.as_slice()
2662                }
2663                _ => instances.as_slice()
2664            };
2665
2666            self.shaders
2667                .borrow_mut()
2668                .get_scale_shader(buffer_kind)
2669                .bind(
2670                    &mut self.device,
2671                    &projection,
2672                    Some(self.texture_resolver.get_texture_size(source).to_f32()),
2673                    &mut self.renderer_errors,
2674                    &mut self.profile,
2675                    &mut self.command_log,
2676                );
2677
2678            self.draw_instanced_batch(
2679                instances,
2680                VertexArrayKind::Scale,
2681                &BatchTextures::composite_rgb(*source),
2682                stats,
2683            );
2684        }
2685    }
2686
2687    fn handle_svg_nodes(
2688        &mut self,
2689        textures: &BatchTextures,
2690        svg_filters: &[SVGFEFilterInstance],
2691        projection: &default::Transform3D<f32>,
2692        stats: &mut RendererStats,
2693    ) {
2694        if svg_filters.is_empty() {
2695            return;
2696        }
2697
2698        let _timer = self.gpu_profiler.start_timer(GPU_TAG_SVG_FILTER_NODES);
2699
2700        self.shaders.borrow_mut().cs_svg_filter_node().bind(
2701            &mut self.device,
2702            &projection,
2703            None,
2704            &mut self.renderer_errors,
2705            &mut self.profile,
2706            &mut self.command_log,
2707        );
2708
2709        self.draw_instanced_batch(
2710            &svg_filters,
2711            VertexArrayKind::SvgFilterNode,
2712            textures,
2713            stats,
2714        );
2715    }
2716
2717    fn handle_resolve(
2718        &mut self,
2719        resolve_op: &ResolveOp,
2720        render_tasks: &RenderTaskGraph,
2721        draw_target: DrawTarget,
2722    ) {
2723        for src_task_id in &resolve_op.src_task_ids {
2724            let src_task = &render_tasks[*src_task_id];
2725            let src_info = match src_task.kind {
2726                RenderTaskKind::Picture(ref info) => info,
2727                _ => panic!("bug: not a picture"),
2728            };
2729            let src_task_rect = src_task.get_target_rect().to_f32();
2730
2731            let dest_task = &render_tasks[resolve_op.dest_task_id];
2732            let dest_info = match dest_task.kind {
2733                RenderTaskKind::Picture(ref info) => info,
2734                _ => panic!("bug: not a picture"),
2735            };
2736            let dest_task_rect = dest_task.get_target_rect().to_f32();
2737
2738            // If the dest picture is going to a blur target, it may have been
2739            // expanded in size so that the downsampling passes don't introduce
2740            // sampling error. In this case, we need to ensure we use the
2741            // content size rather than the render task size to work out
2742            // the intersecting rect to use for the resolve copy.
2743            let dest_task_rect = DeviceRect::from_origin_and_size(
2744                dest_task_rect.min,
2745                dest_info.content_size.to_f32(),
2746            );
2747
2748            // Get the rect that we ideally want, in space of the parent surface
2749            let wanted_rect = DeviceRect::from_origin_and_size(
2750                dest_info.content_origin,
2751                dest_task_rect.size().to_f32(),
2752            ).cast_unit() * dest_info.device_pixel_scale.inverse();
2753
2754            // Get the rect that is available on the parent surface. It may be smaller
2755            // than desired because this is a picture cache tile covering only part of
2756            // the wanted rect and/or because the parent surface was clipped.
2757            let avail_rect = DeviceRect::from_origin_and_size(
2758                src_info.content_origin,
2759                src_task_rect.size().to_f32(),
2760            ).cast_unit() * src_info.device_pixel_scale.inverse();
2761
2762            if let Some(device_int_rect) = wanted_rect.intersection(&avail_rect) {
2763                let src_int_rect = (device_int_rect * src_info.device_pixel_scale).cast_unit();
2764                let dest_int_rect = (device_int_rect * dest_info.device_pixel_scale).cast_unit();
2765
2766                // If there is a valid intersection, work out the correct origins and
2767                // sizes of the copy rects, and do the blit.
2768
2769                let src_origin = src_task_rect.min.to_f32() +
2770                    src_int_rect.min.to_vector() -
2771                    src_info.content_origin.to_vector();
2772
2773                let src = DeviceIntRect::from_origin_and_size(
2774                    src_origin.to_i32(),
2775                    src_int_rect.size().round().to_i32(),
2776                );
2777
2778                let dest_origin = dest_task_rect.min.to_f32() +
2779                    dest_int_rect.min.to_vector() -
2780                    dest_info.content_origin.to_vector();
2781
2782                let dest = DeviceIntRect::from_origin_and_size(
2783                    dest_origin.to_i32(),
2784                    dest_int_rect.size().round().to_i32(),
2785                );
2786
2787                let texture_source = TextureSource::TextureCache(
2788                    src_task.get_target_texture(),
2789                    Swizzle::default(),
2790                );
2791                let (cache_texture, _) = self.texture_resolver
2792                    .resolve(&texture_source).expect("bug: no source texture");
2793
2794                let read_target = ReadTarget::from_texture(cache_texture);
2795
2796                // Should always be drawing to picture cache tiles or off-screen surface!
2797                debug_assert!(!draw_target.is_default());
2798                let device_to_framebuffer = Scale::new(1i32);
2799
2800                self.device.blit_render_target(
2801                    read_target,
2802                    src * device_to_framebuffer,
2803                    draw_target,
2804                    dest * device_to_framebuffer,
2805                    TextureFilter::Linear,
2806                );
2807            }
2808        }
2809    }
2810
2811    fn draw_picture_cache_target(
2812        &mut self,
2813        target: &PictureCacheTarget,
2814        draw_target: DrawTarget,
2815        projection: &default::Transform3D<f32>,
2816        render_tasks: &RenderTaskGraph,
2817        stats: &mut RendererStats,
2818    ) {
2819        profile_scope!("draw_picture_cache_target");
2820        if let Some(history) = &mut self.command_log {
2821            history.begin_render_target("Picture tile", draw_target.dimensions());
2822        }
2823
2824        self.profile.inc(profiler::RENDERED_PICTURE_TILES);
2825        let _gm = self.gpu_profiler.start_marker("picture cache target");
2826        let framebuffer_kind = FramebufferKind::Other;
2827
2828        {
2829            let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_TARGET);
2830            self.device.bind_draw_target(draw_target);
2831
2832            if self.device.get_capabilities().supports_qcom_tiled_rendering {
2833                self.device.gl().start_tiling_qcom(
2834                    target.dirty_rect.min.x.max(0) as _,
2835                    target.dirty_rect.min.y.max(0) as _,
2836                    target.dirty_rect.width() as _,
2837                    target.dirty_rect.height() as _,
2838                    0,
2839                );
2840            }
2841
2842            self.device.enable_depth_write();
2843            self.set_blend(false, framebuffer_kind);
2844
2845            let clear_color = target.clear_color.map(|c| c.to_array());
2846            let scissor_rect = if self.device.get_capabilities().supports_render_target_partial_update
2847                && (target.dirty_rect != target.valid_rect
2848                    || self.device.get_capabilities().prefers_clear_scissor)
2849            {
2850                Some(target.dirty_rect)
2851            } else {
2852                None
2853            };
2854            match scissor_rect {
2855                // If updating only a dirty rect within a picture cache target, the
2856                // clear must also be scissored to that dirty region.
2857                Some(r) if self.clear_caches_with_quads => {
2858                    self.device.enable_depth(DepthFunction::Always);
2859                    // Save the draw call count so that our reftests don't get confused...
2860                    let old_draw_call_count = stats.total_draw_calls;
2861                    if clear_color.is_none() {
2862                        self.device.disable_color_write();
2863                    }
2864                    let instance = ClearInstance {
2865                        rect: [
2866                            r.min.x as f32, r.min.y as f32,
2867                            r.max.x as f32, r.max.y as f32,
2868                        ],
2869                        color: clear_color.unwrap_or([0.0; 4]),
2870                    };
2871                    self.shaders.borrow_mut().ps_clear().bind(
2872                        &mut self.device,
2873                        &projection,
2874                        None,
2875                        &mut self.renderer_errors,
2876                        &mut self.profile,
2877                        &mut self.command_log,
2878                    );
2879                    self.draw_instanced_batch(
2880                        &[instance],
2881                        VertexArrayKind::Clear,
2882                        &BatchTextures::empty(),
2883                        stats,
2884                    );
2885                    if clear_color.is_none() {
2886                        self.device.enable_color_write();
2887                    }
2888                    stats.total_draw_calls = old_draw_call_count;
2889                    self.device.disable_depth();
2890                }
2891                other => {
2892                    let scissor_rect = other.map(|rect| {
2893                        draw_target.build_scissor_rect(Some(rect))
2894                    });
2895                    self.device.clear_target(clear_color, Some(1.0), scissor_rect);
2896                }
2897            };
2898            self.device.disable_depth_write();
2899        }
2900
2901        match target.kind {
2902            PictureCacheTargetKind::Draw { ref alpha_batch_container } => {
2903                self.draw_alpha_batch_container(
2904                    alpha_batch_container,
2905                    draw_target,
2906                    framebuffer_kind,
2907                    projection,
2908                    render_tasks,
2909                    stats,
2910                );
2911            }
2912            PictureCacheTargetKind::Blit { task_id, sub_rect_offset } => {
2913                let src_task = &render_tasks[task_id];
2914                let (texture, _swizzle) = self.texture_resolver
2915                    .resolve(&src_task.get_texture_source())
2916                    .expect("BUG: invalid source texture");
2917
2918                let src_task_rect = src_task.get_target_rect();
2919
2920                let p0 = src_task_rect.min + sub_rect_offset;
2921                let p1 = p0 + target.dirty_rect.size();
2922                let src_rect = DeviceIntRect::new(p0, p1);
2923
2924                // TODO(gw): In future, it'd be tidier to have the draw target offset
2925                //           for DC surfaces handled by `blit_render_target`. However,
2926                //           for now they are only ever written to here.
2927                let target_rect = target
2928                    .dirty_rect
2929                    .translate(draw_target.offset().to_vector())
2930                    .cast_unit();
2931
2932                self.device.blit_render_target(
2933                    ReadTarget::from_texture(texture),
2934                    src_rect.cast_unit(),
2935                    draw_target,
2936                    target_rect,
2937                    TextureFilter::Nearest,
2938                );
2939            }
2940        }
2941
2942        self.device.invalidate_depth_target();
2943        if self.device.get_capabilities().supports_qcom_tiled_rendering {
2944            self.device.gl().end_tiling_qcom(gl::COLOR_BUFFER_BIT0_QCOM);
2945        }
2946    }
2947
2948    /// Draw an alpha batch container into a given draw target. This is used
2949    /// by both color and picture cache target kinds.
2950    fn draw_alpha_batch_container(
2951        &mut self,
2952        alpha_batch_container: &AlphaBatchContainer,
2953        draw_target: DrawTarget,
2954        framebuffer_kind: FramebufferKind,
2955        projection: &default::Transform3D<f32>,
2956        render_tasks: &RenderTaskGraph,
2957        stats: &mut RendererStats,
2958    ) {
2959        let uses_scissor = alpha_batch_container.task_scissor_rect.is_some();
2960
2961        if uses_scissor {
2962            self.device.enable_scissor();
2963            let scissor_rect = draw_target.build_scissor_rect(
2964                alpha_batch_container.task_scissor_rect,
2965            );
2966            self.device.set_scissor_rect(scissor_rect)
2967        }
2968
2969        if !alpha_batch_container.opaque_batches.is_empty()
2970            && !self.debug_flags.contains(DebugFlags::DISABLE_OPAQUE_PASS) {
2971            let _gl = self.gpu_profiler.start_marker("opaque batches");
2972            let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
2973            self.set_blend(false, framebuffer_kind);
2974            //Note: depth equality is needed for split planes
2975            self.device.enable_depth(DepthFunction::LessEqual);
2976            self.device.enable_depth_write();
2977
2978            // Draw opaque batches front-to-back for maximum
2979            // z-buffer efficiency!
2980            for batch in alpha_batch_container
2981                .opaque_batches
2982                .iter()
2983                .rev()
2984                {
2985                    if should_skip_batch(&batch.key.kind, self.debug_flags) {
2986                        continue;
2987                    }
2988
2989                    self.shaders.borrow_mut()
2990                        .get(&batch.key, batch.features, self.debug_flags, &self.device)
2991                        .bind(
2992                            &mut self.device, projection, None,
2993                            &mut self.renderer_errors,
2994                            &mut self.profile,
2995                            &mut self.command_log,
2996                        );
2997
2998                    let _timer = self.gpu_profiler.start_timer(batch.key.kind.sampler_tag());
2999                    self.draw_instanced_batch(
3000                        &batch.instances,
3001                        VertexArrayKind::Primitive,
3002                        &batch.key.textures,
3003                        stats
3004                    );
3005                }
3006
3007            self.device.disable_depth_write();
3008            self.gpu_profiler.finish_sampler(opaque_sampler);
3009        } else {
3010            self.device.disable_depth();
3011        }
3012
3013        if !alpha_batch_container.alpha_batches.is_empty()
3014            && !self.debug_flags.contains(DebugFlags::DISABLE_ALPHA_PASS) {
3015            let _gl = self.gpu_profiler.start_marker("alpha batches");
3016            let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
3017            self.set_blend(true, framebuffer_kind);
3018
3019            let mut prev_blend_mode = BlendMode::None;
3020            let shaders_rc = self.shaders.clone();
3021
3022            for batch in &alpha_batch_container.alpha_batches {
3023                if should_skip_batch(&batch.key.kind, self.debug_flags) {
3024                    continue;
3025                }
3026
3027                let mut shaders = shaders_rc.borrow_mut();
3028                let shader = shaders.get(
3029                    &batch.key,
3030                    batch.features | BatchFeatures::ALPHA_PASS,
3031                    self.debug_flags,
3032                    &self.device,
3033                );
3034
3035                if batch.key.blend_mode != prev_blend_mode {
3036                    match batch.key.blend_mode {
3037                        _ if self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) &&
3038                            framebuffer_kind == FramebufferKind::Main => {
3039                            self.device.set_blend_mode_show_overdraw();
3040                        }
3041                        BlendMode::None => {
3042                            unreachable!("bug: opaque blend in alpha pass");
3043                        }
3044                        BlendMode::Alpha => {
3045                            self.device.set_blend_mode_alpha();
3046                        }
3047                        BlendMode::PremultipliedAlpha => {
3048                            self.device.set_blend_mode_premultiplied_alpha();
3049                        }
3050                        BlendMode::PremultipliedDestOut => {
3051                            self.device.set_blend_mode_premultiplied_dest_out();
3052                        }
3053                        BlendMode::SubpixelDualSource => {
3054                            self.device.set_blend_mode_subpixel_dual_source();
3055                        }
3056                        BlendMode::Advanced(mode) => {
3057                            if self.enable_advanced_blend_barriers {
3058                                self.device.gl().blend_barrier_khr();
3059                            }
3060                            self.device.set_blend_mode_advanced(mode);
3061                        }
3062                        BlendMode::MultiplyDualSource => {
3063                            self.device.set_blend_mode_multiply_dual_source();
3064                        }
3065                        BlendMode::Screen => {
3066                            self.device.set_blend_mode_screen();
3067                        }
3068                        BlendMode::Exclusion => {
3069                            self.device.set_blend_mode_exclusion();
3070                        }
3071                        BlendMode::PlusLighter => {
3072                            self.device.set_blend_mode_plus_lighter();
3073                        }
3074                    }
3075                    prev_blend_mode = batch.key.blend_mode;
3076                }
3077
3078                // Handle special case readback for composites.
3079                if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, backdrop_id }) = batch.key.kind {
3080                    // composites can't be grouped together because
3081                    // they may overlap and affect each other.
3082                    debug_assert_eq!(batch.instances.len(), 1);
3083                    self.handle_readback_composite(
3084                        draw_target,
3085                        uses_scissor,
3086                        &render_tasks[task_id],
3087                        &render_tasks[backdrop_id],
3088                    );
3089                }
3090
3091                let _timer = self.gpu_profiler.start_timer(batch.key.kind.sampler_tag());
3092                shader.bind(
3093                    &mut self.device,
3094                    projection,
3095                    None,
3096                    &mut self.renderer_errors,
3097                    &mut self.profile,
3098                    &mut self.command_log,
3099                );
3100
3101                self.draw_instanced_batch(
3102                    &batch.instances,
3103                    VertexArrayKind::Primitive,
3104                    &batch.key.textures,
3105                    stats
3106                );
3107            }
3108
3109            self.set_blend(false, framebuffer_kind);
3110            self.gpu_profiler.finish_sampler(transparent_sampler);
3111        }
3112
3113        self.device.disable_depth();
3114        if uses_scissor {
3115            self.device.disable_scissor();
3116        }
3117    }
3118
3119    fn clear_render_target(
3120        &mut self,
3121        target: &RenderTarget,
3122        draw_target: DrawTarget,
3123        framebuffer_kind: FramebufferKind,
3124        projection: &default::Transform3D<f32>,
3125        stats: &mut RendererStats,
3126    ) {
3127        let needs_depth = target.needs_depth();
3128
3129        let clear_depth = if needs_depth {
3130            Some(1.0)
3131        } else {
3132            None
3133        };
3134
3135        let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_TARGET);
3136
3137        self.device.disable_depth();
3138        self.set_blend(false, framebuffer_kind);
3139
3140        let is_alpha = target.target_kind == RenderTargetKind::Alpha;
3141        let require_precise_clear = target.cached;
3142
3143        // On some Mali-T devices we have observed crashes in subsequent draw calls
3144        // immediately after clearing the alpha render target regions with glClear().
3145        // Using the shader to clear the regions avoids the crash. See bug 1638593.
3146        let clear_with_quads = (target.cached && self.clear_caches_with_quads)
3147            || (is_alpha && self.clear_alpha_targets_with_quads);
3148
3149        let favor_partial_updates = self.device.get_capabilities().supports_render_target_partial_update
3150            && self.enable_clear_scissor;
3151
3152        // On some Adreno 4xx devices we have seen render tasks to alpha targets have no
3153        // effect unless the target is fully cleared prior to rendering. See bug 1714227.
3154        let full_clears_on_adreno = is_alpha && self.device.get_capabilities().requires_alpha_target_full_clear;
3155        let require_full_clear = !require_precise_clear
3156            && (full_clears_on_adreno || !favor_partial_updates);
3157
3158        let clear_color = target
3159            .clear_color
3160            .map(|color| color.to_array());
3161
3162        let mut cleared_depth = false;
3163        if clear_with_quads {
3164            // Will be handled last. Only specific rects will be cleared.
3165        } else if require_precise_clear {
3166            // Only clear specific rects
3167            for (rect, color) in &target.clears {
3168                self.device.clear_target(
3169                    Some(color.to_array()),
3170                    None,
3171                    Some(draw_target.to_framebuffer_rect(*rect)),
3172                );
3173            }
3174        } else {
3175            // At this point we know we don't require precise clears for correctness.
3176            // We may still attempt to restruct the clear rect as an optimization on
3177            // some configurations.
3178            let clear_rect = if require_full_clear {
3179                None
3180            } else {
3181                match draw_target {
3182                    DrawTarget::Default { rect, total_size, .. } => {
3183                        if rect.min == FramebufferIntPoint::zero() && rect.size() == total_size {
3184                            // Whole screen is covered, no need for scissor
3185                            None
3186                        } else {
3187                            Some(rect)
3188                        }
3189                    }
3190                    DrawTarget::Texture { .. } => {
3191                        // TODO(gw): Applying a scissor rect and minimal clear here
3192                        // is a very large performance win on the Intel and nVidia
3193                        // GPUs that I have tested with. It's possible it may be a
3194                        // performance penalty on other GPU types - we should test this
3195                        // and consider different code paths.
3196                        //
3197                        // Note: The above measurements were taken when render
3198                        // target slices were minimum 2048x2048. Now that we size
3199                        // them adaptively, this may be less of a win (except perhaps
3200                        // on a mostly-unused last slice of a large texture array).
3201                        target.used_rect.map(|rect| draw_target.to_framebuffer_rect(rect))
3202                    }
3203                    // Full clear.
3204                    _ => None,
3205                }
3206            };
3207
3208            self.device.clear_target(
3209                clear_color,
3210                clear_depth,
3211                clear_rect,
3212            );
3213            cleared_depth = true;
3214        }
3215
3216        // Make sure to clear the depth buffer if it is used.
3217        if needs_depth && !cleared_depth {
3218            // TODO: We could also clear the depth buffer via ps_clear. This
3219            // is done by picture cache targets in some cases.
3220            self.device.clear_target(None, clear_depth, None);
3221        }
3222
3223        // Finally, if we decided to clear with quads or if we need to clear
3224        // some areas with specific colors that don't match the global clear
3225        // color, clear more areas using a draw call.
3226
3227        let mut clear_instances = Vec::with_capacity(target.clears.len());
3228        for (rect, color) in &target.clears {
3229            if clear_with_quads || (!require_precise_clear && target.clear_color != Some(*color)) {
3230                let rect = rect.to_f32();
3231                clear_instances.push(ClearInstance {
3232                    rect: [
3233                        rect.min.x, rect.min.y,
3234                        rect.max.x, rect.max.y,
3235                    ],
3236                    color: color.to_array(),
3237                })
3238            }
3239        }
3240
3241        if !clear_instances.is_empty() {
3242            self.shaders.borrow_mut().ps_clear().bind(
3243                &mut self.device,
3244                &projection,
3245                None,
3246                &mut self.renderer_errors,
3247                &mut self.profile,
3248                &mut self.command_log,
3249            );
3250            self.draw_instanced_batch(
3251                &clear_instances,
3252                VertexArrayKind::Clear,
3253                &BatchTextures::empty(),
3254                stats,
3255            );
3256        }
3257    }
3258
3259    fn draw_render_target(
3260        &mut self,
3261        texture_id: CacheTextureId,
3262        target: &RenderTarget,
3263        render_tasks: &RenderTaskGraph,
3264        stats: &mut RendererStats,
3265    ) {
3266        let needs_depth = target.needs_depth();
3267
3268        let texture = self.texture_resolver.get_cache_texture_mut(&texture_id);
3269
3270        if let Some(history) = &mut self.command_log {
3271            let label = match target.target_kind {
3272                RenderTargetKind::Color => "color",
3273                RenderTargetKind::Alpha => "alpha",
3274            };
3275            history.begin_render_target(label, texture.get_dimensions());
3276        }
3277
3278        if needs_depth {
3279            self.device.reuse_render_target::<u8>(
3280                texture,
3281                RenderTargetInfo { has_depth: needs_depth },
3282            );
3283        }
3284
3285        let draw_target = DrawTarget::from_texture(
3286            texture,
3287            needs_depth,
3288        );
3289
3290        let projection = Transform3D::ortho(
3291            0.0,
3292            draw_target.dimensions().width as f32,
3293            0.0,
3294            draw_target.dimensions().height as f32,
3295            self.device.ortho_near_plane(),
3296            self.device.ortho_far_plane(),
3297        );
3298
3299        profile_scope!("draw_render_target");
3300        let _gm = self.gpu_profiler.start_marker("render target");
3301
3302        let counter = match target.target_kind {
3303            RenderTargetKind::Color => profiler::COLOR_PASSES,
3304            RenderTargetKind::Alpha => profiler::ALPHA_PASSES,
3305        };
3306        self.profile.inc(counter);
3307
3308        let sampler_query = match target.target_kind {
3309            RenderTargetKind::Color => None,
3310            RenderTargetKind::Alpha => Some(self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_ALPHA)),
3311        };
3312
3313        // sanity check for the depth buffer
3314        if let DrawTarget::Texture { with_depth, .. } = draw_target {
3315            assert!(with_depth >= target.needs_depth());
3316        }
3317
3318        let framebuffer_kind = if draw_target.is_default() {
3319            FramebufferKind::Main
3320        } else {
3321            FramebufferKind::Other
3322        };
3323
3324        self.device.bind_draw_target(draw_target);
3325
3326        if self.device.get_capabilities().supports_qcom_tiled_rendering {
3327            let preserve_mask = match target.clear_color {
3328                Some(_) => 0,
3329                None => gl::COLOR_BUFFER_BIT0_QCOM,
3330            };
3331            if let Some(used_rect) = target.used_rect {
3332                self.device.gl().start_tiling_qcom(
3333                    used_rect.min.x.max(0) as _,
3334                    used_rect.min.y.max(0) as _,
3335                    used_rect.width() as _,
3336                    used_rect.height() as _,
3337                    preserve_mask,
3338                );
3339            }
3340        }
3341
3342        if needs_depth {
3343            self.device.enable_depth_write();
3344        } else {
3345            self.device.disable_depth_write();
3346        }
3347
3348        self.clear_render_target(
3349            target,
3350            draw_target,
3351            framebuffer_kind,
3352            &projection,
3353            stats,
3354        );
3355
3356        if needs_depth {
3357            self.device.disable_depth_write();
3358        }
3359
3360        // Handle any resolves from parent pictures to this target
3361        self.handle_resolves(
3362            &target.resolve_ops,
3363            render_tasks,
3364            draw_target,
3365        );
3366
3367        // Handle any blits from the texture cache to this target.
3368        self.handle_blits(
3369            &target.blits,
3370            render_tasks,
3371            draw_target,
3372        );
3373
3374        // Draw any borders for this target.
3375        if !target.border_segments_solid.is_empty() ||
3376           !target.border_segments_complex.is_empty()
3377        {
3378            let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_BORDER);
3379
3380            self.set_blend(true, FramebufferKind::Other);
3381            self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
3382
3383            if !target.border_segments_solid.is_empty() {
3384                self.shaders.borrow_mut().cs_border_solid().bind(
3385                    &mut self.device,
3386                    &projection,
3387                    None,
3388                    &mut self.renderer_errors,
3389                    &mut self.profile,
3390                    &mut self.command_log,
3391                );
3392
3393                self.draw_instanced_batch(
3394                    &target.border_segments_solid,
3395                    VertexArrayKind::Border,
3396                    &BatchTextures::empty(),
3397                    stats,
3398                );
3399            }
3400
3401            if !target.border_segments_complex.is_empty() {
3402                self.shaders.borrow_mut().cs_border_segment().bind(
3403                    &mut self.device,
3404                    &projection,
3405                    None,
3406                    &mut self.renderer_errors,
3407                    &mut self.profile,
3408                    &mut self.command_log,
3409                );
3410
3411                self.draw_instanced_batch(
3412                    &target.border_segments_complex,
3413                    VertexArrayKind::Border,
3414                    &BatchTextures::empty(),
3415                    stats,
3416                );
3417            }
3418
3419            self.set_blend(false, FramebufferKind::Other);
3420        }
3421
3422        // Draw any line decorations for this target.
3423        if !target.line_decorations.is_empty() {
3424            let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_LINE_DECORATION);
3425
3426            self.set_blend(true, FramebufferKind::Other);
3427            self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
3428
3429            self.shaders.borrow_mut().cs_line_decoration().bind(
3430                &mut self.device,
3431                &projection,
3432                None,
3433                &mut self.renderer_errors,
3434                &mut self.profile,
3435                &mut self.command_log,
3436            );
3437
3438            self.draw_instanced_batch(
3439                &target.line_decorations,
3440                VertexArrayKind::LineDecoration,
3441                &BatchTextures::empty(),
3442                stats,
3443            );
3444
3445            self.set_blend(false, FramebufferKind::Other);
3446        }
3447
3448
3449        // Draw any blurs for this target.
3450        // Blurs are rendered as a standard 2-pass
3451        // separable implementation.
3452        // TODO(gw): In the future, consider having
3453        //           fast path blur shaders for common
3454        //           blur radii with fixed weights.
3455        if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
3456            let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLUR);
3457
3458            self.set_blend(false, framebuffer_kind);
3459            self.shaders.borrow_mut().cs_blur_rgba8().bind(
3460                &mut self.device,
3461                &projection,
3462                None,
3463                &mut self.renderer_errors,
3464                &mut self.profile,
3465                &mut self.command_log,
3466            );
3467
3468            if !target.vertical_blurs.is_empty() {
3469                self.draw_blurs(
3470                    &target.vertical_blurs,
3471                    stats,
3472                );
3473            }
3474
3475            if !target.horizontal_blurs.is_empty() {
3476                self.draw_blurs(
3477                    &target.horizontal_blurs,
3478                    stats,
3479                );
3480            }
3481        }
3482
3483        self.handle_scaling(
3484            &target.scalings,
3485            &projection,
3486            stats,
3487        );
3488
3489        for (ref textures, ref filters) in &target.svg_nodes {
3490            self.handle_svg_nodes(textures, filters, &projection, stats);
3491        }
3492
3493        for alpha_batch_container in &target.alpha_batch_containers {
3494            self.draw_alpha_batch_container(
3495                alpha_batch_container,
3496                draw_target,
3497                framebuffer_kind,
3498                &projection,
3499                render_tasks,
3500                stats,
3501            );
3502        }
3503
3504        self.handle_prims(
3505            &draw_target,
3506            &target.prim_instances,
3507            &target.prim_instances_with_scissor,
3508            &projection,
3509            stats,
3510        );
3511
3512        // Draw the clip items into the tiled alpha mask.
3513        let has_primary_clips = !target.clip_batcher.primary_clips.is_empty();
3514        let has_secondary_clips = !target.clip_batcher.secondary_clips.is_empty();
3515        let has_clip_masks = !target.clip_masks.is_empty();
3516        if has_primary_clips | has_secondary_clips | has_clip_masks {
3517            let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_CLIP);
3518
3519            // TODO(gw): Consider grouping multiple clip masks per shader
3520            //           invocation here to reduce memory bandwith further?
3521
3522            if has_primary_clips {
3523                // Draw the primary clip mask - since this is the first mask
3524                // for the task, we can disable blending, knowing that it will
3525                // overwrite every pixel in the mask area.
3526                self.set_blend(false, FramebufferKind::Other);
3527                self.draw_clip_batch_list(
3528                    &target.clip_batcher.primary_clips,
3529                    &projection,
3530                    stats,
3531                );
3532            }
3533
3534            if has_secondary_clips {
3535                // switch to multiplicative blending for secondary masks, using
3536                // multiplicative blending to accumulate clips into the mask.
3537                self.set_blend(true, FramebufferKind::Other);
3538                self.set_blend_mode_multiply(FramebufferKind::Other);
3539                self.draw_clip_batch_list(
3540                    &target.clip_batcher.secondary_clips,
3541                    &projection,
3542                    stats,
3543                );
3544            }
3545
3546            if has_clip_masks {
3547                self.handle_clips(
3548                    &draw_target,
3549                    &target.clip_masks,
3550                    &projection,
3551                    stats,
3552                );
3553            }
3554        }
3555
3556        if needs_depth {
3557            self.device.invalidate_depth_target();
3558        }
3559        if self.device.get_capabilities().supports_qcom_tiled_rendering {
3560            self.device.gl().end_tiling_qcom(gl::COLOR_BUFFER_BIT0_QCOM);
3561        }
3562
3563        if let Some(sampler) = sampler_query {
3564            self.gpu_profiler.finish_sampler(sampler);
3565        }
3566    }
3567
3568    fn draw_blurs(
3569        &mut self,
3570        blurs: &FastHashMap<TextureSource, FrameVec<BlurInstance>>,
3571        stats: &mut RendererStats,
3572    ) {
3573        for (texture, blurs) in blurs {
3574            let textures = BatchTextures::composite_rgb(
3575                *texture,
3576            );
3577
3578            self.draw_instanced_batch(
3579                blurs,
3580                VertexArrayKind::Blur,
3581                &textures,
3582                stats,
3583            );
3584        }
3585    }
3586
3587    /// Draw all the instances in a clip batcher list to the current target.
3588    fn draw_clip_batch_list(
3589        &mut self,
3590        list: &ClipBatchList,
3591        projection: &default::Transform3D<f32>,
3592        stats: &mut RendererStats,
3593    ) {
3594        if self.debug_flags.contains(DebugFlags::DISABLE_CLIP_MASKS) {
3595            return;
3596        }
3597
3598        // draw rounded cornered rectangles
3599        if !list.slow_rectangles.is_empty() {
3600            let _gm2 = self.gpu_profiler.start_marker("slow clip rectangles");
3601            self.shaders.borrow_mut().cs_clip_rectangle_slow().bind(
3602                &mut self.device,
3603                projection,
3604                None,
3605                &mut self.renderer_errors,
3606                &mut self.profile,
3607                &mut self.command_log,
3608            );
3609            self.draw_instanced_batch(
3610                &list.slow_rectangles,
3611                VertexArrayKind::ClipRect,
3612                &BatchTextures::empty(),
3613                stats,
3614            );
3615        }
3616        if !list.fast_rectangles.is_empty() {
3617            let _gm2 = self.gpu_profiler.start_marker("fast clip rectangles");
3618            self.shaders.borrow_mut().cs_clip_rectangle_fast().bind(
3619                &mut self.device,
3620                projection,
3621                None,
3622                &mut self.renderer_errors,
3623                &mut self.profile,
3624                &mut self.command_log,
3625            );
3626            self.draw_instanced_batch(
3627                &list.fast_rectangles,
3628                VertexArrayKind::ClipRect,
3629                &BatchTextures::empty(),
3630                stats,
3631            );
3632        }
3633
3634    }
3635
3636    fn bind_frame_data(&mut self, frame: &mut Frame) {
3637        profile_scope!("bind_frame_data");
3638
3639        let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_DATA);
3640
3641        self.vertex_data_textures[self.current_vertex_data_textures].update(
3642            &mut self.device,
3643            &mut self.texture_upload_pbo_pool,
3644            frame,
3645        );
3646        self.current_vertex_data_textures =
3647            (self.current_vertex_data_textures + 1) % VERTEX_DATA_TEXTURE_COUNT;
3648
3649        if let Some(texture) = &self.gpu_buffer_texture_f {
3650            self.device.bind_texture(
3651                TextureSampler::GpuBufferF,
3652                &texture,
3653                Swizzle::default(),
3654            );
3655        }
3656
3657        if let Some(texture) = &self.gpu_buffer_texture_i {
3658            self.device.bind_texture(
3659                TextureSampler::GpuBufferI,
3660                &texture,
3661                Swizzle::default(),
3662            );
3663        }
3664    }
3665
3666    fn update_native_surfaces(&mut self) {
3667        profile_scope!("update_native_surfaces");
3668
3669        match self.compositor_config {
3670            CompositorConfig::Native { ref mut compositor, .. } => {
3671                for op in self.pending_native_surface_updates.drain(..) {
3672                    match op.details {
3673                        NativeSurfaceOperationDetails::CreateSurface { id, virtual_offset, tile_size, is_opaque } => {
3674                            let _inserted = self.allocated_native_surfaces.insert(id);
3675                            debug_assert!(_inserted, "bug: creating existing surface");
3676                            compositor.create_surface(
3677                                    &mut self.device,
3678                                    id,
3679                                    virtual_offset,
3680                                    tile_size,
3681                                    is_opaque,
3682                            );
3683                        }
3684                        NativeSurfaceOperationDetails::CreateExternalSurface { id, is_opaque } => {
3685                            let _inserted = self.allocated_native_surfaces.insert(id);
3686                            debug_assert!(_inserted, "bug: creating existing surface");
3687                            compositor.create_external_surface(
3688                                &mut self.device,
3689                                id,
3690                                is_opaque,
3691                            );
3692                        }
3693                        NativeSurfaceOperationDetails::CreateBackdropSurface { id, color } => {
3694                            let _inserted = self.allocated_native_surfaces.insert(id);
3695                            debug_assert!(_inserted, "bug: creating existing surface");
3696                            compositor.create_backdrop_surface(
3697                                &mut self.device,
3698                                id,
3699                                color,
3700                            );
3701                        }
3702                        NativeSurfaceOperationDetails::DestroySurface { id } => {
3703                            let _existed = self.allocated_native_surfaces.remove(&id);
3704                            debug_assert!(_existed, "bug: removing unknown surface");
3705                            compositor.destroy_surface(&mut self.device, id);
3706                        }
3707                        NativeSurfaceOperationDetails::CreateTile { id } => {
3708                            compositor.create_tile(&mut self.device, id);
3709                        }
3710                        NativeSurfaceOperationDetails::DestroyTile { id } => {
3711                            compositor.destroy_tile(&mut self.device, id);
3712                        }
3713                        NativeSurfaceOperationDetails::AttachExternalImage { id, external_image } => {
3714                            compositor.attach_external_image(&mut self.device, id, external_image);
3715                        }
3716                    }
3717                }
3718            }
3719            CompositorConfig::Draw { .. } | CompositorConfig::Layer { .. } => {
3720                // Ensure nothing is added in simple composite mode, since otherwise
3721                // memory will leak as this doesn't get drained
3722                debug_assert!(self.pending_native_surface_updates.is_empty());
3723            }
3724        }
3725    }
3726
3727    fn update_gpu_buffer_texture<T: Texel>(
3728        device: &mut Device,
3729        buffer: &GpuBuffer<T>,
3730        dst_texture: &mut Option<Texture>,
3731        pbo_pool: &mut UploadPBOPool,
3732    ) {
3733        if buffer.is_empty() {
3734            return;
3735        }
3736
3737        if let Some(texture) = dst_texture {
3738            assert!(texture.get_dimensions().width == buffer.size.width);
3739            if texture.get_dimensions().height < buffer.size.height {
3740                device.delete_texture(dst_texture.take().unwrap());
3741            }
3742        }
3743
3744        if dst_texture.is_none() {
3745            let height = ((buffer.size.height + 7) & !7).max(8);
3746            assert!(height >= buffer.size.height);
3747            *dst_texture = Some(
3748                device.create_texture(
3749                    ImageBufferKind::Texture2D,
3750                    buffer.format,
3751                    buffer.size.width,
3752                    height,
3753                    TextureFilter::Nearest,
3754                    None,
3755                )
3756            );
3757        }
3758
3759        let mut uploader = device.upload_texture(pbo_pool);
3760
3761        uploader.upload(
3762            device,
3763            dst_texture.as_mut().unwrap(),
3764            DeviceIntRect {
3765                min: DeviceIntPoint::zero(),
3766                max: DeviceIntPoint::new(buffer.size.width, buffer.size.height),
3767            },
3768            None,
3769            None,
3770            buffer.data.as_ptr(),
3771            buffer.data.len(),
3772        );
3773
3774        uploader.flush(device);
3775    }
3776
3777    fn maybe_evict_gpu_buffer_texture(
3778        device: &mut Device,
3779        gpu_buffer_height: i32,
3780        texture: &mut Option<Texture>,
3781        texture_too_large: &mut i32,
3782    ) {
3783        if let Some(tex) = texture {
3784            if tex.get_dimensions().height > gpu_buffer_height * 2 {
3785                *texture_too_large += 1;
3786            } else {
3787                *texture_too_large = 0;
3788            }
3789        }
3790
3791        // Delete the texture if it has been too large for 10 frames
3792        // or more.
3793        if *texture_too_large > 10 {
3794            device.delete_texture(texture.take().unwrap());
3795            *texture_too_large = 0;
3796        }
3797    }
3798
3799    fn draw_frame(
3800        &mut self,
3801        frame: &mut Frame,
3802        device_size: Option<DeviceIntSize>,
3803        buffer_age: usize,
3804        results: &mut RenderResults,
3805    ) {
3806        profile_scope!("draw_frame");
3807
3808        // These markers seem to crash a lot on Android, see bug 1559834
3809        #[cfg(not(target_os = "android"))]
3810        let _gm = self.gpu_profiler.start_marker("draw frame");
3811
3812        if frame.passes.is_empty() {
3813            frame.has_been_rendered = true;
3814            return;
3815        }
3816
3817        {
3818            let _gm = self.gpu_profiler.start_marker("gpu buffer update");
3819
3820            Self::update_gpu_buffer_texture(
3821                &mut self.device,
3822                &frame.gpu_buffer_f,
3823                &mut self.gpu_buffer_texture_f,
3824                &mut self.texture_upload_pbo_pool,
3825            );
3826            Self::update_gpu_buffer_texture(
3827                &mut self.device,
3828                &frame.gpu_buffer_i,
3829                &mut self.gpu_buffer_texture_i,
3830                &mut self.texture_upload_pbo_pool,
3831            );
3832        }
3833
3834        self.device.disable_depth_write();
3835        self.set_blend(false, FramebufferKind::Other);
3836        self.device.disable_stencil();
3837
3838        self.bind_frame_data(frame);
3839
3840        let bytes_to_mb = 1.0 / 1000000.0;
3841        let gpu_buffer_bytes_f = frame.gpu_buffer_f.size.to_f32().area() * 16.0;
3842        let gpu_buffer_bytes_i = frame.gpu_buffer_i.size.to_f32().area() * 16.0;
3843        let gpu_buffer_mb = (gpu_buffer_bytes_f + gpu_buffer_bytes_i) as f32 * bytes_to_mb;
3844        self.profile.set(profiler::GPU_BUFFER_MEM, gpu_buffer_mb);
3845
3846        // Determine the present mode and dirty rects, if device_size
3847        // is Some(..). If it's None, no composite will occur and only
3848        // picture cache and texture cache targets will be updated.
3849        // TODO(gw): Split Frame so that it's clearer when a composite
3850        //           is occurring.
3851        let present_mode = device_size.and_then(|device_size| {
3852            self.calculate_dirty_rects(
3853                buffer_age,
3854                &frame.composite_state,
3855                device_size,
3856                results,
3857            )
3858        });
3859
3860        // If we have a native OS compositor, then make use of that interface to
3861        // specify how to composite each of the picture cache surfaces. First, we
3862        // need to find each tile that may be bound and updated later in the frame
3863        // and invalidate it so that the native render compositor knows that these
3864        // tiles can't be composited early. Next, after all such tiles have been
3865        // invalidated, then we queue surfaces for native composition by the render
3866        // compositor before we actually update the tiles. This allows the render
3867        // compositor to start early composition while the tiles are updating.
3868        if let CompositorKind::Native { .. } = self.current_compositor_kind {
3869            let compositor = self.compositor_config.compositor().unwrap();
3870            // Invalidate any native surface tiles that might be updated by passes.
3871            if !frame.has_been_rendered {
3872                for tile in &frame.composite_state.tiles {
3873                    if !tile.local_dirty_rect.is_empty() {
3874                        if let CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { id, .. } } = tile.surface {
3875                            let valid_rect = frame.composite_state.get_surface_rect(
3876                                &tile.local_valid_rect,
3877                                &tile.local_rect,
3878                                tile.transform_index,
3879                            ).to_i32();
3880
3881                            compositor.invalidate_tile(&mut self.device, id, valid_rect);
3882                        }
3883                    }
3884                }
3885            }
3886            // Ensure any external surfaces that might be used during early composition
3887            // are invalidated first so that the native compositor can properly schedule
3888            // composition to happen only when the external surface is updated.
3889            // See update_external_native_surfaces for more details.
3890            for surface in &frame.composite_state.external_surfaces {
3891                if let Some((native_surface_id, size)) = surface.update_params {
3892                    let surface_rect = size.into();
3893                    compositor.invalidate_tile(&mut self.device, NativeTileId { surface_id: native_surface_id, x: 0, y: 0 }, surface_rect);
3894                }
3895            }
3896            // Finally queue native surfaces for early composition, if applicable. By now,
3897            // we have already invalidated any tiles that such surfaces may depend upon, so
3898            // the native render compositor can keep track of when to actually schedule
3899            // composition as surfaces are updated.
3900            if device_size.is_some() {
3901                frame.composite_state.composite_native(
3902                    self.clear_color,
3903                    &results.dirty_rects,
3904                    &mut self.device,
3905                    &mut **compositor,
3906                );
3907            }
3908        }
3909
3910        for (_pass_index, pass) in frame.passes.iter_mut().enumerate() {
3911            #[cfg(not(target_os = "android"))]
3912            let _gm = self.gpu_profiler.start_marker(&format!("pass {}", _pass_index));
3913
3914            profile_scope!("offscreen target");
3915
3916            // If this frame has already been drawn, then any texture
3917            // cache targets have already been updated and can be
3918            // skipped this time.
3919            if !frame.has_been_rendered {
3920                for (&texture_id, target) in &pass.texture_cache {
3921                    self.draw_render_target(
3922                        texture_id,
3923                        target,
3924                        &frame.render_tasks,
3925                        &mut results.stats,
3926                    );
3927                }
3928
3929                if !pass.picture_cache.is_empty() {
3930                    self.profile.inc(profiler::COLOR_PASSES);
3931                }
3932
3933                // Draw picture caching tiles for this pass.
3934                for picture_target in &pass.picture_cache {
3935                    results.stats.color_target_count += 1;
3936
3937                    let draw_target = match picture_target.surface {
3938                        ResolvedSurfaceTexture::TextureCache { ref texture } => {
3939                            let (texture, _) = self.texture_resolver
3940                                .resolve(texture)
3941                                .expect("bug");
3942
3943                            DrawTarget::from_texture(
3944                                texture,
3945                                true,
3946                            )
3947                        }
3948                        ResolvedSurfaceTexture::Native { id, size } => {
3949                            let surface_info = match self.current_compositor_kind {
3950                                CompositorKind::Native { .. } => {
3951                                    let compositor = self.compositor_config.compositor().unwrap();
3952                                    compositor.bind(
3953                                        &mut self.device,
3954                                        id,
3955                                        picture_target.dirty_rect,
3956                                        picture_target.valid_rect,
3957                                    )
3958                                }
3959                                CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
3960                                    unreachable!();
3961                                }
3962                            };
3963
3964                            DrawTarget::NativeSurface {
3965                                offset: surface_info.origin,
3966                                external_fbo_id: surface_info.fbo_id,
3967                                dimensions: size,
3968                            }
3969                        }
3970                    };
3971
3972                    let projection = Transform3D::ortho(
3973                        0.0,
3974                        draw_target.dimensions().width as f32,
3975                        0.0,
3976                        draw_target.dimensions().height as f32,
3977                        self.device.ortho_near_plane(),
3978                        self.device.ortho_far_plane(),
3979                    );
3980
3981                    self.draw_picture_cache_target(
3982                        picture_target,
3983                        draw_target,
3984                        &projection,
3985                        &frame.render_tasks,
3986                        &mut results.stats,
3987                    );
3988
3989                    // Native OS surfaces must be unbound at the end of drawing to them
3990                    if let ResolvedSurfaceTexture::Native { .. } = picture_target.surface {
3991                        match self.current_compositor_kind {
3992                            CompositorKind::Native { .. } => {
3993                                let compositor = self.compositor_config.compositor().unwrap();
3994                                compositor.unbind(&mut self.device);
3995                            }
3996                            CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
3997                                unreachable!();
3998                            }
3999                        }
4000                    }
4001                }
4002            }
4003
4004            for target in &pass.alpha.targets {
4005                results.stats.alpha_target_count += 1;
4006                self.draw_render_target(
4007                    target.texture_id(),
4008                    target,
4009                    &frame.render_tasks,
4010                    &mut results.stats,
4011                );
4012            }
4013
4014            for target in &pass.color.targets {
4015                results.stats.color_target_count += 1;
4016                self.draw_render_target(
4017                    target.texture_id(),
4018                    target,
4019                    &frame.render_tasks,
4020                    &mut results.stats,
4021                );
4022            }
4023
4024            // Only end the pass here and invalidate previous textures for
4025            // off-screen targets. Deferring return of the inputs to the
4026            // frame buffer until the implicit end_pass in end_frame allows
4027            // debug draw overlays to be added without triggering a copy
4028            // resolve stage in mobile / tiled GPUs.
4029            self.texture_resolver.end_pass(
4030                &mut self.device,
4031                &pass.textures_to_invalidate,
4032            );
4033        }
4034
4035        self.composite_frame(
4036            frame,
4037            device_size,
4038            results,
4039            present_mode,
4040        );
4041
4042        frame.has_been_rendered = true;
4043
4044        Self::maybe_evict_gpu_buffer_texture(
4045            &mut self.device,
4046            frame.gpu_buffer_f.size.height,
4047            &mut self.gpu_buffer_texture_f,
4048            &mut self.gpu_buffer_texture_f_too_large,
4049        );
4050
4051        Self::maybe_evict_gpu_buffer_texture(
4052            &mut self.device,
4053            frame.gpu_buffer_i.size.height,
4054            &mut self.gpu_buffer_texture_i,
4055            &mut self.gpu_buffer_texture_i_too_large,
4056        );
4057    }
4058
4059    pub fn debug_renderer(&mut self) -> Option<&mut DebugRenderer> {
4060        self.debug.get_mut(&mut self.device)
4061    }
4062
4063    pub fn get_debug_flags(&self) -> DebugFlags {
4064        self.debug_flags
4065    }
4066
4067    pub fn set_debug_flags(&mut self, flags: DebugFlags) {
4068        if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_TIME_QUERIES) {
4069            if enabled {
4070                self.gpu_profiler.enable_timers();
4071            } else {
4072                self.gpu_profiler.disable_timers();
4073            }
4074        }
4075        if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_SAMPLE_QUERIES) {
4076            if enabled {
4077                self.gpu_profiler.enable_samplers();
4078            } else {
4079                self.gpu_profiler.disable_samplers();
4080            }
4081        }
4082
4083        self.debug_flags = flags;
4084    }
4085
4086    pub fn set_profiler_ui(&mut self, ui_str: &str) {
4087        self.profiler.set_ui(ui_str);
4088    }
4089
4090    fn draw_frame_debug_items(&mut self, items: &[DebugItem]) {
4091        if items.is_empty() {
4092            return;
4093        }
4094
4095        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4096            Some(render) => render,
4097            None => return,
4098        };
4099
4100        for item in items {
4101            match item {
4102                DebugItem::Rect { rect, outer_color, inner_color, thickness } => {
4103                    if inner_color.a > 0.001 {
4104                        let rect = rect.inflate(-thickness as f32, -thickness as f32);
4105                        debug_renderer.add_quad(
4106                            rect.min.x,
4107                            rect.min.y,
4108                            rect.max.x,
4109                            rect.max.y,
4110                            (*inner_color).into(),
4111                            (*inner_color).into(),
4112                        );
4113                    }
4114
4115                    if outer_color.a > 0.001 {
4116                        debug_renderer.add_rect(
4117                            &rect.to_i32(),
4118                            *thickness,
4119                            (*outer_color).into(),
4120                        );
4121                    }
4122                }
4123                DebugItem::Text { ref msg, position, color } => {
4124                    debug_renderer.add_text(
4125                        position.x,
4126                        position.y,
4127                        msg,
4128                        (*color).into(),
4129                        None,
4130                    );
4131                }
4132            }
4133        }
4134    }
4135
4136    fn draw_render_target_debug(&mut self, draw_target: &DrawTarget) {
4137        if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
4138            return;
4139        }
4140
4141        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4142            Some(render) => render,
4143            None => return,
4144        };
4145
4146        let textures = self.texture_resolver
4147            .texture_cache_map
4148            .values()
4149            .filter(|item| item.category == TextureCacheCategory::RenderTarget)
4150            .map(|item| &item.texture)
4151            .collect::<Vec<&Texture>>();
4152
4153        Self::do_debug_blit(
4154            &mut self.device,
4155            debug_renderer,
4156            textures,
4157            draw_target,
4158            0,
4159            &|_| [0.0, 1.0, 0.0, 1.0], // Use green for all RTs.
4160        );
4161    }
4162
4163    fn draw_zoom_debug(
4164        &mut self,
4165        device_size: DeviceIntSize,
4166    ) {
4167        if !self.debug_flags.contains(DebugFlags::ZOOM_DBG) {
4168            return;
4169        }
4170
4171        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4172            Some(render) => render,
4173            None => return,
4174        };
4175
4176        let source_size = DeviceIntSize::new(64, 64);
4177        let target_size = DeviceIntSize::new(1024, 1024);
4178
4179        let source_origin = DeviceIntPoint::new(
4180            (self.cursor_position.x - source_size.width / 2)
4181                .min(device_size.width - source_size.width)
4182                .max(0),
4183            (self.cursor_position.y - source_size.height / 2)
4184                .min(device_size.height - source_size.height)
4185                .max(0),
4186        );
4187
4188        let source_rect = DeviceIntRect::from_origin_and_size(
4189            source_origin,
4190            source_size,
4191        );
4192
4193        let target_rect = DeviceIntRect::from_origin_and_size(
4194            DeviceIntPoint::new(
4195                device_size.width - target_size.width - 64,
4196                device_size.height - target_size.height - 64,
4197            ),
4198            target_size,
4199        );
4200
4201        let texture_rect = FramebufferIntRect::from_size(
4202            source_rect.size().cast_unit(),
4203        );
4204
4205        debug_renderer.add_rect(
4206            &target_rect.inflate(1, 1),
4207            1,
4208            debug_colors::RED.into(),
4209        );
4210
4211        if self.zoom_debug_texture.is_none() {
4212            let texture = self.device.create_texture(
4213                ImageBufferKind::Texture2D,
4214                ImageFormat::BGRA8,
4215                source_rect.width(),
4216                source_rect.height(),
4217                TextureFilter::Nearest,
4218                Some(RenderTargetInfo { has_depth: false }),
4219            );
4220
4221            self.zoom_debug_texture = Some(texture);
4222        }
4223
4224        // Copy frame buffer into the zoom texture
4225        let read_target = DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left());
4226        self.device.blit_render_target(
4227            read_target.into(),
4228            read_target.to_framebuffer_rect(source_rect),
4229            DrawTarget::from_texture(
4230                self.zoom_debug_texture.as_ref().unwrap(),
4231                false,
4232            ),
4233            texture_rect,
4234            TextureFilter::Nearest,
4235        );
4236
4237        // Draw the zoom texture back to the framebuffer
4238        self.device.blit_render_target(
4239            ReadTarget::from_texture(
4240                self.zoom_debug_texture.as_ref().unwrap(),
4241            ),
4242            texture_rect,
4243            read_target,
4244            read_target.to_framebuffer_rect(target_rect),
4245            TextureFilter::Nearest,
4246        );
4247    }
4248
4249    fn draw_texture_cache_debug(&mut self, draw_target: &DrawTarget) {
4250        if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
4251            return;
4252        }
4253
4254        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4255            Some(render) => render,
4256            None => return,
4257        };
4258
4259        let textures = self.texture_resolver
4260            .texture_cache_map
4261            .values()
4262            .filter(|item| item.category == TextureCacheCategory::Atlas)
4263            .map(|item| &item.texture)
4264            .collect::<Vec<&Texture>>();
4265
4266        fn select_color(texture: &Texture) -> [f32; 4] {
4267            if texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE) {
4268                [1.0, 0.5, 0.0, 1.0] // Orange for shared.
4269            } else {
4270                [1.0, 0.0, 1.0, 1.0] // Fuchsia for standalone.
4271            }
4272        }
4273
4274        Self::do_debug_blit(
4275            &mut self.device,
4276            debug_renderer,
4277            textures,
4278            draw_target,
4279            if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) { 544 } else { 0 },
4280            &select_color,
4281        );
4282    }
4283
4284    fn do_debug_blit(
4285        device: &mut Device,
4286        debug_renderer: &mut DebugRenderer,
4287        mut textures: Vec<&Texture>,
4288        draw_target: &DrawTarget,
4289        bottom: i32,
4290        select_color: &dyn Fn(&Texture) -> [f32; 4],
4291    ) {
4292        let mut spacing = 16;
4293        let mut size = 512;
4294
4295        let device_size = draw_target.dimensions();
4296        let fb_width = device_size.width;
4297        let fb_height = device_size.height;
4298        let surface_origin_is_top_left = draw_target.surface_origin_is_top_left();
4299
4300        let num_textures = textures.len() as i32;
4301
4302        if num_textures * (size + spacing) > fb_width {
4303            let factor = fb_width as f32 / (num_textures * (size + spacing)) as f32;
4304            size = (size as f32 * factor) as i32;
4305            spacing = (spacing as f32 * factor) as i32;
4306        }
4307
4308        let text_height = 14; // Visually approximated.
4309        let text_margin = 1;
4310        let tag_height = text_height + text_margin * 2;
4311        let tag_y = fb_height - (bottom + spacing + tag_height);
4312        let image_y = tag_y - size;
4313
4314        // Sort the display by size (in bytes), so that left-to-right is
4315        // largest-to-smallest.
4316        //
4317        // Note that the vec here is in increasing order, because the elements
4318        // get drawn right-to-left.
4319        textures.sort_by_key(|t| t.size_in_bytes());
4320
4321        let mut i = 0;
4322        for texture in textures.iter() {
4323            let dimensions = texture.get_dimensions();
4324            let src_rect = FramebufferIntRect::from_size(
4325                FramebufferIntSize::new(dimensions.width as i32, dimensions.height as i32),
4326            );
4327
4328            let x = fb_width - (spacing + size) * (i as i32 + 1);
4329
4330            // If we have more targets than fit on one row in screen, just early exit.
4331            if x > fb_width {
4332                return;
4333            }
4334
4335            // Draw the info tag.
4336            let tag_rect = rect(x, tag_y, size, tag_height).to_box2d();
4337            let tag_color = select_color(texture);
4338            device.clear_target(
4339                Some(tag_color),
4340                None,
4341                Some(draw_target.to_framebuffer_rect(tag_rect)),
4342            );
4343
4344            // Draw the dimensions onto the tag.
4345            let dim = texture.get_dimensions();
4346            let text_rect = tag_rect.inflate(-text_margin, -text_margin);
4347            debug_renderer.add_text(
4348                text_rect.min.x as f32,
4349                text_rect.max.y as f32, // Top-relative.
4350                &format!("{}x{}", dim.width, dim.height),
4351                ColorU::new(0, 0, 0, 255),
4352                Some(tag_rect.to_f32())
4353            );
4354
4355            // Blit the contents of the texture.
4356            let dest_rect = draw_target.to_framebuffer_rect(rect(x, image_y, size, size).to_box2d());
4357            let read_target = ReadTarget::from_texture(texture);
4358
4359            if surface_origin_is_top_left {
4360                device.blit_render_target(
4361                    read_target,
4362                    src_rect,
4363                    *draw_target,
4364                    dest_rect,
4365                    TextureFilter::Linear,
4366                );
4367            } else {
4368                 // Invert y.
4369                 device.blit_render_target_invert_y(
4370                    read_target,
4371                    src_rect,
4372                    *draw_target,
4373                    dest_rect,
4374                );
4375            }
4376            i += 1;
4377        }
4378    }
4379
4380    fn draw_epoch_debug(&mut self) {
4381        if !self.debug_flags.contains(DebugFlags::EPOCHS) {
4382            return;
4383        }
4384
4385        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4386            Some(render) => render,
4387            None => return,
4388        };
4389
4390        let dy = debug_renderer.line_height();
4391        let x0: f32 = 30.0;
4392        let y0: f32 = 30.0;
4393        let mut y = y0;
4394        let mut text_width = 0.0;
4395        for ((pipeline, document_id), epoch) in  &self.pipeline_info.epochs {
4396            y += dy;
4397            let w = debug_renderer.add_text(
4398                x0, y,
4399                &format!("({:?}, {:?}): {:?}", pipeline, document_id, epoch),
4400                ColorU::new(255, 255, 0, 255),
4401                None,
4402            ).size.width;
4403            text_width = f32::max(text_width, w);
4404        }
4405
4406        let margin = 10.0;
4407        debug_renderer.add_quad(
4408            x0 - margin,
4409            y0 - margin,
4410            x0 + text_width + margin,
4411            y + margin,
4412            ColorU::new(25, 25, 25, 200),
4413            ColorU::new(51, 51, 51, 200),
4414        );
4415    }
4416
4417    fn draw_window_visibility_debug(&mut self) {
4418        if !self.debug_flags.contains(DebugFlags::WINDOW_VISIBILITY_DBG) {
4419            return;
4420        }
4421
4422        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4423            Some(render) => render,
4424            None => return,
4425        };
4426
4427        let x: f32 = 30.0;
4428        let y: f32 = 40.0;
4429
4430        if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config {
4431            let visibility = compositor.get_window_visibility(&mut self.device);
4432            let color = if visibility.is_fully_occluded {
4433                ColorU::new(255, 0, 0, 255)
4434
4435            } else {
4436                ColorU::new(0, 0, 255, 255)
4437            };
4438
4439            debug_renderer.add_text(
4440                x, y,
4441                &format!("{:?}", visibility),
4442                color,
4443                None,
4444            );
4445        }
4446
4447
4448    }
4449
4450    fn draw_external_composite_borders_debug(&mut self) {
4451        if !self.debug_flags.contains(DebugFlags::EXTERNAL_COMPOSITE_BORDERS) {
4452            return;
4453        }
4454
4455        let debug_renderer = match self.debug.get_mut(&mut self.device) {
4456            Some(render) => render,
4457            None => return,
4458        };
4459
4460        for item in &self.external_composite_debug_items {
4461            match item {
4462                DebugItem::Rect { rect, outer_color, inner_color: _, thickness } => {
4463                    if outer_color.a > 0.001 {
4464                        debug_renderer.add_rect(
4465                            &rect.to_i32(),
4466                            *thickness,
4467                            (*outer_color).into(),
4468                        );
4469                    }
4470                }
4471                DebugItem::Text { .. } => {}
4472            }
4473        }
4474    }
4475
4476    /// Pass-through to `Device::read_pixels_into`, used by Gecko's WR bindings.
4477    pub fn read_pixels_into(&mut self, rect: FramebufferIntRect, format: ImageFormat, output: &mut [u8]) {
4478        self.device.read_pixels_into(rect, format, output);
4479    }
4480
4481    pub fn read_pixels_rgba8(&mut self, rect: FramebufferIntRect) -> Vec<u8> {
4482        let mut pixels = vec![0; (rect.area() * 4) as usize];
4483        self.device.read_pixels_into(rect, ImageFormat::RGBA8, &mut pixels);
4484        pixels
4485    }
4486
4487    // De-initialize the Renderer safely, assuming the GL is still alive and active.
4488    pub fn deinit(mut self) {
4489        //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
4490        self.device.begin_frame();
4491        // If we are using a native compositor, ensure that any remaining native
4492        // surfaces are freed.
4493        if let CompositorConfig::Native { mut compositor, .. } = self.compositor_config {
4494            for id in self.allocated_native_surfaces.drain() {
4495                compositor.destroy_surface(&mut self.device, id);
4496            }
4497            // Destroy the debug overlay surface, if currently allocated.
4498            if self.debug_overlay_state.current_size.is_some() {
4499                compositor.destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
4500            }
4501            compositor.deinit(&mut self.device);
4502        }
4503        if let Some(dither_matrix_texture) = self.dither_matrix_texture {
4504            self.device.delete_texture(dither_matrix_texture);
4505        }
4506        if let Some(zoom_debug_texture) = self.zoom_debug_texture {
4507            self.device.delete_texture(zoom_debug_texture);
4508        }
4509        if let Some(texture) = self.gpu_buffer_texture_f {
4510            self.device.delete_texture(texture);
4511        }
4512        if let Some(texture) = self.gpu_buffer_texture_i {
4513            self.device.delete_texture(texture);
4514        }
4515        for textures in self.vertex_data_textures.drain(..) {
4516            textures.deinit(&mut self.device);
4517        }
4518        self.texture_upload_pbo_pool.deinit(&mut self.device);
4519        self.staging_texture_pool.delete_textures(&mut self.device);
4520        self.texture_resolver.deinit(&mut self.device);
4521        self.vaos.deinit(&mut self.device);
4522        self.debug.deinit(&mut self.device);
4523
4524        if let Ok(shaders) = Rc::try_unwrap(self.shaders) {
4525            shaders.into_inner().deinit(&mut self.device);
4526        }
4527
4528        if let Some(async_screenshots) = self.async_screenshots.take() {
4529            async_screenshots.deinit(&mut self.device);
4530        }
4531
4532        if let Some(async_frame_recorder) = self.async_frame_recorder.take() {
4533            async_frame_recorder.deinit(&mut self.device);
4534        }
4535
4536        #[cfg(feature = "capture")]
4537        self.device.delete_fbo(self.read_fbo);
4538        #[cfg(feature = "replay")]
4539        for (_, ext) in self.owned_external_images {
4540            self.device.delete_external_texture(ext);
4541        }
4542        self.device.end_frame();
4543    }
4544
4545    /// Collects a memory report.
4546    pub fn report_memory(&self, swgl: *mut c_void) -> MemoryReport {
4547        let mut report = MemoryReport::default();
4548
4549        self.staging_texture_pool.report_memory_to(&mut report, self.size_of_ops.as_ref().unwrap());
4550
4551        // Render task CPU memory.
4552        for (_id, doc) in &self.active_documents {
4553            let frame_alloc_stats = doc.frame.allocator_memory.get_stats();
4554            report.frame_allocator += frame_alloc_stats.reserved_bytes;
4555            report.render_tasks += doc.frame.render_tasks.report_memory();
4556        }
4557
4558        // Vertex data GPU memory.
4559        for textures in &self.vertex_data_textures {
4560            report.vertex_data_textures += textures.size_in_bytes();
4561        }
4562
4563        // Texture cache and render target GPU memory.
4564        report += self.texture_resolver.report_memory();
4565
4566        // Texture upload PBO memory.
4567        report += self.texture_upload_pbo_pool.report_memory();
4568
4569        // Textures held internally within the device layer.
4570        report += self.device.report_memory(self.size_of_ops.as_ref().unwrap(), swgl);
4571
4572        report
4573    }
4574
4575    // Sets the blend mode. Blend is unconditionally set if the "show overdraw" debugging mode is
4576    // enabled.
4577    fn set_blend(&mut self, mut blend: bool, framebuffer_kind: FramebufferKind) {
4578        if framebuffer_kind == FramebufferKind::Main &&
4579                self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4580            blend = true
4581        }
4582        self.device.set_blend(blend)
4583    }
4584
4585    fn set_blend_mode_multiply(&mut self, framebuffer_kind: FramebufferKind) {
4586        if framebuffer_kind == FramebufferKind::Main &&
4587                self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4588            self.device.set_blend_mode_show_overdraw();
4589        } else {
4590            self.device.set_blend_mode_multiply();
4591        }
4592    }
4593
4594    fn set_blend_mode_premultiplied_alpha(&mut self, framebuffer_kind: FramebufferKind) {
4595        if framebuffer_kind == FramebufferKind::Main &&
4596                self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4597            self.device.set_blend_mode_show_overdraw();
4598        } else {
4599            self.device.set_blend_mode_premultiplied_alpha();
4600        }
4601    }
4602
4603    /// Clears the texture with a given color.
4604    fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
4605        self.device.bind_draw_target(DrawTarget::from_texture(
4606            &texture,
4607            false,
4608        ));
4609        self.device.clear_target(Some(color), None, None);
4610    }
4611}
4612
4613bitflags! {
4614    /// Flags that control how shaders are pre-cached, if at all.
4615    #[derive(Default, Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
4616    pub struct ShaderPrecacheFlags: u32 {
4617        /// Needed for const initialization
4618        const EMPTY                 = 0;
4619
4620        /// Only start async compile
4621        const ASYNC_COMPILE         = 1 << 2;
4622
4623        /// Do a full compile/link during startup
4624        const FULL_COMPILE          = 1 << 3;
4625    }
4626}
4627
4628/// The cumulative times spent in each painting phase to generate this frame.
4629#[derive(Debug, Default)]
4630pub struct FullFrameStats {
4631    pub full_display_list: bool,
4632    pub gecko_display_list_time: f64,
4633    pub wr_display_list_time: f64,
4634    pub scene_build_time: f64,
4635    pub frame_build_time: f64,
4636}
4637
4638impl FullFrameStats {
4639    pub fn merge(&self, other: &FullFrameStats) -> Self {
4640        Self {
4641            full_display_list: self.full_display_list || other.full_display_list,
4642            gecko_display_list_time: self.gecko_display_list_time + other.gecko_display_list_time,
4643            wr_display_list_time: self.wr_display_list_time + other.wr_display_list_time,
4644            scene_build_time: self.scene_build_time + other.scene_build_time,
4645            frame_build_time: self.frame_build_time + other.frame_build_time
4646        }
4647    }
4648
4649    pub fn total(&self) -> f64 {
4650      self.gecko_display_list_time + self.wr_display_list_time + self.scene_build_time + self.frame_build_time
4651    }
4652}
4653
4654/// Some basic statistics about the rendered scene, used in Gecko, as
4655/// well as in wrench reftests to ensure that tests are batching and/or
4656/// allocating on render targets as we expect them to.
4657#[repr(C)]
4658#[derive(Debug, Default)]
4659pub struct RendererStats {
4660    pub total_draw_calls: usize,
4661    pub alpha_target_count: usize,
4662    pub color_target_count: usize,
4663    pub texture_upload_mb: f64,
4664    pub resource_upload_time: f64,
4665    pub gecko_display_list_time: f64,
4666    pub wr_display_list_time: f64,
4667    pub scene_build_time: f64,
4668    pub frame_build_time: f64,
4669    pub full_display_list: bool,
4670    pub full_paint: bool,
4671}
4672
4673impl RendererStats {
4674    pub fn merge(&mut self, stats: &FullFrameStats) {
4675        self.gecko_display_list_time = stats.gecko_display_list_time;
4676        self.wr_display_list_time = stats.wr_display_list_time;
4677        self.scene_build_time = stats.scene_build_time;
4678        self.frame_build_time = stats.frame_build_time;
4679        self.full_display_list = stats.full_display_list;
4680        self.full_paint = true;
4681    }
4682}
4683
4684/// Return type from render(), which contains some repr(C) statistics as well as
4685/// some non-repr(C) data.
4686#[derive(Debug, Default)]
4687pub struct RenderResults {
4688    /// Statistics about the frame that was rendered.
4689    pub stats: RendererStats,
4690
4691    /// A list of the device dirty rects that were updated
4692    /// this frame.
4693    /// TODO(gw): This is an initial interface, likely to change in future.
4694    /// TODO(gw): The dirty rects here are currently only useful when scrolling
4695    ///           is not occurring. They are still correct in the case of
4696    ///           scrolling, but will be very large (until we expose proper
4697    ///           OS compositor support where the dirty rects apply to a
4698    ///           specific picture cache slice / OS compositor surface).
4699    pub dirty_rects: Vec<DeviceIntRect>,
4700
4701    /// Information about the state of picture cache tiles. This is only
4702    /// allocated and stored if config.testing is true (such as wrench)
4703    pub picture_cache_debug: PictureCacheDebugInfo,
4704
4705    /// Whether any tile was rasterized (had is_valid = false)
4706    pub did_rasterize_any_tile: bool,
4707}
4708
4709#[cfg(any(feature = "capture", feature = "replay"))]
4710#[cfg_attr(feature = "capture", derive(Serialize))]
4711#[cfg_attr(feature = "replay", derive(Deserialize))]
4712struct PlainTexture {
4713    data: String,
4714    size: DeviceIntSize,
4715    format: ImageFormat,
4716    filter: TextureFilter,
4717    has_depth: bool,
4718    category: Option<TextureCacheCategory>,
4719}
4720
4721
4722#[cfg(any(feature = "capture", feature = "replay"))]
4723#[cfg_attr(feature = "capture", derive(Serialize))]
4724#[cfg_attr(feature = "replay", derive(Deserialize))]
4725struct PlainRenderer {
4726    device_size: Option<DeviceIntSize>,
4727    textures: FastHashMap<CacheTextureId, PlainTexture>,
4728}
4729
4730#[cfg(any(feature = "capture", feature = "replay"))]
4731#[cfg_attr(feature = "capture", derive(Serialize))]
4732#[cfg_attr(feature = "replay", derive(Deserialize))]
4733struct PlainExternalResources {
4734    images: Vec<ExternalCaptureImage>
4735}
4736
4737#[cfg(feature = "replay")]
4738enum CapturedExternalImageData {
4739    NativeTexture(gl::GLuint),
4740    Buffer(Arc<Vec<u8>>),
4741}
4742
4743#[cfg(feature = "replay")]
4744struct DummyExternalImageHandler {
4745    data: FastHashMap<(ExternalImageId, u8), (CapturedExternalImageData, TexelRect)>,
4746}
4747
4748#[cfg(feature = "replay")]
4749impl ExternalImageHandler for DummyExternalImageHandler {
4750    fn lock(&mut self, key: ExternalImageId, channel_index: u8, _is_composited: bool) -> ExternalImage {
4751        let (ref captured_data, ref uv) = self.data[&(key, channel_index)];
4752        ExternalImage {
4753            uv: *uv,
4754            source: match *captured_data {
4755                CapturedExternalImageData::NativeTexture(tid) => ExternalImageSource::NativeTexture(tid),
4756                CapturedExternalImageData::Buffer(ref arc) => ExternalImageSource::RawData(&*arc),
4757            }
4758        }
4759    }
4760    fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
4761}
4762
4763#[derive(Default)]
4764pub struct PipelineInfo {
4765    pub epochs: FastHashMap<(PipelineId, DocumentId), Epoch>,
4766    pub removed_pipelines: Vec<(PipelineId, DocumentId)>,
4767}
4768
4769impl Renderer {
4770    #[cfg(feature = "capture")]
4771    fn save_texture(
4772        texture: &Texture, category: Option<TextureCacheCategory>, name: &str, root: &PathBuf, device: &mut Device
4773    ) -> PlainTexture {
4774        use std::fs;
4775        use std::io::Write;
4776
4777        let short_path = format!("textures/{}.raw", name);
4778
4779        let bytes_per_pixel = texture.get_format().bytes_per_pixel();
4780        let read_format = texture.get_format();
4781        let rect_size = texture.get_dimensions();
4782
4783        let mut file = fs::File::create(root.join(&short_path))
4784            .expect(&format!("Unable to create {}", short_path));
4785        let bytes_per_texture = (rect_size.width * rect_size.height * bytes_per_pixel) as usize;
4786        let mut data = vec![0; bytes_per_texture];
4787
4788        //TODO: instead of reading from an FBO with `read_pixels*`, we could
4789        // read from textures directly with `get_tex_image*`.
4790
4791        let rect = device_size_as_framebuffer_size(rect_size).into();
4792
4793        device.attach_read_texture(texture);
4794        #[cfg(feature = "png")]
4795        {
4796            let mut png_data;
4797            let (data_ref, format) = match texture.get_format() {
4798                ImageFormat::RGBAF32 => {
4799                    png_data = vec![0; (rect_size.width * rect_size.height * 4) as usize];
4800                    device.read_pixels_into(rect, ImageFormat::RGBA8, &mut png_data);
4801                    (&png_data, ImageFormat::RGBA8)
4802                }
4803                fm => (&data, fm),
4804            };
4805            CaptureConfig::save_png(
4806                root.join(format!("textures/{}-{}.png", name, 0)),
4807                rect_size, format,
4808                None,
4809                data_ref,
4810            );
4811        }
4812        device.read_pixels_into(rect, read_format, &mut data);
4813        file.write_all(&data)
4814            .unwrap();
4815
4816        PlainTexture {
4817            data: short_path,
4818            size: rect_size,
4819            format: texture.get_format(),
4820            filter: texture.get_filter(),
4821            has_depth: texture.supports_depth(),
4822            category,
4823        }
4824    }
4825
4826    #[cfg(feature = "replay")]
4827    fn load_texture(
4828        target: ImageBufferKind,
4829        plain: &PlainTexture,
4830        rt_info: Option<RenderTargetInfo>,
4831        root: &PathBuf,
4832        device: &mut Device
4833    ) -> (Texture, Vec<u8>)
4834    {
4835        use std::fs::File;
4836        use std::io::Read;
4837
4838        let mut texels = Vec::new();
4839        File::open(root.join(&plain.data))
4840            .expect(&format!("Unable to open texture at {}", plain.data))
4841            .read_to_end(&mut texels)
4842            .unwrap();
4843
4844        let texture = device.create_texture(
4845            target,
4846            plain.format,
4847            plain.size.width,
4848            plain.size.height,
4849            plain.filter,
4850            rt_info,
4851        );
4852        device.upload_texture_immediate(&texture, &texels);
4853
4854        (texture, texels)
4855    }
4856
4857    #[cfg(feature = "capture")]
4858    fn save_capture(
4859        &mut self,
4860        config: CaptureConfig,
4861        deferred_images: Vec<ExternalCaptureImage>,
4862    ) {
4863        use std::fs;
4864        use std::io::Write;
4865        use api::ExternalImageData;
4866        use crate::render_api::CaptureBits;
4867
4868        let root = config.resource_root();
4869
4870        self.device.begin_frame();
4871        let _gm = self.gpu_profiler.start_marker("read GPU data");
4872        self.device.bind_read_target_impl(self.read_fbo, DeviceIntPoint::zero());
4873
4874        if config.bits.contains(CaptureBits::EXTERNAL_RESOURCES) && !deferred_images.is_empty() {
4875            info!("saving external images");
4876            let mut arc_map = FastHashMap::<*const u8, String>::default();
4877            let mut tex_map = FastHashMap::<u32, String>::default();
4878            let handler = self.external_image_handler
4879                .as_mut()
4880                .expect("Unable to lock the external image handler!");
4881            for def in &deferred_images {
4882                info!("\t{}", def.short_path);
4883                let ExternalImageData { id, channel_index, image_type, .. } = def.external;
4884                // The image rendering parameter is irrelevant because no filtering happens during capturing.
4885                let ext_image = handler.lock(id, channel_index, false);
4886                let (data, short_path) = match ext_image.source {
4887                    ExternalImageSource::RawData(data) => {
4888                        let arc_id = arc_map.len() + 1;
4889                        match arc_map.entry(data.as_ptr()) {
4890                            Entry::Occupied(e) => {
4891                                (None, e.get().clone())
4892                            }
4893                            Entry::Vacant(e) => {
4894                                let short_path = format!("externals/d{}.raw", arc_id);
4895                                (Some(data.to_vec()), e.insert(short_path).clone())
4896                            }
4897                        }
4898                    }
4899                    ExternalImageSource::NativeTexture(gl_id) => {
4900                        let tex_id = tex_map.len() + 1;
4901                        match tex_map.entry(gl_id) {
4902                            Entry::Occupied(e) => {
4903                                (None, e.get().clone())
4904                            }
4905                            Entry::Vacant(e) => {
4906                                let target = match image_type {
4907                                    ExternalImageType::TextureHandle(target) => target,
4908                                    ExternalImageType::Buffer => unreachable!(),
4909                                };
4910                                info!("\t\tnative texture of target {:?}", target);
4911                                self.device.attach_read_texture_external(gl_id, target);
4912                                let data = self.device.read_pixels(&def.descriptor);
4913                                let short_path = format!("externals/t{}.raw", tex_id);
4914                                (Some(data), e.insert(short_path).clone())
4915                            }
4916                        }
4917                    }
4918                    ExternalImageSource::Invalid => {
4919                        info!("\t\tinvalid source!");
4920                        (None, String::new())
4921                    }
4922                };
4923                if let Some(bytes) = data {
4924                    fs::File::create(root.join(&short_path))
4925                        .expect(&format!("Unable to create {}", short_path))
4926                        .write_all(&bytes)
4927                        .unwrap();
4928                    #[cfg(feature = "png")]
4929                    CaptureConfig::save_png(
4930                        root.join(&short_path).with_extension("png"),
4931                        def.descriptor.size,
4932                        def.descriptor.format,
4933                        def.descriptor.stride,
4934                        &bytes,
4935                    );
4936                }
4937                let plain = PlainExternalImage {
4938                    data: short_path,
4939                    external: def.external,
4940                    uv: ext_image.uv,
4941                };
4942                config.serialize_for_resource(&plain, &def.short_path);
4943            }
4944            for def in &deferred_images {
4945                handler.unlock(def.external.id, def.external.channel_index);
4946            }
4947            let plain_external = PlainExternalResources {
4948                images: deferred_images,
4949            };
4950            config.serialize_for_resource(&plain_external, "external_resources");
4951        }
4952
4953        if config.bits.contains(CaptureBits::FRAME) {
4954            let path_textures = root.join("textures");
4955            if !path_textures.is_dir() {
4956                fs::create_dir(&path_textures).unwrap();
4957            }
4958
4959            let mut plain_self = PlainRenderer {
4960                device_size: self.device_size,
4961                textures: FastHashMap::default(),
4962            };
4963
4964            info!("saving cached textures");
4965            for (id, item) in &self.texture_resolver.texture_cache_map {
4966                let file_name = format!("cache-{}", plain_self.textures.len() + 1);
4967                info!("\t{}", file_name);
4968                let plain = Self::save_texture(&item.texture, Some(item.category), &file_name, &root, &mut self.device);
4969                plain_self.textures.insert(*id, plain);
4970            }
4971
4972            config.serialize_for_resource(&plain_self, "renderer");
4973        }
4974
4975        self.device.reset_read_target();
4976        self.device.end_frame();
4977
4978        let mut stats_file = fs::File::create(config.root.join("profiler-stats.txt"))
4979            .expect(&format!("Unable to create profiler-stats.txt"));
4980        if self.debug_flags.intersects(DebugFlags::PROFILER_DBG | DebugFlags::PROFILER_CAPTURE) {
4981            self.profiler.dump_stats(&mut stats_file).unwrap();
4982        } else {
4983            writeln!(stats_file, "Turn on PROFILER_DBG or PROFILER_CAPTURE to get stats here!").unwrap();
4984        }
4985
4986        info!("done.");
4987    }
4988
4989    #[cfg(feature = "replay")]
4990    fn load_capture(
4991        &mut self,
4992        config: CaptureConfig,
4993        plain_externals: Vec<PlainExternalImage>,
4994    ) {
4995        use std::{fs::File, io::Read};
4996
4997        info!("loading external buffer-backed images");
4998        assert!(self.texture_resolver.external_images.is_empty());
4999        let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
5000        let mut image_handler = DummyExternalImageHandler {
5001            data: FastHashMap::default(),
5002        };
5003
5004        let root = config.resource_root();
5005
5006        // Note: this is a `SCENE` level population of the external image handlers
5007        // It would put both external buffers and texture into the map.
5008        // But latter are going to be overwritten later in this function
5009        // if we are in the `FRAME` level.
5010        for plain_ext in plain_externals {
5011            let data = match raw_map.entry(plain_ext.data) {
5012                Entry::Occupied(e) => e.get().clone(),
5013                Entry::Vacant(e) => {
5014                    let mut buffer = Vec::new();
5015                    File::open(root.join(e.key()))
5016                        .expect(&format!("Unable to open {}", e.key()))
5017                        .read_to_end(&mut buffer)
5018                        .unwrap();
5019                    e.insert(Arc::new(buffer)).clone()
5020                }
5021            };
5022            let ext = plain_ext.external;
5023            let value = (CapturedExternalImageData::Buffer(data), plain_ext.uv);
5024            image_handler.data.insert((ext.id, ext.channel_index), value);
5025        }
5026
5027        if let Some(external_resources) = config.deserialize_for_resource::<PlainExternalResources, _>("external_resources") {
5028            info!("loading external texture-backed images");
5029            let mut native_map = FastHashMap::<String, gl::GLuint>::default();
5030            for ExternalCaptureImage { short_path, external, descriptor } in external_resources.images {
5031                let target = match external.image_type {
5032                    ExternalImageType::TextureHandle(target) => target,
5033                    ExternalImageType::Buffer => continue,
5034                };
5035                let plain_ext = config.deserialize_for_resource::<PlainExternalImage, _>(&short_path)
5036                    .expect(&format!("Unable to read {}.ron", short_path));
5037                let key = (external.id, external.channel_index);
5038
5039                let tid = match native_map.entry(plain_ext.data) {
5040                    Entry::Occupied(e) => e.get().clone(),
5041                    Entry::Vacant(e) => {
5042                        let plain_tex = PlainTexture {
5043                            data: e.key().clone(),
5044                            size: descriptor.size,
5045                            format: descriptor.format,
5046                            filter: TextureFilter::Linear,
5047                            has_depth: false,
5048                            category: None,
5049                        };
5050                        let t = Self::load_texture(
5051                            target,
5052                            &plain_tex,
5053                            None,
5054                            &root,
5055                            &mut self.device
5056                        );
5057                        let extex = t.0.into_external();
5058                        self.owned_external_images.insert(key, extex.clone());
5059                        e.insert(extex.internal_id()).clone()
5060                    }
5061                };
5062
5063                let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv);
5064                image_handler.data.insert(key, value);
5065            }
5066        }
5067
5068        self.device.begin_frame();
5069
5070        if let Some(renderer) = config.deserialize_for_resource::<PlainRenderer, _>("renderer") {
5071            info!("loading cached textures");
5072            self.device_size = renderer.device_size;
5073
5074            for (_id, item) in self.texture_resolver.texture_cache_map.drain() {
5075                self.device.delete_texture(item.texture);
5076            }
5077            for (id, texture) in renderer.textures {
5078                info!("\t{}", texture.data);
5079                let target = ImageBufferKind::Texture2D;
5080                let t = Self::load_texture(
5081                    target,
5082                    &texture,
5083                    Some(RenderTargetInfo { has_depth: texture.has_depth }),
5084                    &root,
5085                    &mut self.device
5086                );
5087                self.texture_resolver.texture_cache_map.insert(id, CacheTexture {
5088                    texture: t.0,
5089                    category: texture.category.unwrap_or(TextureCacheCategory::Standalone),
5090                });
5091            }
5092        } else {
5093            info!("loading cached textures");
5094            self.device.begin_frame();
5095            for (_id, item) in self.texture_resolver.texture_cache_map.drain() {
5096                self.device.delete_texture(item.texture);
5097            }
5098        }
5099        self.device.end_frame();
5100
5101        self.external_image_handler = Some(Box::new(image_handler) as Box<_>);
5102        info!("done.");
5103    }
5104}
5105
5106#[derive(Clone, Copy, PartialEq)]
5107enum FramebufferKind {
5108    Main,
5109    Other,
5110}
5111
5112fn should_skip_batch(kind: &BatchKind, flags: DebugFlags) -> bool {
5113    match kind {
5114        BatchKind::TextRun(_) => {
5115            flags.contains(DebugFlags::DISABLE_TEXT_PRIMS)
5116        }
5117        _ => false,
5118    }
5119}
5120
5121impl CompositeState {
5122    /// Use the client provided native compositor interface to add all picture
5123    /// cache tiles to the OS compositor
5124    fn composite_native(
5125        &self,
5126        clear_color: ColorF,
5127        dirty_rects: &[DeviceIntRect],
5128        device: &mut Device,
5129        compositor: &mut dyn Compositor,
5130    ) {
5131        // Add each surface to the visual tree. z-order is implicit based on
5132        // order added. Offset and clip rect apply to all tiles within this
5133        // surface.
5134        for surface in &self.descriptor.surfaces {
5135            compositor.add_surface(
5136                device,
5137                surface.surface_id.expect("bug: no native surface allocated"),
5138                surface.transform,
5139                surface.clip_rect.to_i32(),
5140                surface.image_rendering,
5141                surface.rounded_clip_rect.to_i32(),
5142                surface.rounded_clip_radii,
5143            );
5144        }
5145        compositor.start_compositing(device, clear_color, dirty_rects, &[]);
5146    }
5147}
5148
5149mod tests {
5150    #[test]
5151    fn test_buffer_damage_tracker() {
5152        use super::BufferDamageTracker;
5153        use api::units::{DevicePoint, DeviceRect, DeviceSize};
5154
5155        let mut tracker = BufferDamageTracker::default();
5156        assert_eq!(tracker.get_damage_rect(0), None);
5157        assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
5158        assert_eq!(tracker.get_damage_rect(2), Some(DeviceRect::zero()));
5159        assert_eq!(tracker.get_damage_rect(3), Some(DeviceRect::zero()));
5160
5161        let damage1 = DeviceRect::from_origin_and_size(DevicePoint::new(10.0, 10.0), DeviceSize::new(10.0, 10.0));
5162        let damage2 = DeviceRect::from_origin_and_size(DevicePoint::new(20.0, 20.0), DeviceSize::new(10.0, 10.0));
5163        let combined = damage1.union(&damage2);
5164
5165        tracker.push_dirty_rect(&damage1);
5166        assert_eq!(tracker.get_damage_rect(0), None);
5167        assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
5168        assert_eq!(tracker.get_damage_rect(2), Some(damage1));
5169        assert_eq!(tracker.get_damage_rect(3), Some(damage1));
5170
5171        tracker.push_dirty_rect(&damage2);
5172        assert_eq!(tracker.get_damage_rect(0), None);
5173        assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
5174        assert_eq!(tracker.get_damage_rect(2), Some(damage2));
5175        assert_eq!(tracker.get_damage_rect(3), Some(combined));
5176    }
5177}