1use api::{ClipMode, ColorF, ColorU, MixBlendMode};
38use api::{DocumentId, Epoch, ExternalImageHandler, RenderReasons};
39#[cfg(feature = "replay")]
40use api::ExternalImageId;
41use api::{ExternalImageSource, ExternalImageType, ImageFormat, PremultipliedColorF};
42use api::{PipelineId, ImageRendering, Checkpoint, NotificationRequest, ImageBufferKind};
43#[cfg(feature = "replay")]
44use api::ExternalImage;
45use api::FramePublishId;
46use api::units::*;
47use api::channel::{Sender, Receiver};
48pub use api::DebugFlags;
49use core::time::Duration;
50
51use crate::pattern::PatternKind;
52use crate::render_api::{DebugCommand, ApiMsg, MemoryReport};
53use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList};
54use crate::batch::ClipMaskInstanceList;
55#[cfg(any(feature = "capture", feature = "replay"))]
56use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
57use crate::composite::{CompositeState, CompositeTileSurface, CompositorInputLayer, CompositorSurfaceTransform, ResolvedExternalSurface};
58use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeFeatures, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData};
59use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation, ClipRadius};
60use crate::composite::TileKind;
61#[cfg(feature = "debugger")]
62use api::debugger::CompositorDebugInfo;
63use crate::segment::SegmentBuilder;
64use crate::{debug_colors, CompositorInputConfig, CompositorSurfaceUsage};
65use crate::device::{DepthFunction, Device, DrawTarget, ExternalTexture, GpuFrameId, UploadPBOPool};
66use crate::device::{ReadTarget, ShaderError, Texture, TextureFilter, TextureFlags, TextureSlot, Texel};
67use crate::device::query::{GpuSampler, GpuTimer};
68#[cfg(feature = "capture")]
69use crate::device::FBOId;
70use crate::debug_item::DebugItem;
71use crate::frame_builder::Frame;
72use glyph_rasterizer::GlyphFormat;
73use crate::gpu_cache::{GpuCacheUpdate, GpuCacheUpdateList};
74use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
75use crate::gpu_types::{ScalingInstance, SvgFilterInstance, SVGFEFilterInstance, CopyInstance, PrimitiveInstanceData};
76use crate::gpu_types::{BlurInstance, ClearInstance, CompositeInstance, ZBufferId};
77use crate::internal_types::{TextureSource, TextureSourceExternal, TextureCacheCategory, FrameId, FrameVec};
78#[cfg(any(feature = "capture", feature = "replay"))]
79use crate::internal_types::DebugOutput;
80use crate::internal_types::{CacheTextureId, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
81use crate::internal_types::{TextureCacheAllocInfo, TextureCacheAllocationKind, TextureUpdateList};
82use crate::internal_types::{RenderTargetInfo, Swizzle, DeferredResolveIndex};
83use crate::picture::{ResolvedSurfaceTexture, TileId};
84use crate::prim_store::DeferredResolve;
85use crate::profiler::{self, GpuProfileTag, TransactionProfile};
86use crate::profiler::{Profiler, add_event_marker, add_text_marker, thread_is_being_profiled};
87use crate::device::query::GpuProfiler;
88use crate::render_target::ResolveOp;
89use crate::render_task_graph::RenderTaskGraph;
90use crate::render_task::{RenderTask, RenderTaskKind, ReadbackTask};
91use crate::screen_capture::AsyncScreenshotGrabber;
92use crate::render_target::{RenderTarget, PictureCacheTarget, PictureCacheTargetKind};
93use crate::render_target::{RenderTargetKind, BlitJob};
94use crate::telemetry::Telemetry;
95use crate::tile_cache::PictureCacheDebugInfo;
96use crate::util::drain_filter;
97use crate::rectangle_occlusion as occlusion;
98#[cfg(feature = "debugger")]
99use crate::debugger::{Debugger, DebugQueryKind};
100use upload::{upload_to_texture_cache, UploadTexturePool};
101use init::*;
102
103use euclid::{rect, Transform3D, Scale, default};
104use gleam::gl;
105use malloc_size_of::MallocSizeOfOps;
106
107#[cfg(feature = "replay")]
108use std::sync::Arc;
109
110use std::{
111 cell::RefCell,
112 collections::VecDeque,
113 f32,
114 ffi::c_void,
115 mem,
116 num::NonZeroUsize,
117 path::PathBuf,
118 rc::Rc,
119};
120#[cfg(any(feature = "capture", feature = "replay"))]
121use std::collections::hash_map::Entry;
122
123mod debug;
124mod gpu_buffer;
125mod gpu_cache;
126mod shade;
127mod vertex;
128mod upload;
129pub(crate) mod init;
130
131pub use debug::DebugRenderer;
132pub use shade::{PendingShadersToPrecache, Shaders, SharedShaders};
133pub use vertex::{desc, VertexArrayKind, MAX_VERTEX_TEXTURE_WIDTH};
134pub use gpu_buffer::{GpuBuffer, GpuBufferF, GpuBufferBuilderF, GpuBufferI, GpuBufferBuilderI};
135pub use gpu_buffer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferWriterF};
136
137pub const VERTEX_DATA_TEXTURE_COUNT: usize = 3;
148
149pub const BLOCKS_PER_UV_RECT: usize = 2;
151
152const GPU_TAG_BRUSH_OPACITY: GpuProfileTag = GpuProfileTag {
153 label: "B_Opacity",
154 color: debug_colors::DARKMAGENTA,
155};
156const GPU_TAG_BRUSH_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
157 label: "B_LinearGradient",
158 color: debug_colors::POWDERBLUE,
159};
160const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
161 label: "B_YuvImage",
162 color: debug_colors::DARKGREEN,
163};
164const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag {
165 label: "B_MixBlend",
166 color: debug_colors::MAGENTA,
167};
168const GPU_TAG_BRUSH_BLEND: GpuProfileTag = GpuProfileTag {
169 label: "B_Blend",
170 color: debug_colors::ORANGE,
171};
172const GPU_TAG_BRUSH_IMAGE: GpuProfileTag = GpuProfileTag {
173 label: "B_Image",
174 color: debug_colors::SPRINGGREEN,
175};
176const GPU_TAG_BRUSH_SOLID: GpuProfileTag = GpuProfileTag {
177 label: "B_Solid",
178 color: debug_colors::RED,
179};
180const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
181 label: "C_Clip",
182 color: debug_colors::PURPLE,
183};
184const GPU_TAG_CACHE_BORDER: GpuProfileTag = GpuProfileTag {
185 label: "C_Border",
186 color: debug_colors::CORNSILK,
187};
188const GPU_TAG_CACHE_LINE_DECORATION: GpuProfileTag = GpuProfileTag {
189 label: "C_LineDecoration",
190 color: debug_colors::YELLOWGREEN,
191};
192const GPU_TAG_CACHE_FAST_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
193 label: "C_FastLinearGradient",
194 color: debug_colors::BROWN,
195};
196const GPU_TAG_CACHE_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
197 label: "C_LinearGradient",
198 color: debug_colors::BROWN,
199};
200const GPU_TAG_GRADIENT: GpuProfileTag = GpuProfileTag {
201 label: "C_Gradient",
202 color: debug_colors::BROWN,
203};
204const GPU_TAG_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
205 label: "C_RadialGradient",
206 color: debug_colors::BROWN,
207};
208const GPU_TAG_CONIC_GRADIENT: GpuProfileTag = GpuProfileTag {
209 label: "C_ConicGradient",
210 color: debug_colors::BROWN,
211};
212const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
213 label: "target init",
214 color: debug_colors::SLATEGREY,
215};
216const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag {
217 label: "data init",
218 color: debug_colors::LIGHTGREY,
219};
220const GPU_TAG_PRIM_SPLIT_COMPOSITE: GpuProfileTag = GpuProfileTag {
221 label: "SplitComposite",
222 color: debug_colors::DARKBLUE,
223};
224const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag {
225 label: "TextRun",
226 color: debug_colors::BLUE,
227};
228const GPU_TAG_PRIMITIVE: GpuProfileTag = GpuProfileTag {
229 label: "Primitive",
230 color: debug_colors::RED,
231};
232const GPU_TAG_INDIRECT_PRIM: GpuProfileTag = GpuProfileTag {
233 label: "Primitive (indirect)",
234 color: debug_colors::YELLOWGREEN,
235};
236const GPU_TAG_INDIRECT_MASK: GpuProfileTag = GpuProfileTag {
237 label: "Mask (indirect)",
238 color: debug_colors::IVORY,
239};
240const GPU_TAG_BLUR: GpuProfileTag = GpuProfileTag {
241 label: "Blur",
242 color: debug_colors::VIOLET,
243};
244const GPU_TAG_BLIT: GpuProfileTag = GpuProfileTag {
245 label: "Blit",
246 color: debug_colors::LIME,
247};
248const GPU_TAG_SCALE: GpuProfileTag = GpuProfileTag {
249 label: "Scale",
250 color: debug_colors::GHOSTWHITE,
251};
252const GPU_SAMPLER_TAG_ALPHA: GpuProfileTag = GpuProfileTag {
253 label: "Alpha targets",
254 color: debug_colors::BLACK,
255};
256const GPU_SAMPLER_TAG_OPAQUE: GpuProfileTag = GpuProfileTag {
257 label: "Opaque pass",
258 color: debug_colors::BLACK,
259};
260const GPU_SAMPLER_TAG_TRANSPARENT: GpuProfileTag = GpuProfileTag {
261 label: "Transparent pass",
262 color: debug_colors::BLACK,
263};
264const GPU_TAG_SVG_FILTER: GpuProfileTag = GpuProfileTag {
265 label: "SvgFilter",
266 color: debug_colors::LEMONCHIFFON,
267};
268const GPU_TAG_SVG_FILTER_NODES: GpuProfileTag = GpuProfileTag {
269 label: "SvgFilterNodes",
270 color: debug_colors::LEMONCHIFFON,
271};
272const GPU_TAG_COMPOSITE: GpuProfileTag = GpuProfileTag {
273 label: "Composite",
274 color: debug_colors::TOMATO,
275};
276
277#[derive(Debug, Copy, Clone)]
282struct OcclusionItemKey {
283 tile_index: usize,
284 needs_mask: bool,
285}
286
287struct SwapChainLayer {
290 occlusion: occlusion::FrontToBackBuilder<OcclusionItemKey>,
291 clear_tiles: Vec<occlusion::Item<OcclusionItemKey>>,
292}
293
294struct CompositeTileState {
296 pub local_rect: PictureRect,
297 pub local_valid_rect: PictureRect,
298 pub device_clip_rect: DeviceRect,
299 pub z_id: ZBufferId,
300 pub device_tile_box: DeviceRect,
301 pub visible_rects: Vec<DeviceRect>,
302}
303
304impl CompositeTileState {
305 pub fn same_state(&self, other: &CompositeTileState) -> bool {
306 self.local_rect == other.local_rect &&
307 self.local_valid_rect == other.local_valid_rect &&
308 self.device_clip_rect == other.device_clip_rect &&
309 self.z_id == other.z_id &&
310 self.device_tile_box == other.device_tile_box
311 }
312}
313
314struct LayerCompositorFrameState {
316 tile_states: FastHashMap<TileId, CompositeTileState>,
317 pub rects_without_id: Vec<DeviceRect>,
318}
319
320pub const TEXTURE_CACHE_DBG_CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.8, 1.0];
324
325impl BatchKind {
326 fn sampler_tag(&self) -> GpuProfileTag {
327 match *self {
328 BatchKind::SplitComposite => GPU_TAG_PRIM_SPLIT_COMPOSITE,
329 BatchKind::Brush(kind) => {
330 match kind {
331 BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
332 BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
333 BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
334 BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
335 BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
336 BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT,
337 BrushBatchKind::Opacity => GPU_TAG_BRUSH_OPACITY,
338 }
339 }
340 BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN,
341 BatchKind::Quad(PatternKind::ColorOrTexture) => GPU_TAG_PRIMITIVE,
342 BatchKind::Quad(PatternKind::Gradient) => GPU_TAG_GRADIENT,
343 BatchKind::Quad(PatternKind::RadialGradient) => GPU_TAG_RADIAL_GRADIENT,
344 BatchKind::Quad(PatternKind::ConicGradient) => GPU_TAG_CONIC_GRADIENT,
345 BatchKind::Quad(PatternKind::Mask) => GPU_TAG_INDIRECT_MASK,
346 }
347 }
348}
349
350fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
351 if before & select != after & select {
352 Some(after.contains(select))
353 } else {
354 None
355 }
356}
357
358#[repr(C)]
359#[derive(Copy, Clone, Debug)]
360pub enum ShaderColorMode {
361 Alpha = 0,
362 SubpixelDualSource = 1,
363 BitmapShadow = 2,
364 ColorBitmap = 3,
365 Image = 4,
366 MultiplyDualSource = 5,
367}
368
369impl From<GlyphFormat> for ShaderColorMode {
370 fn from(format: GlyphFormat) -> ShaderColorMode {
371 match format {
372 GlyphFormat::Alpha |
373 GlyphFormat::TransformedAlpha |
374 GlyphFormat::Bitmap => ShaderColorMode::Alpha,
375 GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => {
376 panic!("Subpixel glyph formats must be handled separately.");
377 }
378 GlyphFormat::ColorBitmap => ShaderColorMode::ColorBitmap,
379 }
380 }
381}
382
383#[derive(Debug, Copy, Clone, PartialEq, Eq)]
389pub(crate) enum TextureSampler {
390 Color0,
391 Color1,
392 Color2,
393 GpuCache,
394 TransformPalette,
395 RenderTasks,
396 Dither,
397 PrimitiveHeadersF,
398 PrimitiveHeadersI,
399 ClipMask,
400 GpuBufferF,
401 GpuBufferI,
402}
403
404impl TextureSampler {
405 pub(crate) fn color(n: usize) -> TextureSampler {
406 match n {
407 0 => TextureSampler::Color0,
408 1 => TextureSampler::Color1,
409 2 => TextureSampler::Color2,
410 _ => {
411 panic!("There are only 3 color samplers.");
412 }
413 }
414 }
415}
416
417impl Into<TextureSlot> for TextureSampler {
418 fn into(self) -> TextureSlot {
419 match self {
420 TextureSampler::Color0 => TextureSlot(0),
421 TextureSampler::Color1 => TextureSlot(1),
422 TextureSampler::Color2 => TextureSlot(2),
423 TextureSampler::GpuCache => TextureSlot(3),
424 TextureSampler::TransformPalette => TextureSlot(4),
425 TextureSampler::RenderTasks => TextureSlot(5),
426 TextureSampler::Dither => TextureSlot(6),
427 TextureSampler::PrimitiveHeadersF => TextureSlot(7),
428 TextureSampler::PrimitiveHeadersI => TextureSlot(8),
429 TextureSampler::ClipMask => TextureSlot(9),
430 TextureSampler::GpuBufferF => TextureSlot(10),
431 TextureSampler::GpuBufferI => TextureSlot(11),
432 }
433 }
434}
435
436#[derive(Clone, Debug, PartialEq)]
437pub enum GraphicsApi {
438 OpenGL,
439}
440
441#[derive(Clone, Debug)]
442pub struct GraphicsApiInfo {
443 pub kind: GraphicsApi,
444 pub renderer: String,
445 pub version: String,
446}
447
448#[derive(Debug)]
449pub struct GpuProfile {
450 pub frame_id: GpuFrameId,
451 pub paint_time_ns: u64,
452}
453
454impl GpuProfile {
455 fn new(frame_id: GpuFrameId, timers: &[GpuTimer]) -> GpuProfile {
456 let mut paint_time_ns = 0;
457 for timer in timers {
458 paint_time_ns += timer.time_ns;
459 }
460 GpuProfile {
461 frame_id,
462 paint_time_ns,
463 }
464 }
465}
466
467#[derive(Debug)]
468pub struct CpuProfile {
469 pub frame_id: GpuFrameId,
470 pub backend_time_ns: u64,
471 pub composite_time_ns: u64,
472 pub draw_calls: usize,
473}
474
475impl CpuProfile {
476 fn new(
477 frame_id: GpuFrameId,
478 backend_time_ns: u64,
479 composite_time_ns: u64,
480 draw_calls: usize,
481 ) -> CpuProfile {
482 CpuProfile {
483 frame_id,
484 backend_time_ns,
485 composite_time_ns,
486 draw_calls,
487 }
488 }
489}
490
491#[derive(Debug, Copy, Clone)]
493enum PartialPresentMode {
494 Single {
498 dirty_rect: DeviceRect,
499 },
500}
501
502struct CacheTexture {
503 texture: Texture,
504 category: TextureCacheCategory,
505}
506
507struct TextureResolver {
513 texture_cache_map: FastHashMap<CacheTextureId, CacheTexture>,
515
516 external_images: FastHashMap<DeferredResolveIndex, ExternalTexture>,
518
519 dummy_cache_texture: Texture,
523}
524
525impl TextureResolver {
526 fn new(device: &mut Device) -> TextureResolver {
527 let dummy_cache_texture = device
528 .create_texture(
529 ImageBufferKind::Texture2D,
530 ImageFormat::RGBA8,
531 1,
532 1,
533 TextureFilter::Linear,
534 None,
535 );
536 device.upload_texture_immediate(
537 &dummy_cache_texture,
538 &[0xff, 0xff, 0xff, 0xff],
539 );
540
541 TextureResolver {
542 texture_cache_map: FastHashMap::default(),
543 external_images: FastHashMap::default(),
544 dummy_cache_texture,
545 }
546 }
547
548 fn deinit(self, device: &mut Device) {
549 device.delete_texture(self.dummy_cache_texture);
550
551 for (_id, item) in self.texture_cache_map {
552 device.delete_texture(item.texture);
553 }
554 }
555
556 fn begin_frame(&mut self) {
557 }
558
559 fn end_pass(
560 &mut self,
561 device: &mut Device,
562 textures_to_invalidate: &[CacheTextureId],
563 ) {
564 for texture_id in textures_to_invalidate {
568 let render_target = &self.texture_cache_map[texture_id].texture;
569 device.invalidate_render_target(render_target);
570 }
571 }
572
573 fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) -> Swizzle {
575 match *texture_id {
576 TextureSource::Invalid => {
577 Swizzle::default()
578 }
579 TextureSource::Dummy => {
580 let swizzle = Swizzle::default();
581 device.bind_texture(sampler, &self.dummy_cache_texture, swizzle);
582 swizzle
583 }
584 TextureSource::External(TextureSourceExternal { ref index, .. }) => {
585 let texture = self.external_images
586 .get(index)
587 .expect("BUG: External image should be resolved by now");
588 device.bind_external_texture(sampler, texture);
589 Swizzle::default()
590 }
591 TextureSource::TextureCache(index, swizzle) => {
592 let texture = &self.texture_cache_map[&index].texture;
593 device.bind_texture(sampler, texture, swizzle);
594 swizzle
595 }
596 }
597 }
598
599 fn resolve(&self, texture_id: &TextureSource) -> Option<(&Texture, Swizzle)> {
603 match *texture_id {
604 TextureSource::Invalid => None,
605 TextureSource::Dummy => {
606 Some((&self.dummy_cache_texture, Swizzle::default()))
607 }
608 TextureSource::External(..) => {
609 panic!("BUG: External textures cannot be resolved, they can only be bound.");
610 }
611 TextureSource::TextureCache(index, swizzle) => {
612 Some((&self.texture_cache_map[&index].texture, swizzle))
613 }
614 }
615 }
616
617 fn get_uv_rect(
620 &self,
621 source: &TextureSource,
622 default_value: TexelRect,
623 ) -> TexelRect {
624 match source {
625 TextureSource::External(TextureSourceExternal { ref index, .. }) => {
626 let texture = self.external_images
627 .get(index)
628 .expect("BUG: External image should be resolved by now");
629 texture.get_uv_rect()
630 }
631 _ => {
632 default_value
633 }
634 }
635 }
636
637 fn get_texture_size(&self, texture: &TextureSource) -> DeviceIntSize {
639 match *texture {
640 TextureSource::Invalid => DeviceIntSize::zero(),
641 TextureSource::TextureCache(id, _) => {
642 self.texture_cache_map[&id].texture.get_dimensions()
643 },
644 TextureSource::External(TextureSourceExternal { index, .. }) => {
645 let uv_rect = self.external_images[&index].get_uv_rect();
650 (uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32()
651 },
652 TextureSource::Dummy => DeviceIntSize::new(1, 1),
653 }
654 }
655
656 fn report_memory(&self) -> MemoryReport {
657 let mut report = MemoryReport::default();
658
659 for item in self.texture_cache_map.values() {
662 let counter = match item.category {
663 TextureCacheCategory::Atlas => &mut report.atlas_textures,
664 TextureCacheCategory::Standalone => &mut report.standalone_textures,
665 TextureCacheCategory::PictureTile => &mut report.picture_tile_textures,
666 TextureCacheCategory::RenderTarget => &mut report.render_target_textures,
667 };
668 *counter += item.texture.size_in_bytes();
669 }
670
671 report
672 }
673
674 fn update_profile(&self, profile: &mut TransactionProfile) {
675 let mut external_image_bytes = 0;
676 for img in self.external_images.values() {
677 let uv_rect = img.get_uv_rect();
678 let size = (uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32();
681
682 let bpp = 4;
685 external_image_bytes += size.area() as usize * bpp;
686 }
687
688 profile.set(profiler::EXTERNAL_IMAGE_BYTES, profiler::bytes_to_mb(external_image_bytes));
689 }
690
691 fn get_cache_texture_mut(&mut self, id: &CacheTextureId) -> &mut Texture {
692 &mut self.texture_cache_map
693 .get_mut(id)
694 .expect("bug: texture not allocated")
695 .texture
696 }
697}
698
699#[derive(Debug, Copy, Clone, PartialEq)]
700#[cfg_attr(feature = "capture", derive(Serialize))]
701#[cfg_attr(feature = "replay", derive(Deserialize))]
702pub enum BlendMode {
703 None,
704 Alpha,
705 PremultipliedAlpha,
706 PremultipliedDestOut,
707 SubpixelDualSource,
708 Advanced(MixBlendMode),
709 MultiplyDualSource,
710 Screen,
711 Exclusion,
712 PlusLighter,
713}
714
715impl BlendMode {
716 pub fn from_mix_blend_mode(
720 mode: MixBlendMode,
721 advanced_blend: bool,
722 coherent: bool,
723 dual_source: bool,
724 ) -> Option<BlendMode> {
725 Some(match mode {
729 _ if advanced_blend && coherent => BlendMode::Advanced(mode),
731 MixBlendMode::Screen => BlendMode::Screen,
733 MixBlendMode::Exclusion => BlendMode::Exclusion,
735 MixBlendMode::PlusLighter => BlendMode::PlusLighter,
737 MixBlendMode::Multiply if dual_source => BlendMode::MultiplyDualSource,
739 _ if advanced_blend => BlendMode::Advanced(mode),
741 _ => return None,
743 })
744 }
745}
746
747struct DebugOverlayState {
749 is_enabled: bool,
751
752 current_size: Option<DeviceIntSize>,
755
756 layer_index: usize,
757}
758
759impl DebugOverlayState {
760 fn new() -> Self {
761 DebugOverlayState {
762 is_enabled: false,
763 current_size: None,
764 layer_index: 0,
765 }
766 }
767}
768
769#[derive(Debug, Default)]
771pub(crate) struct BufferDamageTracker {
772 damage_rects: [DeviceRect; 4],
773 current_offset: usize,
774}
775
776impl BufferDamageTracker {
777 fn push_dirty_rect(&mut self, rect: &DeviceRect) {
780 self.damage_rects[self.current_offset] = rect.clone();
781 self.current_offset = match self.current_offset {
782 0 => self.damage_rects.len() - 1,
783 n => n - 1,
784 }
785 }
786
787 fn get_damage_rect(&self, buffer_age: usize) -> Option<DeviceRect> {
791 match buffer_age {
792 0 => None,
794 1 => Some(DeviceRect::zero()),
797 n if n <= self.damage_rects.len() + 1 => {
800 Some(
801 self.damage_rects.iter()
802 .cycle()
803 .skip(self.current_offset + 1)
804 .take(n - 1)
805 .fold(DeviceRect::zero(), |acc, r| acc.union(r))
806 )
807 }
808 _ => None,
811 }
812 }
813}
814
815pub struct Renderer {
821 result_rx: Receiver<ResultMsg>,
822 api_tx: Sender<ApiMsg>,
823 pub device: Device,
824 pending_texture_updates: Vec<TextureUpdateList>,
825 pending_texture_cache_updates: bool,
827 pending_native_surface_updates: Vec<NativeSurfaceOperation>,
828 pending_gpu_cache_updates: Vec<GpuCacheUpdateList>,
829 pending_gpu_cache_clear: bool,
830 pending_shader_updates: Vec<PathBuf>,
831 active_documents: FastHashMap<DocumentId, RenderedDocument>,
832
833 shaders: Rc<RefCell<Shaders>>,
834
835 max_recorded_profiles: usize,
836
837 clear_color: ColorF,
838 enable_clear_scissor: bool,
839 enable_advanced_blend_barriers: bool,
840 clear_caches_with_quads: bool,
841 clear_alpha_targets_with_quads: bool,
842
843 debug: debug::LazyInitializedDebugRenderer,
844 debug_flags: DebugFlags,
845 profile: TransactionProfile,
846 frame_counter: u64,
847 resource_upload_time: f64,
848 gpu_cache_upload_time: f64,
849 profiler: Profiler,
850 #[cfg(feature = "debugger")]
851 debugger: Debugger,
852
853 last_time: u64,
854
855 pub gpu_profiler: GpuProfiler,
856 vaos: vertex::RendererVAOs,
857
858 gpu_cache_texture: gpu_cache::GpuCacheTexture,
859 vertex_data_textures: Vec<vertex::VertexDataTextures>,
860 current_vertex_data_textures: usize,
861
862 gpu_cache_debug_chunks: Vec<Vec<GpuCacheDebugChunk>>,
866
867 gpu_cache_frame_id: FrameId,
868 gpu_cache_overflow: bool,
869
870 pipeline_info: PipelineInfo,
871
872 texture_resolver: TextureResolver,
874
875 texture_upload_pbo_pool: UploadPBOPool,
876 staging_texture_pool: UploadTexturePool,
877
878 dither_matrix_texture: Option<Texture>,
879
880 external_image_handler: Option<Box<dyn ExternalImageHandler>>,
883
884 size_of_ops: Option<MallocSizeOfOps>,
887
888 pub renderer_errors: Vec<RendererError>,
889
890 pub(in crate) async_frame_recorder: Option<AsyncScreenshotGrabber>,
891 pub(in crate) async_screenshots: Option<AsyncScreenshotGrabber>,
892
893 cpu_profiles: VecDeque<CpuProfile>,
896 gpu_profiles: VecDeque<GpuProfile>,
897
898 notifications: Vec<NotificationRequest>,
900
901 device_size: Option<DeviceIntSize>,
902
903 zoom_debug_texture: Option<Texture>,
905
906 cursor_position: DeviceIntPoint,
909
910 shared_texture_cache_cleared: bool,
913
914 documents_seen: FastHashSet<DocumentId>,
916
917 #[cfg(feature = "capture")]
918 read_fbo: FBOId,
919 #[cfg(feature = "replay")]
920 owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
921
922 compositor_config: CompositorConfig,
924 current_compositor_kind: CompositorKind,
925
926 allocated_native_surfaces: FastHashSet<NativeSurfaceId>,
931
932 force_redraw: bool,
935
936 debug_overlay_state: DebugOverlayState,
938
939 buffer_damage_tracker: BufferDamageTracker,
943
944 max_primitive_instance_count: usize,
945 enable_instancing: bool,
946
947 consecutive_oom_frames: u32,
950
951 target_frame_publish_id: Option<FramePublishId>,
954
955 pending_result_msg: Option<ResultMsg>,
957
958 layer_compositor_frame_state_in_prev_frame: Option<LayerCompositorFrameState>,
960}
961
962#[derive(Debug)]
963pub enum RendererError {
964 Shader(ShaderError),
965 Thread(std::io::Error),
966 MaxTextureSize,
967 SoftwareRasterizer,
968 OutOfMemory,
969}
970
971impl From<ShaderError> for RendererError {
972 fn from(err: ShaderError) -> Self {
973 RendererError::Shader(err)
974 }
975}
976
977impl From<std::io::Error> for RendererError {
978 fn from(err: std::io::Error) -> Self {
979 RendererError::Thread(err)
980 }
981}
982
983impl Renderer {
984 pub fn device_size(&self) -> Option<DeviceIntSize> {
985 self.device_size
986 }
987
988 pub fn set_cursor_position(
990 &mut self,
991 position: DeviceIntPoint,
992 ) {
993 self.cursor_position = position;
994 }
995
996 pub fn get_max_texture_size(&self) -> i32 {
997 self.device.max_texture_size()
998 }
999
1000 pub fn get_graphics_api_info(&self) -> GraphicsApiInfo {
1001 GraphicsApiInfo {
1002 kind: GraphicsApi::OpenGL,
1003 version: self.device.gl().get_string(gl::VERSION),
1004 renderer: self.device.gl().get_string(gl::RENDERER),
1005 }
1006 }
1007
1008 pub fn preferred_color_format(&self) -> ImageFormat {
1009 self.device.preferred_color_formats().external
1010 }
1011
1012 pub fn required_texture_stride_alignment(&self, format: ImageFormat) -> usize {
1013 self.device.required_pbo_stride().num_bytes(format).get()
1014 }
1015
1016 pub fn set_clear_color(&mut self, color: ColorF) {
1017 self.clear_color = color;
1018 }
1019
1020 pub fn flush_pipeline_info(&mut self) -> PipelineInfo {
1021 mem::replace(&mut self.pipeline_info, PipelineInfo::default())
1022 }
1023
1024 pub fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option<Epoch> {
1026 self.pipeline_info.epochs.get(&(pipeline_id, document_id)).cloned()
1027 }
1028
1029 fn get_next_result_msg(&mut self) -> Option<ResultMsg> {
1030 if self.pending_result_msg.is_none() {
1031 if let Ok(msg) = self.result_rx.try_recv() {
1032 self.pending_result_msg = Some(msg);
1033 }
1034 }
1035
1036 match (&self.pending_result_msg, &self.target_frame_publish_id) {
1037 (Some(ResultMsg::PublishDocument(frame_publish_id, _, _, _)), Some(target_id)) => {
1038 if frame_publish_id > target_id {
1039 return None;
1040 }
1041 }
1042 _ => {}
1043 }
1044
1045 self.pending_result_msg.take()
1046 }
1047
1048 pub fn update(&mut self) {
1052 profile_scope!("update");
1053
1054 while let Some(msg) = self.get_next_result_msg() {
1056 match msg {
1057 ResultMsg::PublishPipelineInfo(mut pipeline_info) => {
1058 for ((pipeline_id, document_id), epoch) in pipeline_info.epochs {
1059 self.pipeline_info.epochs.insert((pipeline_id, document_id), epoch);
1060 }
1061 self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..));
1062 }
1063 ResultMsg::PublishDocument(
1064 _,
1065 document_id,
1066 mut doc,
1067 resource_update_list,
1068 ) => {
1069 let prev_frame_memory = if let Some(mut prev_doc) = self.active_documents.remove(&document_id) {
1078 doc.profile.merge(&mut prev_doc.profile);
1079
1080 if prev_doc.frame.must_be_drawn() {
1081 prev_doc.render_reasons |= RenderReasons::TEXTURE_CACHE_FLUSH;
1082 self.render_impl(
1083 document_id,
1084 &mut prev_doc,
1085 None,
1086 0,
1087 ).ok();
1088 }
1089
1090 Some(prev_doc.frame.allocator_memory)
1091 } else {
1092 None
1093 };
1094
1095 if let Some(memory) = prev_frame_memory {
1096 memory.assert_memory_reusable();
1099 }
1100
1101 self.active_documents.insert(document_id, doc);
1102
1103 self.pending_texture_cache_updates |= !resource_update_list.texture_updates.updates.is_empty();
1115 self.pending_texture_updates.push(resource_update_list.texture_updates);
1116 self.pending_native_surface_updates.extend(resource_update_list.native_surface_updates);
1117 self.documents_seen.insert(document_id);
1118 }
1119 ResultMsg::UpdateGpuCache(mut list) => {
1120 if list.clear {
1121 self.pending_gpu_cache_clear = true;
1122 }
1123 if list.clear {
1124 self.gpu_cache_debug_chunks = Vec::new();
1125 }
1126 for cmd in mem::replace(&mut list.debug_commands, Vec::new()) {
1127 match cmd {
1128 GpuCacheDebugCmd::Alloc(chunk) => {
1129 let row = chunk.address.v as usize;
1130 if row >= self.gpu_cache_debug_chunks.len() {
1131 self.gpu_cache_debug_chunks.resize(row + 1, Vec::new());
1132 }
1133 self.gpu_cache_debug_chunks[row].push(chunk);
1134 },
1135 GpuCacheDebugCmd::Free(address) => {
1136 let chunks = &mut self.gpu_cache_debug_chunks[address.v as usize];
1137 let pos = chunks.iter()
1138 .position(|x| x.address == address).unwrap();
1139 chunks.remove(pos);
1140 },
1141 }
1142 }
1143 self.pending_gpu_cache_updates.push(list);
1144 }
1145 ResultMsg::UpdateResources {
1146 resource_updates,
1147 memory_pressure,
1148 } => {
1149 if memory_pressure {
1150 let active_documents = mem::replace(
1160 &mut self.active_documents,
1161 FastHashMap::default(),
1162 );
1163 for (doc_id, mut doc) in active_documents {
1164 if doc.frame.must_be_drawn() {
1165 self.render_impl(
1169 doc_id,
1170 &mut doc,
1171 None,
1172 0,
1173 ).ok();
1174 }
1175 }
1176 }
1177
1178 self.pending_texture_cache_updates |= !resource_updates.texture_updates.updates.is_empty();
1179 self.pending_texture_updates.push(resource_updates.texture_updates);
1180 self.pending_native_surface_updates.extend(resource_updates.native_surface_updates);
1181 self.device.begin_frame();
1182
1183 self.update_texture_cache();
1184 self.update_native_surfaces();
1185
1186 if memory_pressure {
1192 self.texture_upload_pbo_pool.on_memory_pressure(&mut self.device);
1193 self.staging_texture_pool.delete_textures(&mut self.device);
1194 }
1195
1196 self.device.end_frame();
1197 }
1198 ResultMsg::RenderDocumentOffscreen(document_id, mut offscreen_doc, resources) => {
1199 let prev_doc = self.active_documents.remove(&document_id);
1204 if let Some(mut prev_doc) = prev_doc {
1205 if prev_doc.frame.must_be_drawn() {
1206 prev_doc.render_reasons |= RenderReasons::TEXTURE_CACHE_FLUSH;
1207 self.render_impl(
1208 document_id,
1209 &mut prev_doc,
1210 None,
1211 0,
1212 ).ok();
1213 }
1214
1215 self.active_documents.insert(document_id, prev_doc);
1216 }
1217
1218 self.pending_texture_cache_updates |= !resources.texture_updates.updates.is_empty();
1221 self.pending_texture_updates.push(resources.texture_updates);
1222 self.pending_native_surface_updates.extend(resources.native_surface_updates);
1223
1224 self.render_impl(
1225 document_id,
1226 &mut offscreen_doc,
1227 None,
1228 0,
1229 ).unwrap();
1230 }
1231 ResultMsg::AppendNotificationRequests(mut notifications) => {
1232 if !self.pending_texture_cache_updates {
1238 drain_filter(
1239 &mut notifications,
1240 |n| { n.when() == Checkpoint::FrameTexturesUpdated },
1241 |n| { n.notify(); },
1242 );
1243 }
1244 self.notifications.append(&mut notifications);
1245 }
1246 ResultMsg::ForceRedraw => {
1247 self.force_redraw = true;
1248 }
1249 ResultMsg::RefreshShader(path) => {
1250 self.pending_shader_updates.push(path);
1251 }
1252 ResultMsg::SetParameter(ref param) => {
1253 self.device.set_parameter(param);
1254 self.profiler.set_parameter(param);
1255 }
1256 ResultMsg::DebugOutput(output) => match output {
1257 #[cfg(feature = "capture")]
1258 DebugOutput::SaveCapture(config, deferred) => {
1259 self.save_capture(config, deferred);
1260 }
1261 #[cfg(feature = "replay")]
1262 DebugOutput::LoadCapture(config, plain_externals) => {
1263 self.active_documents.clear();
1264 self.load_capture(config, plain_externals);
1265 }
1266 },
1267 ResultMsg::DebugCommand(command) => {
1268 self.handle_debug_command(command);
1269 }
1270 }
1271 }
1272 }
1273
1274 pub fn set_target_frame_publish_id(&mut self, publish_id: FramePublishId) {
1277 self.target_frame_publish_id = Some(publish_id);
1278 }
1279
1280 fn handle_debug_command(&mut self, command: DebugCommand) {
1281 match command {
1282 DebugCommand::SetPictureTileSize(_) |
1283 DebugCommand::SetMaximumSurfaceSize(_) |
1284 DebugCommand::GenerateFrame => {
1285 panic!("Should be handled by render backend");
1286 }
1287 #[cfg(feature = "debugger")]
1288 DebugCommand::Query(ref query) => {
1289 match query.kind {
1290 DebugQueryKind::SpatialTree { .. } => {
1291 panic!("Should be handled by render backend");
1292 }
1293 DebugQueryKind::CompositorConfig { .. } => {
1294 let result = match self.active_documents.iter().last() {
1295 Some((_, doc)) => {
1296 doc.frame.composite_state.print_to_string()
1297 }
1298 None => {
1299 "No active documents".into()
1300 }
1301 };
1302 query.result.send(result).ok();
1303 }
1304 DebugQueryKind::CompositorView { .. } => {
1305 let result = match self.active_documents.iter().last() {
1306 Some((_, doc)) => {
1307 let info = CompositorDebugInfo::from(&doc.frame.composite_state);
1308 serde_json::to_string(&info).unwrap()
1309 }
1310 None => {
1311 "No active documents".into()
1312 }
1313 };
1314 query.result.send(result).ok();
1315 }
1316 }
1317 }
1318 DebugCommand::SaveCapture(..) |
1319 DebugCommand::LoadCapture(..) |
1320 DebugCommand::StartCaptureSequence(..) |
1321 DebugCommand::StopCaptureSequence => {
1322 panic!("Capture commands are not welcome here! Did you build with 'capture' feature?")
1323 }
1324 DebugCommand::ClearCaches(_)
1325 | DebugCommand::SimulateLongSceneBuild(_)
1326 | DebugCommand::EnableNativeCompositor(_)
1327 | DebugCommand::SetBatchingLookback(_) => {}
1328 DebugCommand::InvalidateGpuCache => {
1329 self.gpu_cache_texture.invalidate();
1330 }
1331 DebugCommand::SetFlags(flags) => {
1332 self.set_debug_flags(flags);
1333 }
1334 DebugCommand::GetDebugFlags(tx) => {
1335 tx.send(self.debug_flags).unwrap();
1336 }
1337 #[cfg(feature = "debugger")]
1338 DebugCommand::AddDebugClient(client) => {
1339 self.debugger.add_client(
1340 client,
1341 self.debug_flags,
1342 &self.profiler,
1343 );
1344 }
1345 }
1346 }
1347
1348 pub fn set_external_image_handler(&mut self, handler: Box<dyn ExternalImageHandler>) {
1350 self.external_image_handler = Some(handler);
1351 }
1352
1353 pub fn get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>) {
1355 let cpu_profiles = self.cpu_profiles.drain(..).collect();
1356 let gpu_profiles = self.gpu_profiles.drain(..).collect();
1357 (cpu_profiles, gpu_profiles)
1358 }
1359
1360 pub fn force_redraw(&mut self) {
1363 self.force_redraw = true;
1364 }
1365
1366 pub fn render(
1372 &mut self,
1373 device_size: DeviceIntSize,
1374 buffer_age: usize,
1375 ) -> Result<RenderResults, Vec<RendererError>> {
1376 self.device_size = Some(device_size);
1377
1378 let doc_id = self.active_documents.keys().last().cloned();
1385
1386 let result = match doc_id {
1387 Some(doc_id) => {
1388 let mut doc = self.active_documents
1390 .remove(&doc_id)
1391 .unwrap();
1392
1393 let size = if !device_size.is_empty() {
1394 Some(device_size)
1395 } else {
1396 None
1397 };
1398
1399 let result = self.render_impl(
1400 doc_id,
1401 &mut doc,
1402 size,
1403 buffer_age,
1404 );
1405
1406 self.active_documents.insert(doc_id, doc);
1407
1408 result
1409 }
1410 None => {
1411 self.last_time = zeitstempel::now();
1412 Ok(RenderResults::default())
1413 }
1414 };
1415
1416 drain_filter(
1417 &mut self.notifications,
1418 |n| { n.when() == Checkpoint::FrameRendered },
1419 |n| { n.notify(); },
1420 );
1421
1422 let mut oom = false;
1423 if let Err(ref errors) = result {
1424 for error in errors {
1425 if matches!(error, &RendererError::OutOfMemory) {
1426 oom = true;
1427 break;
1428 }
1429 }
1430 }
1431
1432 if oom {
1433 let _ = self.api_tx.send(ApiMsg::MemoryPressure);
1434 self.consecutive_oom_frames += 1;
1436 assert!(self.consecutive_oom_frames < 5, "Renderer out of memory");
1437 } else {
1438 self.consecutive_oom_frames = 0;
1439 }
1440
1441 self.notifications.clear();
1445
1446 tracy_frame_marker!();
1447
1448 result
1449 }
1450
1451 fn update_debug_overlay(
1454 &mut self,
1455 framebuffer_size: DeviceIntSize,
1456 has_debug_items: bool,
1457 ) {
1458 self.debug_overlay_state.is_enabled = has_debug_items || self.debug_flags.intersects(
1460 DebugFlags::PROFILER_DBG |
1461 DebugFlags::RENDER_TARGET_DBG |
1462 DebugFlags::TEXTURE_CACHE_DBG |
1463 DebugFlags::EPOCHS |
1464 DebugFlags::GPU_CACHE_DBG |
1465 DebugFlags::PICTURE_CACHING_DBG |
1466 DebugFlags::PRIMITIVE_DBG |
1467 DebugFlags::ZOOM_DBG |
1468 DebugFlags::WINDOW_VISIBILITY_DBG
1469 );
1470
1471 if let CompositorKind::Native { .. } = self.current_compositor_kind {
1473 let compositor = self.compositor_config.compositor().unwrap();
1474
1475 if let Some(current_size) = self.debug_overlay_state.current_size {
1478 if !self.debug_overlay_state.is_enabled || current_size != framebuffer_size {
1479 compositor.destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
1480 self.debug_overlay_state.current_size = None;
1481 }
1482 }
1483
1484 if self.debug_overlay_state.is_enabled && self.debug_overlay_state.current_size.is_none() {
1486 compositor.create_surface(
1487 &mut self.device,
1488 NativeSurfaceId::DEBUG_OVERLAY,
1489 DeviceIntPoint::zero(),
1490 framebuffer_size,
1491 false,
1492 );
1493 compositor.create_tile(
1494 &mut self.device,
1495 NativeTileId::DEBUG_OVERLAY,
1496 );
1497 self.debug_overlay_state.current_size = Some(framebuffer_size);
1498 }
1499 }
1500 }
1501
1502 fn bind_debug_overlay(&mut self, device_size: DeviceIntSize) -> Option<DrawTarget> {
1504 if self.debug_overlay_state.is_enabled {
1506 match self.current_compositor_kind {
1507 CompositorKind::Native { .. } => {
1508 let compositor = self.compositor_config.compositor().unwrap();
1509 let surface_size = self.debug_overlay_state.current_size.unwrap();
1510
1511 compositor.invalidate_tile(
1513 &mut self.device,
1514 NativeTileId::DEBUG_OVERLAY,
1515 DeviceIntRect::from_size(surface_size),
1516 );
1517 let surface_info = compositor.bind(
1519 &mut self.device,
1520 NativeTileId::DEBUG_OVERLAY,
1521 DeviceIntRect::from_size(surface_size),
1522 DeviceIntRect::from_size(surface_size),
1523 );
1524
1525 let draw_target = DrawTarget::NativeSurface {
1527 offset: surface_info.origin,
1528 external_fbo_id: surface_info.fbo_id,
1529 dimensions: surface_size,
1530 };
1531 self.device.bind_draw_target(draw_target);
1532
1533 self.device.clear_target(
1535 Some([0.0, 0.0, 0.0, 0.0]),
1536 None, None,
1538 );
1539
1540 Some(draw_target)
1541 }
1542 CompositorKind::Layer { .. } => {
1543 let compositor = self.compositor_config.layer_compositor().unwrap();
1544 compositor.bind_layer(self.debug_overlay_state.layer_index, &[]);
1545
1546 self.device.clear_target(
1547 Some([0.0, 0.0, 0.0, 0.0]),
1548 None, None,
1550 );
1551
1552 Some(DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left()))
1553 }
1554 CompositorKind::Draw { .. } => {
1555 Some(DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left()))
1559 }
1560 }
1561 } else {
1562 None
1563 }
1564 }
1565
1566 fn unbind_debug_overlay(&mut self) {
1568 if self.debug_overlay_state.is_enabled {
1570 match self.current_compositor_kind {
1571 CompositorKind::Native { .. } => {
1572 let compositor = self.compositor_config.compositor().unwrap();
1573 compositor.unbind(&mut self.device);
1575
1576 let clip_rect = DeviceIntRect::from_size(
1577 self.debug_overlay_state.current_size.unwrap(),
1578 );
1579
1580 compositor.add_surface(
1581 &mut self.device,
1582 NativeSurfaceId::DEBUG_OVERLAY,
1583 CompositorSurfaceTransform::identity(),
1584 clip_rect,
1585 ImageRendering::Auto,
1586 clip_rect,
1587 ClipRadius::EMPTY,
1588 );
1589 }
1590 CompositorKind::Draw { .. } => {}
1591 CompositorKind::Layer { .. } => {
1592 let compositor = self.compositor_config.layer_compositor().unwrap();
1593 compositor.present_layer(self.debug_overlay_state.layer_index, &[]);
1594 }
1595 }
1596 }
1597 }
1598
1599 fn render_impl(
1604 &mut self,
1605 doc_id: DocumentId,
1606 active_doc: &mut RenderedDocument,
1607 mut device_size: Option<DeviceIntSize>,
1608 buffer_age: usize,
1609 ) -> Result<RenderResults, Vec<RendererError>> {
1610 profile_scope!("render");
1611 let mut results = RenderResults::default();
1612 self.profile.end_time_if_started(profiler::FRAME_SEND_TIME);
1613 self.profile.start_time(profiler::RENDERER_TIME);
1614
1615 self.staging_texture_pool.begin_frame();
1616
1617 let compositor_kind = active_doc.frame.composite_state.compositor_kind;
1618 if self.current_compositor_kind != compositor_kind {
1620 let enable = match (self.current_compositor_kind, compositor_kind) {
1621 (CompositorKind::Native { .. }, CompositorKind::Draw { .. }) => {
1622 if self.debug_overlay_state.current_size.is_some() {
1623 self.compositor_config
1624 .compositor()
1625 .unwrap()
1626 .destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
1627 self.debug_overlay_state.current_size = None;
1628 }
1629 false
1630 }
1631 (CompositorKind::Draw { .. }, CompositorKind::Native { .. }) => {
1632 true
1633 }
1634 (current_compositor_kind, active_doc_compositor_kind) => {
1635 warn!("Compositor mismatch, assuming this is Wrench running. Current {:?}, active {:?}",
1636 current_compositor_kind, active_doc_compositor_kind);
1637 false
1638 }
1639 };
1640
1641 if let Some(config) = self.compositor_config.compositor() {
1642 config.enable_native_compositor(&mut self.device, enable);
1643 }
1644 self.current_compositor_kind = compositor_kind;
1645 }
1646
1647 self.texture_resolver.begin_frame();
1654
1655 if let Some(device_size) = device_size {
1656 self.update_gpu_profile(device_size);
1657 }
1658
1659 let cpu_frame_id = {
1660 let _gm = self.gpu_profiler.start_marker("begin frame");
1661 let frame_id = self.device.begin_frame();
1662 self.gpu_profiler.begin_frame(frame_id);
1663
1664 self.device.disable_scissor();
1665 self.device.disable_depth();
1666 self.set_blend(false, FramebufferKind::Main);
1667 self.update_texture_cache();
1670 self.update_native_surfaces();
1671
1672 frame_id
1673 };
1674
1675 if !active_doc.frame.present {
1676 device_size = None;
1679 }
1680
1681 if let Some(device_size) = device_size {
1682 if let CompositorKind::Native { .. } = self.current_compositor_kind {
1686 let compositor = self.compositor_config.compositor().unwrap();
1687 compositor.begin_frame(&mut self.device);
1688 }
1689
1690 self.update_debug_overlay(device_size, !active_doc.frame.debug_items.is_empty());
1693 }
1694
1695 let frame = &mut active_doc.frame;
1696 let profile = &mut active_doc.profile;
1697 assert!(self.current_compositor_kind == frame.composite_state.compositor_kind);
1698
1699 if self.shared_texture_cache_cleared {
1700 assert!(self.documents_seen.contains(&doc_id),
1701 "Cleared texture cache without sending new document frame.");
1702 }
1703
1704 match self.prepare_gpu_cache(&frame.deferred_resolves) {
1705 Ok(..) => {
1706 assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
1707 "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
1708 frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
1709
1710 self.draw_frame(
1711 frame,
1712 device_size,
1713 buffer_age,
1714 &mut results,
1715 );
1716
1717 if thread_is_being_profiled() {
1720 let duration = Duration::new(0,0);
1721 if let Some(n) = self.profile.get(profiler::RENDERED_PICTURE_TILES) {
1722 let message = (n as usize).to_string();
1723 add_text_marker("NumPictureCacheInvalidated", &message, duration);
1724 }
1725 }
1726
1727 if device_size.is_some() {
1728 self.draw_frame_debug_items(&frame.debug_items);
1729 }
1730
1731 self.profile.merge(profile);
1732 }
1733 Err(e) => {
1734 self.renderer_errors.push(e);
1735 }
1736 }
1737
1738 self.unlock_external_images(&frame.deferred_resolves);
1739
1740 let _gm = self.gpu_profiler.start_marker("end frame");
1741 self.gpu_profiler.end_frame();
1742
1743 let t = self.profile.end_time(profiler::RENDERER_TIME);
1744 self.profile.end_time_if_started(profiler::TOTAL_FRAME_CPU_TIME);
1745
1746 let current_time = zeitstempel::now();
1747 if device_size.is_some() {
1748 let time = profiler::ns_to_ms(current_time - self.last_time);
1749 self.profile.set(profiler::FRAME_TIME, time);
1750 }
1751
1752 let debug_overlay = device_size.and_then(|device_size| {
1753 self.bind_debug_overlay(device_size).map(|draw_target| {
1755 self.draw_render_target_debug(&draw_target);
1756 self.draw_texture_cache_debug(&draw_target);
1757 self.draw_gpu_cache_debug(device_size);
1758 self.draw_zoom_debug(device_size);
1759 self.draw_epoch_debug();
1760 self.draw_window_visibility_debug();
1761 draw_target
1762 })
1763 });
1764
1765 Telemetry::record_renderer_time(Duration::from_micros((t * 1000.00) as u64));
1766 if self.profile.get(profiler::SHADER_BUILD_TIME).is_none() {
1767 Telemetry::record_renderer_time_no_sc(Duration::from_micros((t * 1000.00) as u64));
1768 }
1769
1770 if self.max_recorded_profiles > 0 {
1771 while self.cpu_profiles.len() >= self.max_recorded_profiles {
1772 self.cpu_profiles.pop_front();
1773 }
1774 let cpu_profile = CpuProfile::new(
1775 cpu_frame_id,
1776 (self.profile.get_or(profiler::FRAME_BUILDING_TIME, 0.0) * 1000000.0) as u64,
1777 (self.profile.get_or(profiler::RENDERER_TIME, 0.0) * 1000000.0) as u64,
1778 self.profile.get_or(profiler::DRAW_CALLS, 0.0) as usize,
1779 );
1780 self.cpu_profiles.push_back(cpu_profile);
1781 }
1782
1783 if thread_is_being_profiled() {
1784 let duration = Duration::new(0,0);
1785 let message = (self.profile.get_or(profiler::DRAW_CALLS, 0.0) as usize).to_string();
1786 add_text_marker("NumDrawCalls", &message, duration);
1787 }
1788
1789 let report = self.texture_resolver.report_memory();
1790 self.profile.set(profiler::RENDER_TARGET_MEM, profiler::bytes_to_mb(report.render_target_textures));
1791 self.profile.set(profiler::PICTURE_TILES_MEM, profiler::bytes_to_mb(report.picture_tile_textures));
1792 self.profile.set(profiler::ATLAS_TEXTURES_MEM, profiler::bytes_to_mb(report.atlas_textures));
1793 self.profile.set(profiler::STANDALONE_TEXTURES_MEM, profiler::bytes_to_mb(report.standalone_textures));
1794
1795 self.profile.set(profiler::DEPTH_TARGETS_MEM, profiler::bytes_to_mb(self.device.depth_targets_memory()));
1796
1797 self.profile.set(profiler::TEXTURES_CREATED, self.device.textures_created);
1798 self.profile.set(profiler::TEXTURES_DELETED, self.device.textures_deleted);
1799
1800 results.stats.texture_upload_mb = self.profile.get_or(profiler::TEXTURE_UPLOADS_MEM, 0.0);
1801 self.frame_counter += 1;
1802 results.stats.resource_upload_time = self.resource_upload_time;
1803 self.resource_upload_time = 0.0;
1804 results.stats.gpu_cache_upload_time = self.gpu_cache_upload_time;
1805 self.gpu_cache_upload_time = 0.0;
1806
1807 if let Some(stats) = active_doc.frame_stats.take() {
1808 results.stats.merge(&stats);
1810
1811 self.profiler.update_frame_stats(stats);
1812 }
1813
1814 let add_markers = thread_is_being_profiled();
1821 for i in 0..RenderReasons::NUM_BITS {
1822 let counter = profiler::RENDER_REASON_FIRST + i as usize;
1823 let mut val = 0.0;
1824 let reason_bit = RenderReasons::from_bits_truncate(1 << i);
1825 if active_doc.render_reasons.contains(reason_bit) {
1826 val = 1.0;
1827 if add_markers {
1828 let event_str = format!("Render reason {:?}", reason_bit);
1829 add_event_marker(&event_str);
1830 }
1831 }
1832 self.profile.set(counter, val);
1833 }
1834 active_doc.render_reasons = RenderReasons::empty();
1835
1836
1837 self.texture_resolver.update_profile(&mut self.profile);
1838
1839 self.profiler.set_counters(&mut self.profile);
1841
1842 #[cfg(feature = "debugger")]
1845 self.debugger.update(
1846 self.debug_flags,
1847 &self.profiler,
1848 );
1849
1850 self.profiler.update();
1852
1853 if self.debug_flags.intersects(DebugFlags::PROFILER_DBG | DebugFlags::PROFILER_CAPTURE) {
1854 if let Some(device_size) = device_size {
1855 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
1857 self.profiler.draw_profile(
1858 self.frame_counter,
1859 debug_renderer,
1860 device_size,
1861 );
1862 }
1863 }
1864 }
1865
1866 if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
1867 self.device.echo_driver_messages();
1868 }
1869
1870 if let Some(debug_renderer) = self.debug.try_get_mut() {
1871 let small_screen = self.debug_flags.contains(DebugFlags::SMALL_SCREEN);
1872 let scale = if small_screen { 1.6 } else { 1.0 };
1873 let surface_origin_is_top_left = match self.current_compositor_kind {
1876 CompositorKind::Native { .. } => true,
1877 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => self.device.surface_origin_is_top_left(),
1878 };
1879 debug_renderer.render(
1882 &mut self.device,
1883 debug_overlay.and(device_size),
1884 scale,
1885 surface_origin_is_top_left,
1886 );
1887 }
1888
1889 self.staging_texture_pool.end_frame(&mut self.device);
1890 self.texture_upload_pbo_pool.end_frame(&mut self.device);
1891 self.device.end_frame();
1892
1893 if debug_overlay.is_some() {
1894 self.last_time = current_time;
1895
1896 self.unbind_debug_overlay();
1899 }
1900
1901 if device_size.is_some() {
1902 match self.current_compositor_kind {
1906 CompositorKind::Layer { .. } => {
1907 let compositor = self.compositor_config.layer_compositor().unwrap();
1908 compositor.end_frame();
1909 }
1910 CompositorKind::Native { .. } => {
1911 profile_scope!("compositor.end_frame");
1912 let compositor = self.compositor_config.compositor().unwrap();
1913 compositor.end_frame(&mut self.device);
1914 }
1915 CompositorKind::Draw { .. } => {}
1916 }
1917 }
1918
1919 self.documents_seen.clear();
1920 self.shared_texture_cache_cleared = false;
1921
1922 self.check_gl_errors();
1923
1924 if self.renderer_errors.is_empty() {
1925 Ok(results)
1926 } else {
1927 Err(mem::replace(&mut self.renderer_errors, Vec::new()))
1928 }
1929 }
1930
1931 fn update_gpu_profile(&mut self, device_size: DeviceIntSize) {
1932 let _gm = self.gpu_profiler.start_marker("build samples");
1933 let (gpu_frame_id, timers, samplers) = self.gpu_profiler.build_samples();
1936
1937 if self.max_recorded_profiles > 0 {
1938 while self.gpu_profiles.len() >= self.max_recorded_profiles {
1939 self.gpu_profiles.pop_front();
1940 }
1941
1942 self.gpu_profiles.push_back(GpuProfile::new(gpu_frame_id, &timers));
1943 }
1944
1945 self.profiler.set_gpu_time_queries(timers);
1946
1947 if !samplers.is_empty() {
1948 let screen_fraction = 1.0 / device_size.to_f32().area();
1949
1950 fn accumulate_sampler_value(description: &str, samplers: &[GpuSampler]) -> f32 {
1951 let mut accum = 0.0;
1952 for sampler in samplers {
1953 if sampler.tag.label != description {
1954 continue;
1955 }
1956
1957 accum += sampler.count as f32;
1958 }
1959
1960 accum
1961 }
1962
1963 let alpha_targets = accumulate_sampler_value(&"Alpha targets", &samplers) * screen_fraction;
1964 let transparent_pass = accumulate_sampler_value(&"Transparent pass", &samplers) * screen_fraction;
1965 let opaque_pass = accumulate_sampler_value(&"Opaque pass", &samplers) * screen_fraction;
1966 self.profile.set(profiler::ALPHA_TARGETS_SAMPLERS, alpha_targets);
1967 self.profile.set(profiler::TRANSPARENT_PASS_SAMPLERS, transparent_pass);
1968 self.profile.set(profiler::OPAQUE_PASS_SAMPLERS, opaque_pass);
1969 self.profile.set(profiler::TOTAL_SAMPLERS, alpha_targets + transparent_pass + opaque_pass);
1970 }
1971 }
1972
1973 fn update_texture_cache(&mut self) {
1974 profile_scope!("update_texture_cache");
1975
1976 let _gm = self.gpu_profiler.start_marker("texture cache update");
1977 let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
1978 self.pending_texture_cache_updates = false;
1979
1980 self.profile.start_time(profiler::TEXTURE_CACHE_UPDATE_TIME);
1981
1982 let mut create_cache_texture_time = 0;
1983 let mut delete_cache_texture_time = 0;
1984
1985 for update_list in pending_texture_updates.drain(..) {
1986 for ((src_tex, dst_tex), copies) in &update_list.copies {
1988
1989 let dest_texture = &self.texture_resolver.texture_cache_map[&dst_tex].texture;
1990 let dst_texture_size = dest_texture.get_dimensions().to_f32();
1991
1992 let mut copy_instances = Vec::new();
1993 for copy in copies {
1994 copy_instances.push(CopyInstance {
1995 src_rect: copy.src_rect.to_f32(),
1996 dst_rect: copy.dst_rect.to_f32(),
1997 dst_texture_size,
1998 });
1999 }
2000
2001 let draw_target = DrawTarget::from_texture(dest_texture, false);
2002 self.device.bind_draw_target(draw_target);
2003
2004 self.shaders
2005 .borrow_mut()
2006 .ps_copy()
2007 .bind(
2008 &mut self.device,
2009 &Transform3D::identity(),
2010 None,
2011 &mut self.renderer_errors,
2012 &mut self.profile,
2013 );
2014
2015 self.draw_instanced_batch(
2016 ©_instances,
2017 VertexArrayKind::Copy,
2018 &BatchTextures::composite_rgb(
2019 TextureSource::TextureCache(*src_tex, Swizzle::default())
2020 ),
2021 &mut RendererStats::default(),
2022 );
2023 }
2024
2025 let mut pending_deletes = Vec::new();
2027 for allocation in &update_list.allocations {
2028 let old = self.texture_resolver.texture_cache_map.remove(&allocation.id);
2029 match allocation.kind {
2030 TextureCacheAllocationKind::Alloc(_) => {
2031 assert!(old.is_none(), "Renderer and backend disagree!");
2032 }
2033 TextureCacheAllocationKind::Reset(_) |
2034 TextureCacheAllocationKind::Free => {
2035 assert!(old.is_some(), "Renderer and backend disagree!");
2036 }
2037 }
2038 if let Some(old) = old {
2039
2040 let size = old.texture.get_dimensions();
2042 let info = TextureCacheAllocInfo {
2043 width: size.width,
2044 height: size.height,
2045 format: old.texture.get_format(),
2046 filter: old.texture.get_filter(),
2047 target: old.texture.get_target(),
2048 is_shared_cache: old.texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE),
2049 has_depth: old.texture.supports_depth(),
2050 category: old.category,
2051 };
2052 pending_deletes.push((old.texture, info));
2053 }
2054 }
2055 let mut reused_textures = VecDeque::with_capacity(pending_deletes.len());
2057 for allocation in &update_list.allocations {
2058 match allocation.kind {
2059 TextureCacheAllocationKind::Alloc(ref info) |
2060 TextureCacheAllocationKind::Reset(ref info) => {
2061 reused_textures.push_back(
2062 pending_deletes.iter()
2063 .position(|(_, old_info)| *old_info == *info)
2064 .map(|index| pending_deletes.swap_remove(index).0)
2065 );
2066 }
2067 TextureCacheAllocationKind::Free => {}
2068 }
2069 }
2070
2071 if !pending_deletes.is_empty() {
2073 let delete_texture_start = zeitstempel::now();
2074 for (texture, _) in pending_deletes {
2075 add_event_marker("TextureCacheFree");
2076 self.device.delete_texture(texture);
2077 }
2078 delete_cache_texture_time += zeitstempel::now() - delete_texture_start;
2079 }
2080
2081 for allocation in update_list.allocations {
2082 match allocation.kind {
2083 TextureCacheAllocationKind::Alloc(_) => add_event_marker("TextureCacheAlloc"),
2084 TextureCacheAllocationKind::Reset(_) => add_event_marker("TextureCacheReset"),
2085 TextureCacheAllocationKind::Free => {}
2086 };
2087 match allocation.kind {
2088 TextureCacheAllocationKind::Alloc(ref info) |
2089 TextureCacheAllocationKind::Reset(ref info) => {
2090 let create_cache_texture_start = zeitstempel::now();
2091 let mut texture = reused_textures.pop_front().unwrap_or(None).unwrap_or_else(|| {
2097 self.device.create_texture(
2098 info.target,
2099 info.format,
2100 info.width,
2101 info.height,
2102 info.filter,
2103 Some(RenderTargetInfo { has_depth: info.has_depth }),
2106 )
2107 });
2108
2109 if info.is_shared_cache {
2110 texture.flags_mut()
2111 .insert(TextureFlags::IS_SHARED_TEXTURE_CACHE);
2112
2113 if self.device.use_batched_texture_uploads() &&
2117 !self.device.get_capabilities().supports_render_target_partial_update
2118 {
2119 self.clear_texture(&texture, [0.0; 4]);
2120 }
2121
2122 if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
2126 self.clear_texture(&texture, TEXTURE_CACHE_DBG_CLEAR_COLOR);
2127 }
2128 }
2129
2130 create_cache_texture_time += zeitstempel::now() - create_cache_texture_start;
2131
2132 self.texture_resolver.texture_cache_map.insert(allocation.id, CacheTexture {
2133 texture,
2134 category: info.category,
2135 });
2136 }
2137 TextureCacheAllocationKind::Free => {}
2138 };
2139 }
2140
2141 upload_to_texture_cache(self, update_list.updates);
2142
2143 self.check_gl_errors();
2144 }
2145
2146 if create_cache_texture_time > 0 {
2147 self.profile.set(
2148 profiler::CREATE_CACHE_TEXTURE_TIME,
2149 profiler::ns_to_ms(create_cache_texture_time)
2150 );
2151 }
2152 if delete_cache_texture_time > 0 {
2153 self.profile.set(
2154 profiler::DELETE_CACHE_TEXTURE_TIME,
2155 profiler::ns_to_ms(delete_cache_texture_time)
2156 )
2157 }
2158
2159 let t = self.profile.end_time(profiler::TEXTURE_CACHE_UPDATE_TIME);
2160 self.resource_upload_time += t;
2161 Telemetry::record_texture_cache_update_time(Duration::from_micros((t * 1000.00) as u64));
2162
2163 drain_filter(
2164 &mut self.notifications,
2165 |n| { n.when() == Checkpoint::FrameTexturesUpdated },
2166 |n| { n.notify(); },
2167 );
2168 }
2169
2170 fn check_gl_errors(&mut self) {
2171 let err = self.device.gl().get_error();
2172 if err == gl::OUT_OF_MEMORY {
2173 self.renderer_errors.push(RendererError::OutOfMemory);
2174 }
2175
2176 }
2178
2179 fn bind_textures(&mut self, textures: &BatchTextures) {
2180 for i in 0 .. 3 {
2181 self.texture_resolver.bind(
2182 &textures.input.colors[i],
2183 TextureSampler::color(i),
2184 &mut self.device,
2185 );
2186 }
2187
2188 self.texture_resolver.bind(
2189 &textures.clip_mask,
2190 TextureSampler::ClipMask,
2191 &mut self.device,
2192 );
2193
2194 if let Some(ref texture) = self.dither_matrix_texture {
2196 self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
2197 }
2198 }
2199
2200 fn draw_instanced_batch<T: Clone>(
2201 &mut self,
2202 data: &[T],
2203 vertex_array_kind: VertexArrayKind,
2204 textures: &BatchTextures,
2205 stats: &mut RendererStats,
2206 ) {
2207 self.bind_textures(textures);
2208
2209 debug_assert!(!data.is_empty());
2214
2215 let vao = &self.vaos[vertex_array_kind];
2216 self.device.bind_vao(vao);
2217
2218 let chunk_size = if self.debug_flags.contains(DebugFlags::DISABLE_BATCHING) {
2219 1
2220 } else if vertex_array_kind == VertexArrayKind::Primitive {
2221 self.max_primitive_instance_count
2222 } else {
2223 data.len()
2224 };
2225
2226 for chunk in data.chunks(chunk_size) {
2227 if self.enable_instancing {
2228 self.device
2229 .update_vao_instances(vao, chunk, ONE_TIME_USAGE_HINT, None);
2230 self.device
2231 .draw_indexed_triangles_instanced_u16(6, chunk.len() as i32);
2232 } else {
2233 self.device
2234 .update_vao_instances(vao, chunk, ONE_TIME_USAGE_HINT, NonZeroUsize::new(4));
2235 self.device
2236 .draw_indexed_triangles(6 * chunk.len() as i32);
2237 }
2238 self.profile.inc(profiler::DRAW_CALLS);
2239 stats.total_draw_calls += 1;
2240 }
2241
2242 self.profile.add(profiler::VERTICES, 6 * data.len());
2243 }
2244
2245 fn handle_readback_composite(
2246 &mut self,
2247 draw_target: DrawTarget,
2248 uses_scissor: bool,
2249 backdrop: &RenderTask,
2250 readback: &RenderTask,
2251 ) {
2252 let readback_origin = match readback.kind {
2255 RenderTaskKind::Readback(ReadbackTask { readback_origin: Some(o), .. }) => o,
2256 RenderTaskKind::Readback(ReadbackTask { readback_origin: None, .. }) => {
2257 return;
2261 }
2262 _ => unreachable!(),
2263 };
2264
2265 if uses_scissor {
2266 self.device.disable_scissor();
2267 }
2268
2269 let texture_source = TextureSource::TextureCache(
2270 readback.get_target_texture(),
2271 Swizzle::default(),
2272 );
2273 let (cache_texture, _) = self.texture_resolver
2274 .resolve(&texture_source).expect("bug: no source texture");
2275
2276 let readback_rect = readback.get_target_rect();
2280 let backdrop_rect = backdrop.get_target_rect();
2281 let (backdrop_screen_origin, _) = match backdrop.kind {
2282 RenderTaskKind::Picture(ref task_info) => (task_info.content_origin, task_info.device_pixel_scale),
2283 _ => panic!("bug: composite on non-picture?"),
2284 };
2285
2286 let cache_draw_target = DrawTarget::from_texture(
2290 cache_texture,
2291 false,
2292 );
2293
2294 let wanted_rect = DeviceRect::from_origin_and_size(
2296 readback_origin,
2297 readback_rect.size().to_f32(),
2298 );
2299
2300 let avail_rect = DeviceRect::from_origin_and_size(
2304 backdrop_screen_origin,
2305 backdrop_rect.size().to_f32(),
2306 );
2307
2308 if let Some(int_rect) = wanted_rect.intersection(&avail_rect) {
2309 let copy_size = int_rect.size().to_i32();
2312
2313 let src_origin = backdrop_rect.min.to_f32() +
2314 int_rect.min.to_vector() -
2315 backdrop_screen_origin.to_vector();
2316
2317 let src = DeviceIntRect::from_origin_and_size(
2318 src_origin.to_i32(),
2319 copy_size,
2320 );
2321
2322 let dest_origin = readback_rect.min.to_f32() +
2323 int_rect.min.to_vector() -
2324 readback_origin.to_vector();
2325
2326 let dest = DeviceIntRect::from_origin_and_size(
2327 dest_origin.to_i32(),
2328 copy_size,
2329 );
2330
2331 debug_assert!(!draw_target.is_default());
2333 let device_to_framebuffer = Scale::new(1i32);
2334
2335 self.device.blit_render_target(
2336 draw_target.into(),
2337 src * device_to_framebuffer,
2338 cache_draw_target,
2339 dest * device_to_framebuffer,
2340 TextureFilter::Linear,
2341 );
2342 }
2343
2344 self.device.bind_draw_target(draw_target);
2347 self.device.reset_read_target();
2348
2349 if uses_scissor {
2350 self.device.enable_scissor();
2351 }
2352 }
2353
2354 fn handle_resolves(
2355 &mut self,
2356 resolve_ops: &[ResolveOp],
2357 render_tasks: &RenderTaskGraph,
2358 draw_target: DrawTarget,
2359 ) {
2360 if resolve_ops.is_empty() {
2361 return;
2362 }
2363
2364 let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLIT);
2365
2366 for resolve_op in resolve_ops {
2367 self.handle_resolve(
2368 resolve_op,
2369 render_tasks,
2370 draw_target,
2371 );
2372 }
2373
2374 self.device.reset_read_target();
2375 }
2376
2377 fn handle_prims(
2378 &mut self,
2379 draw_target: &DrawTarget,
2380 prim_instances: &[FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>],
2381 prim_instances_with_scissor: &FastHashMap<(DeviceIntRect, PatternKind), FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>>,
2382 projection: &default::Transform3D<f32>,
2383 stats: &mut RendererStats,
2384 ) {
2385 self.device.disable_depth_write();
2386
2387 let has_prim_instances = prim_instances.iter().any(|map| !map.is_empty());
2388 if has_prim_instances || !prim_instances_with_scissor.is_empty() {
2389 let _timer = self.gpu_profiler.start_timer(GPU_TAG_INDIRECT_PRIM);
2390
2391 self.set_blend(false, FramebufferKind::Other);
2392
2393 for (pattern_idx, prim_instances_map) in prim_instances.iter().enumerate() {
2394 if prim_instances_map.is_empty() {
2395 continue;
2396 }
2397 let pattern = PatternKind::from_u32(pattern_idx as u32);
2398
2399 self.shaders.borrow_mut().get_quad_shader(pattern).bind(
2400 &mut self.device,
2401 projection,
2402 None,
2403 &mut self.renderer_errors,
2404 &mut self.profile,
2405 );
2406
2407 for (texture_source, prim_instances) in prim_instances_map {
2408 let texture_bindings = BatchTextures::composite_rgb(*texture_source);
2409
2410 self.draw_instanced_batch(
2411 prim_instances,
2412 VertexArrayKind::Primitive,
2413 &texture_bindings,
2414 stats,
2415 );
2416 }
2417 }
2418
2419 if !prim_instances_with_scissor.is_empty() {
2420 self.set_blend(true, FramebufferKind::Other);
2421 self.device.set_blend_mode_premultiplied_alpha();
2422 self.device.enable_scissor();
2423
2424 let mut prev_pattern = None;
2425
2426 for ((scissor_rect, pattern), prim_instances_map) in prim_instances_with_scissor {
2427 if prev_pattern != Some(*pattern) {
2428 prev_pattern = Some(*pattern);
2429 self.shaders.borrow_mut().get_quad_shader(*pattern).bind(
2430 &mut self.device,
2431 projection,
2432 None,
2433 &mut self.renderer_errors,
2434 &mut self.profile,
2435 );
2436 }
2437
2438 self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2439
2440 for (texture_source, prim_instances) in prim_instances_map {
2441 let texture_bindings = BatchTextures::composite_rgb(*texture_source);
2442
2443 self.draw_instanced_batch(
2444 prim_instances,
2445 VertexArrayKind::Primitive,
2446 &texture_bindings,
2447 stats,
2448 );
2449 }
2450 }
2451
2452 self.device.disable_scissor();
2453 }
2454 }
2455 }
2456
2457 fn handle_clips(
2458 &mut self,
2459 draw_target: &DrawTarget,
2460 masks: &ClipMaskInstanceList,
2461 projection: &default::Transform3D<f32>,
2462 stats: &mut RendererStats,
2463 ) {
2464 self.device.disable_depth_write();
2465
2466 {
2467 let _timer = self.gpu_profiler.start_timer(GPU_TAG_INDIRECT_MASK);
2468
2469 self.set_blend(true, FramebufferKind::Other);
2470 self.set_blend_mode_multiply(FramebufferKind::Other);
2471
2472 if !masks.mask_instances_fast.is_empty() {
2473 self.shaders.borrow_mut().ps_mask_fast().bind(
2474 &mut self.device,
2475 projection,
2476 None,
2477 &mut self.renderer_errors,
2478 &mut self.profile,
2479 );
2480
2481 self.draw_instanced_batch(
2482 &masks.mask_instances_fast,
2483 VertexArrayKind::Mask,
2484 &BatchTextures::empty(),
2485 stats,
2486 );
2487 }
2488
2489 if !masks.mask_instances_fast_with_scissor.is_empty() {
2490 self.shaders.borrow_mut().ps_mask_fast().bind(
2491 &mut self.device,
2492 projection,
2493 None,
2494 &mut self.renderer_errors,
2495 &mut self.profile,
2496 );
2497
2498 self.device.enable_scissor();
2499
2500 for (scissor_rect, instances) in &masks.mask_instances_fast_with_scissor {
2501 self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2502
2503 self.draw_instanced_batch(
2504 instances,
2505 VertexArrayKind::Mask,
2506 &BatchTextures::empty(),
2507 stats,
2508 );
2509 }
2510
2511 self.device.disable_scissor();
2512 }
2513
2514 if !masks.image_mask_instances.is_empty() {
2515 self.shaders.borrow_mut().ps_quad_textured().bind(
2516 &mut self.device,
2517 projection,
2518 None,
2519 &mut self.renderer_errors,
2520 &mut self.profile,
2521 );
2522
2523 for (texture, prim_instances) in &masks.image_mask_instances {
2524 self.draw_instanced_batch(
2525 prim_instances,
2526 VertexArrayKind::Primitive,
2527 &BatchTextures::composite_rgb(*texture),
2528 stats,
2529 );
2530 }
2531 }
2532
2533 if !masks.image_mask_instances_with_scissor.is_empty() {
2534 self.device.enable_scissor();
2535
2536 self.shaders.borrow_mut().ps_quad_textured().bind(
2537 &mut self.device,
2538 projection,
2539 None,
2540 &mut self.renderer_errors,
2541 &mut self.profile,
2542 );
2543
2544 for ((scissor_rect, texture), prim_instances) in &masks.image_mask_instances_with_scissor {
2545 self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2546
2547 self.draw_instanced_batch(
2548 prim_instances,
2549 VertexArrayKind::Primitive,
2550 &BatchTextures::composite_rgb(*texture),
2551 stats,
2552 );
2553 }
2554
2555 self.device.disable_scissor();
2556 }
2557
2558 if !masks.mask_instances_slow.is_empty() {
2559 self.shaders.borrow_mut().ps_mask().bind(
2560 &mut self.device,
2561 projection,
2562 None,
2563 &mut self.renderer_errors,
2564 &mut self.profile,
2565 );
2566
2567 self.draw_instanced_batch(
2568 &masks.mask_instances_slow,
2569 VertexArrayKind::Mask,
2570 &BatchTextures::empty(),
2571 stats,
2572 );
2573 }
2574
2575 if !masks.mask_instances_slow_with_scissor.is_empty() {
2576 self.shaders.borrow_mut().ps_mask().bind(
2577 &mut self.device,
2578 projection,
2579 None,
2580 &mut self.renderer_errors,
2581 &mut self.profile,
2582 );
2583
2584 self.device.enable_scissor();
2585
2586 for (scissor_rect, instances) in &masks.mask_instances_slow_with_scissor {
2587 self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
2588
2589 self.draw_instanced_batch(
2590 instances,
2591 VertexArrayKind::Mask,
2592 &BatchTextures::empty(),
2593 stats,
2594 );
2595 }
2596
2597 self.device.disable_scissor();
2598 }
2599 }
2600 }
2601
2602 fn handle_blits(
2603 &mut self,
2604 blits: &[BlitJob],
2605 render_tasks: &RenderTaskGraph,
2606 draw_target: DrawTarget,
2607 ) {
2608 if blits.is_empty() {
2609 return;
2610 }
2611
2612 let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLIT);
2613
2614 for blit in blits {
2617 let (source, source_rect) = {
2618 let task = &render_tasks[blit.source];
2622 let source_rect = blit.source_rect.translate(task.get_target_rect().min.to_vector());
2623 let source_texture = task.get_texture_source();
2624
2625 (source_texture, source_rect)
2626 };
2627
2628 let (texture, swizzle) = self.texture_resolver
2629 .resolve(&source)
2630 .expect("BUG: invalid source texture");
2631
2632 if swizzle != Swizzle::default() {
2633 error!("Swizzle {:?} can't be handled by a blit", swizzle);
2634 }
2635
2636 let read_target = DrawTarget::from_texture(
2637 texture,
2638 false,
2639 );
2640
2641 self.device.blit_render_target(
2642 read_target.into(),
2643 read_target.to_framebuffer_rect(source_rect),
2644 draw_target,
2645 draw_target.to_framebuffer_rect(blit.target_rect),
2646 TextureFilter::Linear,
2647 );
2648 }
2649 }
2650
2651 fn handle_scaling(
2652 &mut self,
2653 scalings: &FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
2654 projection: &default::Transform3D<f32>,
2655 stats: &mut RendererStats,
2656 ) {
2657 if scalings.is_empty() {
2658 return
2659 }
2660
2661 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SCALE);
2662 for (source, instances) in scalings {
2663 let buffer_kind = source.image_buffer_kind();
2664
2665 let uv_override_instances;
2670 let instances = match source {
2671 TextureSource::External(..) => {
2672 uv_override_instances = instances.iter().map(|instance| {
2673 let mut new_instance = instance.clone();
2674 let texel_rect: TexelRect = self.texture_resolver.get_uv_rect(
2675 &source,
2676 instance.source_rect.cast().into()
2677 ).into();
2678 new_instance.source_rect = DeviceRect::new(texel_rect.uv0, texel_rect.uv1);
2679 new_instance
2680 }).collect::<Vec<_>>();
2681 uv_override_instances.as_slice()
2682 }
2683 _ => instances.as_slice()
2684 };
2685
2686 self.shaders
2687 .borrow_mut()
2688 .get_scale_shader(buffer_kind)
2689 .bind(
2690 &mut self.device,
2691 &projection,
2692 Some(self.texture_resolver.get_texture_size(source).to_f32()),
2693 &mut self.renderer_errors,
2694 &mut self.profile,
2695 );
2696
2697 self.draw_instanced_batch(
2698 instances,
2699 VertexArrayKind::Scale,
2700 &BatchTextures::composite_rgb(*source),
2701 stats,
2702 );
2703 }
2704 }
2705
2706 fn handle_svg_filters(
2707 &mut self,
2708 textures: &BatchTextures,
2709 svg_filters: &[SvgFilterInstance],
2710 projection: &default::Transform3D<f32>,
2711 stats: &mut RendererStats,
2712 ) {
2713 if svg_filters.is_empty() {
2714 return;
2715 }
2716
2717 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SVG_FILTER);
2718
2719 self.shaders.borrow_mut().cs_svg_filter().bind(
2720 &mut self.device,
2721 &projection,
2722 None,
2723 &mut self.renderer_errors,
2724 &mut self.profile,
2725 );
2726
2727 self.draw_instanced_batch(
2728 &svg_filters,
2729 VertexArrayKind::SvgFilter,
2730 textures,
2731 stats,
2732 );
2733 }
2734
2735 fn handle_svg_nodes(
2736 &mut self,
2737 textures: &BatchTextures,
2738 svg_filters: &[SVGFEFilterInstance],
2739 projection: &default::Transform3D<f32>,
2740 stats: &mut RendererStats,
2741 ) {
2742 if svg_filters.is_empty() {
2743 return;
2744 }
2745
2746 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SVG_FILTER_NODES);
2747
2748 self.shaders.borrow_mut().cs_svg_filter_node().bind(
2749 &mut self.device,
2750 &projection,
2751 None,
2752 &mut self.renderer_errors,
2753 &mut self.profile,
2754 );
2755
2756 self.draw_instanced_batch(
2757 &svg_filters,
2758 VertexArrayKind::SvgFilterNode,
2759 textures,
2760 stats,
2761 );
2762 }
2763
2764 fn handle_resolve(
2765 &mut self,
2766 resolve_op: &ResolveOp,
2767 render_tasks: &RenderTaskGraph,
2768 draw_target: DrawTarget,
2769 ) {
2770 for src_task_id in &resolve_op.src_task_ids {
2771 let src_task = &render_tasks[*src_task_id];
2772 let src_info = match src_task.kind {
2773 RenderTaskKind::Picture(ref info) => info,
2774 _ => panic!("bug: not a picture"),
2775 };
2776 let src_task_rect = src_task.get_target_rect().to_f32();
2777
2778 let dest_task = &render_tasks[resolve_op.dest_task_id];
2779 let dest_info = match dest_task.kind {
2780 RenderTaskKind::Picture(ref info) => info,
2781 _ => panic!("bug: not a picture"),
2782 };
2783 let dest_task_rect = dest_task.get_target_rect().to_f32();
2784
2785 let dest_task_rect = DeviceRect::from_origin_and_size(
2791 dest_task_rect.min,
2792 dest_info.content_size.to_f32(),
2793 );
2794
2795 let wanted_rect = DeviceRect::from_origin_and_size(
2797 dest_info.content_origin,
2798 dest_task_rect.size().to_f32(),
2799 ).cast_unit() * dest_info.device_pixel_scale.inverse();
2800
2801 let avail_rect = DeviceRect::from_origin_and_size(
2805 src_info.content_origin,
2806 src_task_rect.size().to_f32(),
2807 ).cast_unit() * src_info.device_pixel_scale.inverse();
2808
2809 if let Some(device_int_rect) = wanted_rect.intersection(&avail_rect) {
2810 let src_int_rect = (device_int_rect * src_info.device_pixel_scale).cast_unit();
2811 let dest_int_rect = (device_int_rect * dest_info.device_pixel_scale).cast_unit();
2812
2813 let src_origin = src_task_rect.min.to_f32() +
2817 src_int_rect.min.to_vector() -
2818 src_info.content_origin.to_vector();
2819
2820 let src = DeviceIntRect::from_origin_and_size(
2821 src_origin.to_i32(),
2822 src_int_rect.size().round().to_i32(),
2823 );
2824
2825 let dest_origin = dest_task_rect.min.to_f32() +
2826 dest_int_rect.min.to_vector() -
2827 dest_info.content_origin.to_vector();
2828
2829 let dest = DeviceIntRect::from_origin_and_size(
2830 dest_origin.to_i32(),
2831 dest_int_rect.size().round().to_i32(),
2832 );
2833
2834 let texture_source = TextureSource::TextureCache(
2835 src_task.get_target_texture(),
2836 Swizzle::default(),
2837 );
2838 let (cache_texture, _) = self.texture_resolver
2839 .resolve(&texture_source).expect("bug: no source texture");
2840
2841 let read_target = ReadTarget::from_texture(cache_texture);
2842
2843 debug_assert!(!draw_target.is_default());
2845 let device_to_framebuffer = Scale::new(1i32);
2846
2847 self.device.blit_render_target(
2848 read_target,
2849 src * device_to_framebuffer,
2850 draw_target,
2851 dest * device_to_framebuffer,
2852 TextureFilter::Linear,
2853 );
2854 }
2855 }
2856 }
2857
2858 fn draw_picture_cache_target(
2859 &mut self,
2860 target: &PictureCacheTarget,
2861 draw_target: DrawTarget,
2862 projection: &default::Transform3D<f32>,
2863 render_tasks: &RenderTaskGraph,
2864 stats: &mut RendererStats,
2865 ) {
2866 profile_scope!("draw_picture_cache_target");
2867
2868 self.profile.inc(profiler::RENDERED_PICTURE_TILES);
2869 let _gm = self.gpu_profiler.start_marker("picture cache target");
2870 let framebuffer_kind = FramebufferKind::Other;
2871
2872 {
2873 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_TARGET);
2874 self.device.bind_draw_target(draw_target);
2875
2876 if self.device.get_capabilities().supports_qcom_tiled_rendering {
2877 self.device.gl().start_tiling_qcom(
2878 target.dirty_rect.min.x.max(0) as _,
2879 target.dirty_rect.min.y.max(0) as _,
2880 target.dirty_rect.width() as _,
2881 target.dirty_rect.height() as _,
2882 0,
2883 );
2884 }
2885
2886 self.device.enable_depth_write();
2887 self.set_blend(false, framebuffer_kind);
2888
2889 let clear_color = target.clear_color.map(|c| c.to_array());
2890 let scissor_rect = if self.device.get_capabilities().supports_render_target_partial_update
2891 && (target.dirty_rect != target.valid_rect
2892 || self.device.get_capabilities().prefers_clear_scissor)
2893 {
2894 Some(target.dirty_rect)
2895 } else {
2896 None
2897 };
2898 match scissor_rect {
2899 Some(r) if self.clear_caches_with_quads => {
2902 self.device.enable_depth(DepthFunction::Always);
2903 let old_draw_call_count = stats.total_draw_calls;
2905 if clear_color.is_none() {
2906 self.device.disable_color_write();
2907 }
2908 let instance = ClearInstance {
2909 rect: [
2910 r.min.x as f32, r.min.y as f32,
2911 r.max.x as f32, r.max.y as f32,
2912 ],
2913 color: clear_color.unwrap_or([0.0; 4]),
2914 };
2915 self.shaders.borrow_mut().ps_clear().bind(
2916 &mut self.device,
2917 &projection,
2918 None,
2919 &mut self.renderer_errors,
2920 &mut self.profile,
2921 );
2922 self.draw_instanced_batch(
2923 &[instance],
2924 VertexArrayKind::Clear,
2925 &BatchTextures::empty(),
2926 stats,
2927 );
2928 if clear_color.is_none() {
2929 self.device.enable_color_write();
2930 }
2931 stats.total_draw_calls = old_draw_call_count;
2932 self.device.disable_depth();
2933 }
2934 other => {
2935 let scissor_rect = other.map(|rect| {
2936 draw_target.build_scissor_rect(Some(rect))
2937 });
2938 self.device.clear_target(clear_color, Some(1.0), scissor_rect);
2939 }
2940 };
2941 self.device.disable_depth_write();
2942 }
2943
2944 match target.kind {
2945 PictureCacheTargetKind::Draw { ref alpha_batch_container } => {
2946 self.draw_alpha_batch_container(
2947 alpha_batch_container,
2948 draw_target,
2949 framebuffer_kind,
2950 projection,
2951 render_tasks,
2952 stats,
2953 );
2954 }
2955 PictureCacheTargetKind::Blit { task_id, sub_rect_offset } => {
2956 let src_task = &render_tasks[task_id];
2957 let (texture, _swizzle) = self.texture_resolver
2958 .resolve(&src_task.get_texture_source())
2959 .expect("BUG: invalid source texture");
2960
2961 let src_task_rect = src_task.get_target_rect();
2962
2963 let p0 = src_task_rect.min + sub_rect_offset;
2964 let p1 = p0 + target.dirty_rect.size();
2965 let src_rect = DeviceIntRect::new(p0, p1);
2966
2967 let target_rect = target
2971 .dirty_rect
2972 .translate(draw_target.offset().to_vector())
2973 .cast_unit();
2974
2975 self.device.blit_render_target(
2976 ReadTarget::from_texture(texture),
2977 src_rect.cast_unit(),
2978 draw_target,
2979 target_rect,
2980 TextureFilter::Nearest,
2981 );
2982 }
2983 }
2984
2985 self.device.invalidate_depth_target();
2986 if self.device.get_capabilities().supports_qcom_tiled_rendering {
2987 self.device.gl().end_tiling_qcom(gl::COLOR_BUFFER_BIT0_QCOM);
2988 }
2989 }
2990
2991 fn draw_alpha_batch_container(
2994 &mut self,
2995 alpha_batch_container: &AlphaBatchContainer,
2996 draw_target: DrawTarget,
2997 framebuffer_kind: FramebufferKind,
2998 projection: &default::Transform3D<f32>,
2999 render_tasks: &RenderTaskGraph,
3000 stats: &mut RendererStats,
3001 ) {
3002 let uses_scissor = alpha_batch_container.task_scissor_rect.is_some();
3003
3004 if uses_scissor {
3005 self.device.enable_scissor();
3006 let scissor_rect = draw_target.build_scissor_rect(
3007 alpha_batch_container.task_scissor_rect,
3008 );
3009 self.device.set_scissor_rect(scissor_rect)
3010 }
3011
3012 if !alpha_batch_container.opaque_batches.is_empty()
3013 && !self.debug_flags.contains(DebugFlags::DISABLE_OPAQUE_PASS) {
3014 let _gl = self.gpu_profiler.start_marker("opaque batches");
3015 let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
3016 self.set_blend(false, framebuffer_kind);
3017 self.device.enable_depth(DepthFunction::LessEqual);
3019 self.device.enable_depth_write();
3020
3021 for batch in alpha_batch_container
3024 .opaque_batches
3025 .iter()
3026 .rev()
3027 {
3028 if should_skip_batch(&batch.key.kind, self.debug_flags) {
3029 continue;
3030 }
3031
3032 self.shaders.borrow_mut()
3033 .get(&batch.key, batch.features, self.debug_flags, &self.device)
3034 .bind(
3035 &mut self.device, projection, None,
3036 &mut self.renderer_errors,
3037 &mut self.profile,
3038 );
3039
3040 let _timer = self.gpu_profiler.start_timer(batch.key.kind.sampler_tag());
3041 self.draw_instanced_batch(
3042 &batch.instances,
3043 VertexArrayKind::Primitive,
3044 &batch.key.textures,
3045 stats
3046 );
3047 }
3048
3049 self.device.disable_depth_write();
3050 self.gpu_profiler.finish_sampler(opaque_sampler);
3051 } else {
3052 self.device.disable_depth();
3053 }
3054
3055 if !alpha_batch_container.alpha_batches.is_empty()
3056 && !self.debug_flags.contains(DebugFlags::DISABLE_ALPHA_PASS) {
3057 let _gl = self.gpu_profiler.start_marker("alpha batches");
3058 let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
3059 self.set_blend(true, framebuffer_kind);
3060
3061 let mut prev_blend_mode = BlendMode::None;
3062 let shaders_rc = self.shaders.clone();
3063
3064 for batch in &alpha_batch_container.alpha_batches {
3065 if should_skip_batch(&batch.key.kind, self.debug_flags) {
3066 continue;
3067 }
3068
3069 let mut shaders = shaders_rc.borrow_mut();
3070 let shader = shaders.get(
3071 &batch.key,
3072 batch.features | BatchFeatures::ALPHA_PASS,
3073 self.debug_flags,
3074 &self.device,
3075 );
3076
3077 if batch.key.blend_mode != prev_blend_mode {
3078 match batch.key.blend_mode {
3079 _ if self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) &&
3080 framebuffer_kind == FramebufferKind::Main => {
3081 self.device.set_blend_mode_show_overdraw();
3082 }
3083 BlendMode::None => {
3084 unreachable!("bug: opaque blend in alpha pass");
3085 }
3086 BlendMode::Alpha => {
3087 self.device.set_blend_mode_alpha();
3088 }
3089 BlendMode::PremultipliedAlpha => {
3090 self.device.set_blend_mode_premultiplied_alpha();
3091 }
3092 BlendMode::PremultipliedDestOut => {
3093 self.device.set_blend_mode_premultiplied_dest_out();
3094 }
3095 BlendMode::SubpixelDualSource => {
3096 self.device.set_blend_mode_subpixel_dual_source();
3097 }
3098 BlendMode::Advanced(mode) => {
3099 if self.enable_advanced_blend_barriers {
3100 self.device.gl().blend_barrier_khr();
3101 }
3102 self.device.set_blend_mode_advanced(mode);
3103 }
3104 BlendMode::MultiplyDualSource => {
3105 self.device.set_blend_mode_multiply_dual_source();
3106 }
3107 BlendMode::Screen => {
3108 self.device.set_blend_mode_screen();
3109 }
3110 BlendMode::Exclusion => {
3111 self.device.set_blend_mode_exclusion();
3112 }
3113 BlendMode::PlusLighter => {
3114 self.device.set_blend_mode_plus_lighter();
3115 }
3116 }
3117 prev_blend_mode = batch.key.blend_mode;
3118 }
3119
3120 if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, backdrop_id }) = batch.key.kind {
3122 debug_assert_eq!(batch.instances.len(), 1);
3125 self.handle_readback_composite(
3126 draw_target,
3127 uses_scissor,
3128 &render_tasks[task_id],
3129 &render_tasks[backdrop_id],
3130 );
3131 }
3132
3133 let _timer = self.gpu_profiler.start_timer(batch.key.kind.sampler_tag());
3134 shader.bind(
3135 &mut self.device,
3136 projection,
3137 None,
3138 &mut self.renderer_errors,
3139 &mut self.profile,
3140 );
3141
3142 self.draw_instanced_batch(
3143 &batch.instances,
3144 VertexArrayKind::Primitive,
3145 &batch.key.textures,
3146 stats
3147 );
3148 }
3149
3150 self.set_blend(false, framebuffer_kind);
3151 self.gpu_profiler.finish_sampler(transparent_sampler);
3152 }
3153
3154 self.device.disable_depth();
3155 if uses_scissor {
3156 self.device.disable_scissor();
3157 }
3158 }
3159
3160 fn update_external_native_surfaces(
3162 &mut self,
3163 external_surfaces: &[ResolvedExternalSurface],
3164 results: &mut RenderResults,
3165 ) {
3166 if external_surfaces.is_empty() {
3167 return;
3168 }
3169
3170 let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
3171
3172 self.device.disable_depth();
3173 self.set_blend(false, FramebufferKind::Main);
3174
3175 for surface in external_surfaces {
3176 let (native_surface_id, surface_size) = match surface.update_params {
3178 Some(params) => params,
3179 None => continue,
3180 };
3181
3182 let surface_rect = surface_size.into();
3185
3186 let surface_info = self.compositor_config
3188 .compositor()
3189 .unwrap()
3190 .bind(
3191 &mut self.device,
3192 NativeTileId {
3193 surface_id: native_surface_id,
3194 x: 0,
3195 y: 0,
3196 },
3197 surface_rect,
3198 surface_rect,
3199 );
3200
3201 let draw_target = DrawTarget::NativeSurface {
3203 offset: surface_info.origin,
3204 external_fbo_id: surface_info.fbo_id,
3205 dimensions: surface_size,
3206 };
3207 self.device.bind_draw_target(draw_target);
3208
3209 let projection = Transform3D::ortho(
3210 0.0,
3211 surface_size.width as f32,
3212 0.0,
3213 surface_size.height as f32,
3214 self.device.ortho_near_plane(),
3215 self.device.ortho_far_plane(),
3216 );
3217
3218 let ( textures, instance ) = match surface.color_data {
3219 ResolvedExternalSurfaceColorData::Yuv{
3220 ref planes, color_space, format, channel_bit_depth, .. } => {
3221
3222 let textures = BatchTextures::composite_yuv(
3223 planes[0].texture,
3224 planes[1].texture,
3225 planes[2].texture,
3226 );
3227
3228 let uv_rects = [
3234 self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
3235 self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
3236 self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
3237 ];
3238
3239 let instance = CompositeInstance::new_yuv(
3240 surface_rect.to_f32(),
3241 surface_rect.to_f32(),
3242 color_space,
3245 format,
3246 channel_bit_depth,
3247 uv_rects,
3248 (false, false),
3249 None,
3250 );
3251
3252 self.shaders
3254 .borrow_mut()
3255 .get_composite_shader(
3256 CompositeSurfaceFormat::Yuv,
3257 surface.image_buffer_kind,
3258 instance.get_yuv_features(),
3259 ).bind(
3260 &mut self.device,
3261 &projection,
3262 None,
3263 &mut self.renderer_errors,
3264 &mut self.profile,
3265 );
3266
3267 ( textures, instance )
3268 },
3269 ResolvedExternalSurfaceColorData::Rgb{ ref plane, .. } => {
3270 let textures = BatchTextures::composite_rgb(plane.texture);
3271 let uv_rect = self.texture_resolver.get_uv_rect(&textures.input.colors[0], plane.uv_rect);
3272 let instance = CompositeInstance::new_rgb(
3273 surface_rect.to_f32(),
3274 surface_rect.to_f32(),
3275 PremultipliedColorF::WHITE,
3276 uv_rect,
3277 plane.texture.uses_normalized_uvs(),
3278 (false, false),
3279 None,
3280 );
3281 let features = instance.get_rgb_features();
3282
3283 self.shaders
3284 .borrow_mut()
3285 .get_composite_shader(
3286 CompositeSurfaceFormat::Rgba,
3287 surface.image_buffer_kind,
3288 features,
3289 ).bind(
3290 &mut self.device,
3291 &projection,
3292 None,
3293 &mut self.renderer_errors,
3294 &mut self.profile,
3295 );
3296
3297 ( textures, instance )
3298 },
3299 };
3300
3301 self.draw_instanced_batch(
3302 &[instance],
3303 VertexArrayKind::Composite,
3304 &textures,
3305 &mut results.stats,
3306 );
3307
3308 self.compositor_config
3309 .compositor()
3310 .unwrap()
3311 .unbind(&mut self.device);
3312 }
3313
3314 self.gpu_profiler.finish_sampler(opaque_sampler);
3315 }
3316
3317 fn draw_tile_list<'a, I: Iterator<Item = &'a occlusion::Item<OcclusionItemKey>>>(
3319 &mut self,
3320 tiles_iter: I,
3321 composite_state: &CompositeState,
3322 external_surfaces: &[ResolvedExternalSurface],
3323 projection: &default::Transform3D<f32>,
3324 stats: &mut RendererStats,
3325 ) {
3326 let mut current_shader_params = (
3327 CompositeSurfaceFormat::Rgba,
3328 ImageBufferKind::Texture2D,
3329 CompositeFeatures::empty(),
3330 None,
3331 );
3332 let mut current_textures = BatchTextures::empty();
3333 let mut instances = Vec::new();
3334
3335 self.shaders
3336 .borrow_mut()
3337 .get_composite_shader(
3338 current_shader_params.0,
3339 current_shader_params.1,
3340 current_shader_params.2,
3341 ).bind(
3342 &mut self.device,
3343 projection,
3344 None,
3345 &mut self.renderer_errors,
3346 &mut self.profile,
3347 );
3348
3349 for item in tiles_iter {
3350 let tile = &composite_state.tiles[item.key.tile_index];
3351
3352 let clip_rect = item.rectangle;
3353 let tile_rect = composite_state.get_device_rect(&tile.local_rect, tile.transform_index);
3354 let transform = composite_state.get_device_transform(tile.transform_index);
3355 let flip = (transform.scale.x < 0.0, transform.scale.y < 0.0);
3356
3357 let clip = if item.key.needs_mask {
3358 tile.clip_index.map(|index| {
3359 composite_state.get_compositor_clip(index)
3360 })
3361 } else {
3362 None
3363 };
3364
3365 let (instance, textures, shader_params) = match tile.surface {
3367 CompositeTileSurface::Color { color } => {
3368 let dummy = TextureSource::Dummy;
3369 let image_buffer_kind = dummy.image_buffer_kind();
3370 let instance = CompositeInstance::new(
3371 tile_rect,
3372 clip_rect,
3373 color.premultiplied(),
3374 flip,
3375 clip,
3376 );
3377 let features = instance.get_rgb_features();
3378 (
3379 instance,
3380 BatchTextures::composite_rgb(dummy),
3381 (CompositeSurfaceFormat::Rgba, image_buffer_kind, features, None),
3382 )
3383 }
3384 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::TextureCache { texture } } => {
3385 let instance = CompositeInstance::new(
3386 tile_rect,
3387 clip_rect,
3388 PremultipliedColorF::WHITE,
3389 flip,
3390 clip,
3391 );
3392 let features = instance.get_rgb_features();
3393 (
3394 instance,
3395 BatchTextures::composite_rgb(texture),
3396 (
3397 CompositeSurfaceFormat::Rgba,
3398 ImageBufferKind::Texture2D,
3399 features,
3400 None,
3401 ),
3402 )
3403 }
3404 CompositeTileSurface::ExternalSurface { external_surface_index } => {
3405 let surface = &external_surfaces[external_surface_index.0];
3406
3407 match surface.color_data {
3408 ResolvedExternalSurfaceColorData::Yuv{ ref planes, color_space, format, channel_bit_depth, .. } => {
3409 let textures = BatchTextures::composite_yuv(
3410 planes[0].texture,
3411 planes[1].texture,
3412 planes[2].texture,
3413 );
3414
3415 let uv_rects = [
3421 self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
3422 self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
3423 self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
3424 ];
3425
3426 let instance = CompositeInstance::new_yuv(
3427 tile_rect,
3428 clip_rect,
3429 color_space,
3430 format,
3431 channel_bit_depth,
3432 uv_rects,
3433 flip,
3434 clip,
3435 );
3436 let features = instance.get_yuv_features();
3437
3438 (
3439 instance,
3440 textures,
3441 (
3442 CompositeSurfaceFormat::Yuv,
3443 surface.image_buffer_kind,
3444 features,
3445 None
3446 ),
3447 )
3448 },
3449 ResolvedExternalSurfaceColorData::Rgb { ref plane, .. } => {
3450 let uv_rect = self.texture_resolver.get_uv_rect(&plane.texture, plane.uv_rect);
3451 let instance = CompositeInstance::new_rgb(
3452 tile_rect,
3453 clip_rect,
3454 PremultipliedColorF::WHITE,
3455 uv_rect,
3456 plane.texture.uses_normalized_uvs(),
3457 flip,
3458 clip,
3459 );
3460 let features = instance.get_rgb_features();
3461 (
3462 instance,
3463 BatchTextures::composite_rgb(plane.texture),
3464 (
3465 CompositeSurfaceFormat::Rgba,
3466 surface.image_buffer_kind,
3467 features,
3468 Some(self.texture_resolver.get_texture_size(&plane.texture).to_f32()),
3469 ),
3470 )
3471 },
3472 }
3473 }
3474 CompositeTileSurface::Clear => {
3475 let dummy = TextureSource::Dummy;
3476 let image_buffer_kind = dummy.image_buffer_kind();
3477 let instance = CompositeInstance::new(
3478 tile_rect,
3479 clip_rect,
3480 PremultipliedColorF::BLACK,
3481 flip,
3482 clip,
3483 );
3484 let features = instance.get_rgb_features();
3485 (
3486 instance,
3487 BatchTextures::composite_rgb(dummy),
3488 (CompositeSurfaceFormat::Rgba, image_buffer_kind, features, None),
3489 )
3490 }
3491 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { .. } } => {
3492 unreachable!("bug: found native surface in simple composite path");
3493 }
3494 };
3495
3496 let flush_batch = !current_textures.is_compatible_with(&textures) ||
3498 shader_params != current_shader_params;
3499
3500 if flush_batch {
3501 if !instances.is_empty() {
3502 self.draw_instanced_batch(
3503 &instances,
3504 VertexArrayKind::Composite,
3505 ¤t_textures,
3506 stats,
3507 );
3508 instances.clear();
3509 }
3510 }
3511
3512 if shader_params != current_shader_params {
3513 self.shaders
3514 .borrow_mut()
3515 .get_composite_shader(shader_params.0, shader_params.1, shader_params.2)
3516 .bind(
3517 &mut self.device,
3518 projection,
3519 shader_params.3,
3520 &mut self.renderer_errors,
3521 &mut self.profile,
3522 );
3523
3524 current_shader_params = shader_params;
3525 }
3526
3527 current_textures = textures;
3528
3529 instances.push(instance);
3531 }
3532
3533 if !instances.is_empty() {
3535 self.draw_instanced_batch(
3536 &instances,
3537 VertexArrayKind::Composite,
3538 ¤t_textures,
3539 stats,
3540 );
3541 }
3542 }
3543
3544 fn composite_pass(
3547 &mut self,
3548 composite_state: &CompositeState,
3549 draw_target: DrawTarget,
3550 clear_color: ColorF,
3551 projection: &default::Transform3D<f32>,
3552 results: &mut RenderResults,
3553 partial_present_mode: Option<PartialPresentMode>,
3554 layer: &SwapChainLayer,
3555 ) {
3556 self.device.bind_draw_target(draw_target);
3557 self.device.disable_depth_write();
3558 self.device.disable_depth();
3559
3560 if let Some(partial_present) = self.compositor_config.partial_present() {
3566 if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
3567 partial_present.set_buffer_damage_region(&[dirty_rect.to_i32()]);
3568 }
3569 }
3570
3571 let clear_color = Some(clear_color.to_array());
3573
3574 match partial_present_mode {
3575 Some(PartialPresentMode::Single { dirty_rect }) => {
3576 if !dirty_rect.is_empty() && layer.occlusion.test(&dirty_rect) {
3581 self.device.clear_target(clear_color,
3583 None,
3584 Some(draw_target.to_framebuffer_rect(dirty_rect.to_i32())));
3585 }
3586 }
3587 None => {
3588 self.device.clear_target(clear_color,
3590 None,
3591 None);
3592 }
3593 }
3594
3595 let opaque_items = layer.occlusion.opaque_items();
3597 if !opaque_items.is_empty() {
3598 let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
3599 self.set_blend(false, FramebufferKind::Main);
3600 self.draw_tile_list(
3601 opaque_items.iter(),
3602 &composite_state,
3603 &composite_state.external_surfaces,
3604 projection,
3605 &mut results.stats,
3606 );
3607 self.gpu_profiler.finish_sampler(opaque_sampler);
3608 }
3609
3610 if !layer.clear_tiles.is_empty() {
3612 let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
3613 self.set_blend(true, FramebufferKind::Main);
3614 self.device.set_blend_mode_premultiplied_dest_out();
3615 self.draw_tile_list(
3616 layer.clear_tiles.iter(),
3617 &composite_state,
3618 &composite_state.external_surfaces,
3619 projection,
3620 &mut results.stats,
3621 );
3622 self.gpu_profiler.finish_sampler(transparent_sampler);
3623 }
3624
3625 let alpha_items = layer.occlusion.alpha_items();
3627 if !alpha_items.is_empty() {
3628 let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
3629 self.set_blend(true, FramebufferKind::Main);
3630 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Main);
3631 self.draw_tile_list(
3632 alpha_items.iter().rev(),
3633 &composite_state,
3634 &composite_state.external_surfaces,
3635 projection,
3636 &mut results.stats,
3637 );
3638 self.gpu_profiler.finish_sampler(transparent_sampler);
3639 }
3640 }
3641
3642 fn composite_simple(
3647 &mut self,
3648 composite_state: &CompositeState,
3649 frame_device_size: DeviceIntSize,
3650 fb_draw_target: DrawTarget,
3651 projection: &default::Transform3D<f32>,
3652 results: &mut RenderResults,
3653 partial_present_mode: Option<PartialPresentMode>,
3654 device_size: DeviceIntSize,
3655 ) {
3656 let _gm = self.gpu_profiler.start_marker("framebuffer");
3657 let _timer = self.gpu_profiler.start_timer(GPU_TAG_COMPOSITE);
3658
3659 let num_tiles = composite_state.tiles
3662 .iter()
3663 .filter(|tile| tile.kind != TileKind::Clear).count();
3664 self.profile.set(profiler::PICTURE_TILES, num_tiles);
3665
3666 let (window_is_opaque, enable_screenshot) = match self.compositor_config.layer_compositor() {
3667 Some(ref compositor) => {
3668 let props = compositor.get_window_properties();
3669 (props.is_opaque, props.enable_screenshot)
3670 }
3671 None => (true, true)
3672 };
3673
3674 let mut input_layers: Vec<CompositorInputLayer> = Vec::new();
3675 let mut swapchain_layers = Vec::new();
3676 let cap = composite_state.tiles.len();
3677 let mut segment_builder = SegmentBuilder::new();
3678 let mut tile_index_to_layer_index = vec![None; composite_state.tiles.len()];
3679 let mut full_render_occlusion = occlusion::FrontToBackBuilder::with_capacity(cap, cap);
3680 let mut layer_compositor_frame_state = LayerCompositorFrameState{
3681 tile_states: FastHashMap::default(),
3682 rects_without_id: Vec::new(),
3683 };
3684
3685 if self.debug_overlay_state.is_enabled {
3689 self.debug_overlay_state.layer_index = input_layers.len();
3690
3691 input_layers.push(CompositorInputLayer {
3692 usage: CompositorSurfaceUsage::DebugOverlay,
3693 is_opaque: false,
3694 offset: DeviceIntPoint::zero(),
3695 clip_rect: device_size.into(),
3696 });
3697
3698 swapchain_layers.push(SwapChainLayer {
3699 clear_tiles: Vec::new(),
3700 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
3701 });
3702 }
3703
3704 for (idx, tile) in composite_state.tiles.iter().enumerate() {
3707 let device_tile_box = composite_state.get_device_rect(
3708 &tile.local_rect,
3709 tile.transform_index
3710 );
3711
3712 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
3713 match tile.tile_id {
3714 Some(tile_id) => {
3715 layer_compositor_frame_state.
3716 tile_states
3717 .insert(
3718 tile_id,
3719 CompositeTileState {
3720 local_rect: tile.local_rect,
3721 local_valid_rect: tile.local_valid_rect,
3722 device_clip_rect: tile.device_clip_rect,
3723 z_id: tile.z_id,
3724 device_tile_box: device_tile_box,
3725 visible_rects: Vec::new(),
3726 },
3727 );
3728 }
3729 None => {}
3730 }
3731 }
3732
3733 let device_valid_rect = composite_state
3735 .get_device_rect(&tile.local_valid_rect, tile.transform_index);
3736
3737 let rect = device_tile_box
3738 .intersection_unchecked(&tile.device_clip_rect)
3739 .intersection_unchecked(&device_valid_rect);
3740
3741 if rect.is_empty() {
3742 continue;
3743 }
3744
3745 let usage = match tile.surface {
3747 CompositeTileSurface::Texture { .. } |
3748 CompositeTileSurface::Color { .. } |
3749 CompositeTileSurface::Clear => {
3750 CompositorSurfaceUsage::Content
3751 }
3752 CompositeTileSurface::ExternalSurface { external_surface_index } => {
3753 match (self.current_compositor_kind, enable_screenshot) {
3754 (CompositorKind::Native { .. }, _) | (CompositorKind::Draw { .. }, _) => {
3755 CompositorSurfaceUsage::Content
3756 }
3757 (CompositorKind::Layer { .. }, true) => {
3758 CompositorSurfaceUsage::Content
3759 }
3760 (CompositorKind::Layer { .. }, false) => {
3761 let surface = &composite_state.external_surfaces[external_surface_index.0];
3762
3763 match surface.external_image_id {
3767 Some(external_image_id) => {
3768 let image_key = match surface.color_data {
3769 ResolvedExternalSurfaceColorData::Rgb { image_dependency, .. } => image_dependency.key,
3770 ResolvedExternalSurfaceColorData::Yuv { image_dependencies, .. } => image_dependencies[0].key,
3771 };
3772
3773 CompositorSurfaceUsage::External {
3774 image_key,
3775 external_image_id,
3776 transform_index: tile.transform_index,
3777 }
3778 }
3779 None => {
3780 CompositorSurfaceUsage::Content
3781 }
3782 }
3783 }
3784 }
3785 }
3786 };
3787
3788 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
3789 if let CompositeTileSurface::ExternalSurface { .. } = tile.surface {
3790 assert!(tile.tile_id.is_none());
3791 if let CompositorSurfaceUsage::Content = usage {
3793 layer_compositor_frame_state.rects_without_id.push(rect);
3794 }
3795 } else {
3796 assert!(tile.tile_id.is_some());
3797 }
3798 }
3799
3800 let new_layer_kind = match input_layers.last() {
3802 Some(curr_layer) => {
3803 match (curr_layer.usage, usage) {
3804 (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::Content) => None,
3806 (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::Content) => Some(usage),
3807
3808 (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::External { .. }) |
3810 (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::External { .. }) => {
3811 match self.compositor_config {
3813 CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => None,
3814 CompositorConfig::Layer { .. } => {
3815 Some(usage)
3816 }
3817 }
3818 }
3819 (CompositorSurfaceUsage::DebugOverlay, _) => {
3820 Some(usage)
3821 }
3822 (_, CompositorSurfaceUsage::DebugOverlay) => {
3824 unreachable!();
3825 }
3826 }
3827 }
3828 None => {
3829 Some(usage)
3831 }
3832 };
3833
3834 if let Some(new_layer_kind) = new_layer_kind {
3835 let (offset, clip_rect, is_opaque) = match usage {
3836 CompositorSurfaceUsage::Content => {
3837 (
3838 DeviceIntPoint::zero(),
3839 device_size.into(),
3840 false, )
3842 }
3843 CompositorSurfaceUsage::External { .. } => {
3844 let rect = composite_state.get_device_rect(
3845 &tile.local_rect,
3846 tile.transform_index
3847 );
3848
3849 let clip_rect = tile.device_clip_rect.to_i32();
3850 let is_opaque = tile.kind != TileKind::Alpha;
3851
3852 (rect.min.to_i32(), clip_rect, is_opaque)
3853 }
3854 CompositorSurfaceUsage::DebugOverlay => unreachable!(),
3855 };
3856
3857 input_layers.push(CompositorInputLayer {
3858 usage: new_layer_kind,
3859 is_opaque,
3860 offset,
3861 clip_rect,
3862 });
3863
3864 swapchain_layers.push(SwapChainLayer {
3865 clear_tiles: Vec::new(),
3866 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
3867 })
3868 }
3869 tile_index_to_layer_index[idx] = Some(input_layers.len() - 1);
3870
3871 match tile.kind {
3874 TileKind::Opaque | TileKind::Alpha => {
3875 let is_opaque = tile.kind != TileKind::Alpha;
3876
3877 match tile.clip_index {
3878 Some(clip_index) => {
3879 let clip = composite_state.get_compositor_clip(clip_index);
3880
3881 segment_builder.initialize(
3883 rect.cast_unit(),
3884 None,
3885 rect.cast_unit(),
3886 );
3887 segment_builder.push_clip_rect(
3888 clip.rect.cast_unit(),
3889 Some(clip.radius),
3890 ClipMode::Clip,
3891 );
3892 segment_builder.build(|segment| {
3893 let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };
3894
3895 full_render_occlusion.add(
3896 &segment.rect.cast_unit(),
3897 is_opaque && !segment.has_mask,
3898 key,
3899 );
3900 });
3901 }
3902 None => {
3903 full_render_occlusion.add(&rect, is_opaque, OcclusionItemKey {
3904 tile_index: idx,
3905 needs_mask: false,
3906 });
3907 }
3908 }
3909 }
3910 TileKind::Clear => {}
3911 }
3912 }
3913
3914 assert_eq!(swapchain_layers.len(), input_layers.len());
3915
3916 if window_is_opaque {
3917 match input_layers.last_mut() {
3918 Some(_layer) => {
3919 }
3926 None => {
3927 input_layers.push(CompositorInputLayer {
3931 usage: CompositorSurfaceUsage::Content,
3932 is_opaque: true,
3933 offset: DeviceIntPoint::zero(),
3934 clip_rect: device_size.into(),
3935 });
3936
3937 swapchain_layers.push(SwapChainLayer {
3938 clear_tiles: Vec::new(),
3939 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
3940 });
3941 }
3942 }
3943 }
3944
3945 let mut full_render = false;
3946
3947 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
3949 let input = CompositorInputConfig {
3950 enable_screenshot,
3951 layers: &input_layers,
3952 };
3953 full_render = compositor.begin_frame(&input);
3954 }
3955
3956 let mut partial_present_mode = if full_render {
3958 None
3959 } else {
3960 partial_present_mode
3961 };
3962
3963 assert_eq!(swapchain_layers.len(), input_layers.len());
3964
3965 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
3967 for item in full_render_occlusion
3969 .opaque_items()
3970 .iter()
3971 .chain(full_render_occlusion.alpha_items().iter()) {
3972 let tile = &composite_state.tiles[item.key.tile_index];
3973 match tile.tile_id {
3974 Some(tile_id) => {
3975 if let Some(tile_state) = layer_compositor_frame_state.tile_states.get_mut(&tile_id) {
3976 tile_state.visible_rects.push(item.rectangle);
3977 } else {
3978 unreachable!();
3979 }
3980 }
3981 None => {}
3982 }
3983 }
3984
3985 let can_use_partial_present =
3986 !self.force_redraw && !full_render &&
3987 self.layer_compositor_frame_state_in_prev_frame.is_some();
3988
3989 if can_use_partial_present {
3990 let mut combined_dirty_rect = DeviceRect::zero();
3991
3992 for tile in composite_state.tiles.iter() {
3993 if tile.kind == TileKind::Clear {
3994 continue;
3995 }
3996
3997 if tile.tile_id.is_none() {
3998 match tile.surface {
3999 CompositeTileSurface::ExternalSurface { .. } => {}
4000 CompositeTileSurface::Texture { .. } |
4001 CompositeTileSurface::Color { .. } |
4002 CompositeTileSurface::Clear => {
4003 unreachable!();
4004 },
4005 }
4006 continue;
4007 }
4008
4009 assert!(tile.tile_id.is_some());
4010
4011 let tiles_exists_in_prev_frame =
4012 self.layer_compositor_frame_state_in_prev_frame
4013 .as_ref()
4014 .unwrap()
4015 .tile_states
4016 .contains_key(&tile.tile_id.unwrap());
4017 let tile_id = tile.tile_id.unwrap();
4018 let tile_state = layer_compositor_frame_state.tile_states.get(&tile_id).unwrap();
4019
4020 if tiles_exists_in_prev_frame {
4021 let prev_tile_state = self.layer_compositor_frame_state_in_prev_frame
4022 .as_ref()
4023 .unwrap()
4024 .tile_states
4025 .get(&tile_id)
4026 .unwrap();
4027
4028 if tile_state.same_state(prev_tile_state) {
4029 let dirty_rect = composite_state.get_device_rect(
4032 &tile.local_dirty_rect,
4033 tile.transform_index,
4034 );
4035 for rect in tile_state.visible_rects.iter() {
4036 let visible_dirty_rect = rect.intersection(&dirty_rect);
4037 if visible_dirty_rect.is_some() {
4038 combined_dirty_rect = combined_dirty_rect.union(&visible_dirty_rect.unwrap());
4039 }
4040 }
4041 } else {
4042 for rect in tile_state.visible_rects
4045 .iter()
4046 .chain(prev_tile_state.visible_rects.iter()) {
4047 combined_dirty_rect = combined_dirty_rect.union(&rect);
4048 }
4049 }
4050 } else {
4051 for rect in &tile_state.visible_rects {
4053 combined_dirty_rect = combined_dirty_rect.union(&rect);
4054 }
4055 }
4056 }
4057
4058 for (tile_id, tile_state) in self.layer_compositor_frame_state_in_prev_frame
4060 .as_ref()
4061 .unwrap()
4062 .tile_states
4063 .iter() {
4064 if !layer_compositor_frame_state.tile_states.contains_key(&tile_id) {
4065 for rect in tile_state.visible_rects.iter() {
4066 combined_dirty_rect = combined_dirty_rect.union(&rect);
4067 }
4068 }
4069 }
4070
4071 for rect in layer_compositor_frame_state
4073 .rects_without_id
4074 .iter()
4075 .chain(self.layer_compositor_frame_state_in_prev_frame.as_ref().unwrap().rects_without_id.iter()) {
4076 combined_dirty_rect = combined_dirty_rect.union(&rect);
4077 }
4078
4079 partial_present_mode = Some(PartialPresentMode::Single {
4080 dirty_rect: combined_dirty_rect,
4081 });
4082 } else {
4083 partial_present_mode = None;
4084 }
4085
4086 self.layer_compositor_frame_state_in_prev_frame = Some(layer_compositor_frame_state);
4087 }
4088
4089 for (idx, tile) in composite_state.tiles.iter().enumerate() {
4094 let device_tile_box = composite_state.get_device_rect(
4095 &tile.local_rect,
4096 tile.transform_index
4097 );
4098
4099 let partial_clip_rect = match partial_present_mode {
4102 Some(PartialPresentMode::Single { dirty_rect }) => dirty_rect,
4103 None => device_tile_box,
4104 };
4105
4106 let device_valid_rect = composite_state
4108 .get_device_rect(&tile.local_valid_rect, tile.transform_index);
4109
4110 let rect = device_tile_box
4111 .intersection_unchecked(&tile.device_clip_rect)
4112 .intersection_unchecked(&partial_clip_rect)
4113 .intersection_unchecked(&device_valid_rect);
4114
4115 if rect.is_empty() {
4116 continue;
4117 }
4118
4119 let layer_index = match tile_index_to_layer_index[idx] {
4120 None => {
4121 error!("rect {:?} should have valid layer index", rect);
4123 continue;
4124 }
4125 Some(layer_index) => layer_index,
4126 };
4127
4128 let layer = &mut swapchain_layers[layer_index];
4131
4132 match tile.kind {
4134 TileKind::Opaque | TileKind::Alpha => {
4135 let is_opaque = tile.kind != TileKind::Alpha;
4136
4137 match tile.clip_index {
4138 Some(clip_index) => {
4139 let clip = composite_state.get_compositor_clip(clip_index);
4140
4141 segment_builder.initialize(
4143 rect.cast_unit(),
4144 None,
4145 rect.cast_unit(),
4146 );
4147 segment_builder.push_clip_rect(
4148 clip.rect.cast_unit(),
4149 Some(clip.radius),
4150 ClipMode::Clip,
4151 );
4152 segment_builder.build(|segment| {
4153 let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };
4154
4155 layer.occlusion.add(
4156 &segment.rect.cast_unit(),
4157 is_opaque && !segment.has_mask,
4158 key,
4159 );
4160 });
4161 }
4162 None => {
4163 layer.occlusion.add(&rect, is_opaque, OcclusionItemKey {
4164 tile_index: idx,
4165 needs_mask: false,
4166 });
4167 }
4168 }
4169 }
4170 TileKind::Clear => {
4171 layer.clear_tiles.push(occlusion::Item { rectangle: rect, key: OcclusionItemKey { tile_index: idx, needs_mask: false } });
4176 }
4177 }
4178 }
4179
4180 assert_eq!(swapchain_layers.len(), input_layers.len());
4181 let mut content_clear_color = Some(self.clear_color);
4182
4183 for (layer_index, (layer, swapchain_layer)) in input_layers.iter().zip(swapchain_layers.iter()).enumerate() {
4184 self.device.reset_state();
4185
4186 match layer.usage {
4188 CompositorSurfaceUsage::Content => {}
4189 CompositorSurfaceUsage::External { .. } | CompositorSurfaceUsage::DebugOverlay => {
4190 continue;
4191 }
4192 }
4193
4194 let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT);
4196
4197 if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() {
4198 if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
4199 if dirty_rect.is_empty() {
4200 continue;
4201 }
4202 }
4203 }
4204
4205 let draw_target = match self.compositor_config {
4206 CompositorConfig::Layer { ref mut compositor } => {
4207 match partial_present_mode {
4208 Some(PartialPresentMode::Single { dirty_rect }) => {
4209 compositor.bind_layer(layer_index, &[dirty_rect.to_i32()]);
4210 }
4211 None => {
4212 compositor.bind_layer(layer_index, &[]);
4213 }
4214 };
4215
4216 DrawTarget::NativeSurface {
4217 offset: -layer.offset,
4218 external_fbo_id: 0,
4219 dimensions: frame_device_size,
4220 }
4221 }
4222 CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => {
4224 fb_draw_target
4225 }
4226 };
4227
4228 self.composite_pass(
4232 composite_state,
4233 draw_target,
4234 clear_color,
4235 projection,
4236 results,
4237 partial_present_mode,
4238 swapchain_layer,
4239 );
4240
4241 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
4242 match partial_present_mode {
4243 Some(PartialPresentMode::Single { dirty_rect }) => {
4244 compositor.present_layer(layer_index, &[dirty_rect.to_i32()]);
4245 }
4246 None => {
4247 compositor.present_layer(layer_index, &[]);
4248 }
4249 };
4250 }
4251 }
4252
4253 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
4255 for (layer_index, layer) in input_layers.iter().enumerate() {
4256 let transform = match layer.usage {
4259 CompositorSurfaceUsage::Content => CompositorSurfaceTransform::identity(),
4260 CompositorSurfaceUsage::External { transform_index, .. } => composite_state.get_compositor_transform(transform_index),
4261 CompositorSurfaceUsage::DebugOverlay => CompositorSurfaceTransform::identity(),
4262 };
4263
4264 compositor.add_surface(
4265 layer_index,
4266 transform,
4267 layer.clip_rect,
4268 ImageRendering::Auto,
4269 );
4270 }
4271 }
4272 }
4273
4274 fn clear_render_target(
4275 &mut self,
4276 target: &RenderTarget,
4277 draw_target: DrawTarget,
4278 framebuffer_kind: FramebufferKind,
4279 projection: &default::Transform3D<f32>,
4280 stats: &mut RendererStats,
4281 ) {
4282 let needs_depth = target.needs_depth();
4283
4284 let clear_depth = if needs_depth {
4285 Some(1.0)
4286 } else {
4287 None
4288 };
4289
4290 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_TARGET);
4291
4292 self.device.disable_depth();
4293 self.set_blend(false, framebuffer_kind);
4294
4295 let is_alpha = target.target_kind == RenderTargetKind::Alpha;
4296 let require_precise_clear = target.cached;
4297
4298 let clear_with_quads = (target.cached && self.clear_caches_with_quads)
4302 || (is_alpha && self.clear_alpha_targets_with_quads);
4303
4304 let favor_partial_updates = self.device.get_capabilities().supports_render_target_partial_update
4305 && self.enable_clear_scissor;
4306
4307 let full_clears_on_adreno = is_alpha && self.device.get_capabilities().requires_alpha_target_full_clear;
4310 let require_full_clear = !require_precise_clear
4311 && (full_clears_on_adreno || !favor_partial_updates);
4312
4313 let clear_color = target
4314 .clear_color
4315 .map(|color| color.to_array());
4316
4317 let mut cleared_depth = false;
4318 if clear_with_quads {
4319 } else if require_precise_clear {
4321 for (rect, color) in &target.clears {
4323 self.device.clear_target(
4324 Some(color.to_array()),
4325 None,
4326 Some(draw_target.to_framebuffer_rect(*rect)),
4327 );
4328 }
4329 } else {
4330 let clear_rect = if require_full_clear {
4334 None
4335 } else {
4336 match draw_target {
4337 DrawTarget::Default { rect, total_size, .. } => {
4338 if rect.min == FramebufferIntPoint::zero() && rect.size() == total_size {
4339 None
4341 } else {
4342 Some(rect)
4343 }
4344 }
4345 DrawTarget::Texture { .. } => {
4346 target.used_rect.map(|rect| draw_target.to_framebuffer_rect(rect))
4357 }
4358 _ => None,
4360 }
4361 };
4362
4363 self.device.clear_target(
4364 clear_color,
4365 clear_depth,
4366 clear_rect,
4367 );
4368 cleared_depth = true;
4369 }
4370
4371 if needs_depth && !cleared_depth {
4373 self.device.clear_target(None, clear_depth, None);
4376 }
4377
4378 let mut clear_instances = Vec::with_capacity(target.clears.len());
4383 for (rect, color) in &target.clears {
4384 if clear_with_quads || (!require_precise_clear && target.clear_color != Some(*color)) {
4385 let rect = rect.to_f32();
4386 clear_instances.push(ClearInstance {
4387 rect: [
4388 rect.min.x, rect.min.y,
4389 rect.max.x, rect.max.y,
4390 ],
4391 color: color.to_array(),
4392 })
4393 }
4394 }
4395
4396 if !clear_instances.is_empty() {
4397 self.shaders.borrow_mut().ps_clear().bind(
4398 &mut self.device,
4399 &projection,
4400 None,
4401 &mut self.renderer_errors,
4402 &mut self.profile,
4403 );
4404 self.draw_instanced_batch(
4405 &clear_instances,
4406 VertexArrayKind::Clear,
4407 &BatchTextures::empty(),
4408 stats,
4409 );
4410 }
4411 }
4412
4413 fn draw_render_target(
4414 &mut self,
4415 texture_id: CacheTextureId,
4416 target: &RenderTarget,
4417 render_tasks: &RenderTaskGraph,
4418 stats: &mut RendererStats,
4419 ) {
4420 let needs_depth = target.needs_depth();
4421
4422 let texture = self.texture_resolver.get_cache_texture_mut(&texture_id);
4423 if needs_depth {
4424 self.device.reuse_render_target::<u8>(
4425 texture,
4426 RenderTargetInfo { has_depth: needs_depth },
4427 );
4428 }
4429
4430 let draw_target = DrawTarget::from_texture(
4431 texture,
4432 needs_depth,
4433 );
4434
4435 let projection = Transform3D::ortho(
4436 0.0,
4437 draw_target.dimensions().width as f32,
4438 0.0,
4439 draw_target.dimensions().height as f32,
4440 self.device.ortho_near_plane(),
4441 self.device.ortho_far_plane(),
4442 );
4443
4444 profile_scope!("draw_render_target");
4445 let _gm = self.gpu_profiler.start_marker("render target");
4446
4447 let counter = match target.target_kind {
4448 RenderTargetKind::Color => profiler::COLOR_PASSES,
4449 RenderTargetKind::Alpha => profiler::ALPHA_PASSES,
4450 };
4451 self.profile.inc(counter);
4452
4453 let sampler_query = match target.target_kind {
4454 RenderTargetKind::Color => None,
4455 RenderTargetKind::Alpha => Some(self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_ALPHA)),
4456 };
4457
4458 if let DrawTarget::Texture { with_depth, .. } = draw_target {
4460 assert!(with_depth >= target.needs_depth());
4461 }
4462
4463 let framebuffer_kind = if draw_target.is_default() {
4464 FramebufferKind::Main
4465 } else {
4466 FramebufferKind::Other
4467 };
4468
4469 self.device.bind_draw_target(draw_target);
4470
4471 if self.device.get_capabilities().supports_qcom_tiled_rendering {
4472 let preserve_mask = match target.clear_color {
4473 Some(_) => 0,
4474 None => gl::COLOR_BUFFER_BIT0_QCOM,
4475 };
4476 if let Some(used_rect) = target.used_rect {
4477 self.device.gl().start_tiling_qcom(
4478 used_rect.min.x.max(0) as _,
4479 used_rect.min.y.max(0) as _,
4480 used_rect.width() as _,
4481 used_rect.height() as _,
4482 preserve_mask,
4483 );
4484 }
4485 }
4486
4487 if needs_depth {
4488 self.device.enable_depth_write();
4489 } else {
4490 self.device.disable_depth_write();
4491 }
4492
4493 self.clear_render_target(
4494 target,
4495 draw_target,
4496 framebuffer_kind,
4497 &projection,
4498 stats,
4499 );
4500
4501 if needs_depth {
4502 self.device.disable_depth_write();
4503 }
4504
4505 self.handle_resolves(
4507 &target.resolve_ops,
4508 render_tasks,
4509 draw_target,
4510 );
4511
4512 self.handle_blits(
4514 &target.blits,
4515 render_tasks,
4516 draw_target,
4517 );
4518
4519 if !target.border_segments_solid.is_empty() ||
4521 !target.border_segments_complex.is_empty()
4522 {
4523 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_BORDER);
4524
4525 self.set_blend(true, FramebufferKind::Other);
4526 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
4527
4528 if !target.border_segments_solid.is_empty() {
4529 self.shaders.borrow_mut().cs_border_solid().bind(
4530 &mut self.device,
4531 &projection,
4532 None,
4533 &mut self.renderer_errors,
4534 &mut self.profile,
4535 );
4536
4537 self.draw_instanced_batch(
4538 &target.border_segments_solid,
4539 VertexArrayKind::Border,
4540 &BatchTextures::empty(),
4541 stats,
4542 );
4543 }
4544
4545 if !target.border_segments_complex.is_empty() {
4546 self.shaders.borrow_mut().cs_border_segment().bind(
4547 &mut self.device,
4548 &projection,
4549 None,
4550 &mut self.renderer_errors,
4551 &mut self.profile,
4552 );
4553
4554 self.draw_instanced_batch(
4555 &target.border_segments_complex,
4556 VertexArrayKind::Border,
4557 &BatchTextures::empty(),
4558 stats,
4559 );
4560 }
4561
4562 self.set_blend(false, FramebufferKind::Other);
4563 }
4564
4565 if !target.line_decorations.is_empty() {
4567 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_LINE_DECORATION);
4568
4569 self.set_blend(true, FramebufferKind::Other);
4570 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
4571
4572 self.shaders.borrow_mut().cs_line_decoration().bind(
4573 &mut self.device,
4574 &projection,
4575 None,
4576 &mut self.renderer_errors,
4577 &mut self.profile,
4578 );
4579
4580 self.draw_instanced_batch(
4581 &target.line_decorations,
4582 VertexArrayKind::LineDecoration,
4583 &BatchTextures::empty(),
4584 stats,
4585 );
4586
4587 self.set_blend(false, FramebufferKind::Other);
4588 }
4589
4590 if !target.fast_linear_gradients.is_empty() {
4592 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_FAST_LINEAR_GRADIENT);
4593
4594 self.set_blend(false, FramebufferKind::Other);
4595
4596 self.shaders.borrow_mut().cs_fast_linear_gradient().bind(
4597 &mut self.device,
4598 &projection,
4599 None,
4600 &mut self.renderer_errors,
4601 &mut self.profile,
4602 );
4603
4604 self.draw_instanced_batch(
4605 &target.fast_linear_gradients,
4606 VertexArrayKind::FastLinearGradient,
4607 &BatchTextures::empty(),
4608 stats,
4609 );
4610 }
4611
4612 if !target.linear_gradients.is_empty() {
4614 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_LINEAR_GRADIENT);
4615
4616 self.set_blend(false, FramebufferKind::Other);
4617
4618 self.shaders.borrow_mut().cs_linear_gradient().bind(
4619 &mut self.device,
4620 &projection,
4621 None,
4622 &mut self.renderer_errors,
4623 &mut self.profile,
4624 );
4625
4626 if let Some(ref texture) = self.dither_matrix_texture {
4627 self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
4628 }
4629
4630 self.draw_instanced_batch(
4631 &target.linear_gradients,
4632 VertexArrayKind::LinearGradient,
4633 &BatchTextures::empty(),
4634 stats,
4635 );
4636 }
4637
4638 if !target.radial_gradients.is_empty() {
4640 let _timer = self.gpu_profiler.start_timer(GPU_TAG_RADIAL_GRADIENT);
4641
4642 self.set_blend(false, FramebufferKind::Other);
4643
4644 self.shaders.borrow_mut().cs_radial_gradient().bind(
4645 &mut self.device,
4646 &projection,
4647 None,
4648 &mut self.renderer_errors,
4649 &mut self.profile,
4650 );
4651
4652 if let Some(ref texture) = self.dither_matrix_texture {
4653 self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
4654 }
4655
4656 self.draw_instanced_batch(
4657 &target.radial_gradients,
4658 VertexArrayKind::RadialGradient,
4659 &BatchTextures::empty(),
4660 stats,
4661 );
4662 }
4663
4664 if !target.conic_gradients.is_empty() {
4666 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CONIC_GRADIENT);
4667
4668 self.set_blend(false, FramebufferKind::Other);
4669
4670 self.shaders.borrow_mut().cs_conic_gradient().bind(
4671 &mut self.device,
4672 &projection,
4673 None,
4674 &mut self.renderer_errors,
4675 &mut self.profile,
4676 );
4677
4678 if let Some(ref texture) = self.dither_matrix_texture {
4679 self.device.bind_texture(TextureSampler::Dither, texture, Swizzle::default());
4680 }
4681
4682 self.draw_instanced_batch(
4683 &target.conic_gradients,
4684 VertexArrayKind::ConicGradient,
4685 &BatchTextures::empty(),
4686 stats,
4687 );
4688 }
4689
4690 if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
4697 let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLUR);
4698
4699 self.set_blend(false, framebuffer_kind);
4700 self.shaders.borrow_mut().cs_blur_rgba8()
4701 .bind(&mut self.device, &projection, None, &mut self.renderer_errors, &mut self.profile);
4702
4703 if !target.vertical_blurs.is_empty() {
4704 self.draw_blurs(
4705 &target.vertical_blurs,
4706 stats,
4707 );
4708 }
4709
4710 if !target.horizontal_blurs.is_empty() {
4711 self.draw_blurs(
4712 &target.horizontal_blurs,
4713 stats,
4714 );
4715 }
4716 }
4717
4718 self.handle_scaling(
4719 &target.scalings,
4720 &projection,
4721 stats,
4722 );
4723
4724 for (ref textures, ref filters) in &target.svg_filters {
4725 self.handle_svg_filters(
4726 textures,
4727 filters,
4728 &projection,
4729 stats,
4730 );
4731 }
4732
4733 for (ref textures, ref filters) in &target.svg_nodes {
4734 self.handle_svg_nodes(textures, filters, &projection, stats);
4735 }
4736
4737 for alpha_batch_container in &target.alpha_batch_containers {
4738 self.draw_alpha_batch_container(
4739 alpha_batch_container,
4740 draw_target,
4741 framebuffer_kind,
4742 &projection,
4743 render_tasks,
4744 stats,
4745 );
4746 }
4747
4748 self.handle_prims(
4749 &draw_target,
4750 &target.prim_instances,
4751 &target.prim_instances_with_scissor,
4752 &projection,
4753 stats,
4754 );
4755
4756 let has_primary_clips = !target.clip_batcher.primary_clips.is_empty();
4758 let has_secondary_clips = !target.clip_batcher.secondary_clips.is_empty();
4759 let has_clip_masks = !target.clip_masks.is_empty();
4760 if has_primary_clips | has_secondary_clips | has_clip_masks {
4761 let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_CLIP);
4762
4763 if has_primary_clips {
4767 self.set_blend(false, FramebufferKind::Other);
4771 self.draw_clip_batch_list(
4772 &target.clip_batcher.primary_clips,
4773 &projection,
4774 stats,
4775 );
4776 }
4777
4778 if has_secondary_clips {
4779 self.set_blend(true, FramebufferKind::Other);
4782 self.set_blend_mode_multiply(FramebufferKind::Other);
4783 self.draw_clip_batch_list(
4784 &target.clip_batcher.secondary_clips,
4785 &projection,
4786 stats,
4787 );
4788 }
4789
4790 if has_clip_masks {
4791 self.handle_clips(
4792 &draw_target,
4793 &target.clip_masks,
4794 &projection,
4795 stats,
4796 );
4797 }
4798 }
4799
4800 if needs_depth {
4801 self.device.invalidate_depth_target();
4802 }
4803 if self.device.get_capabilities().supports_qcom_tiled_rendering {
4804 self.device.gl().end_tiling_qcom(gl::COLOR_BUFFER_BIT0_QCOM);
4805 }
4806
4807 if let Some(sampler) = sampler_query {
4808 self.gpu_profiler.finish_sampler(sampler);
4809 }
4810 }
4811
4812 fn draw_blurs(
4813 &mut self,
4814 blurs: &FastHashMap<TextureSource, FrameVec<BlurInstance>>,
4815 stats: &mut RendererStats,
4816 ) {
4817 for (texture, blurs) in blurs {
4818 let textures = BatchTextures::composite_rgb(
4819 *texture,
4820 );
4821
4822 self.draw_instanced_batch(
4823 blurs,
4824 VertexArrayKind::Blur,
4825 &textures,
4826 stats,
4827 );
4828 }
4829 }
4830
4831 fn draw_clip_batch_list(
4833 &mut self,
4834 list: &ClipBatchList,
4835 projection: &default::Transform3D<f32>,
4836 stats: &mut RendererStats,
4837 ) {
4838 if self.debug_flags.contains(DebugFlags::DISABLE_CLIP_MASKS) {
4839 return;
4840 }
4841
4842 if !list.slow_rectangles.is_empty() {
4844 let _gm2 = self.gpu_profiler.start_marker("slow clip rectangles");
4845 self.shaders.borrow_mut().cs_clip_rectangle_slow().bind(
4846 &mut self.device,
4847 projection,
4848 None,
4849 &mut self.renderer_errors,
4850 &mut self.profile,
4851 );
4852 self.draw_instanced_batch(
4853 &list.slow_rectangles,
4854 VertexArrayKind::ClipRect,
4855 &BatchTextures::empty(),
4856 stats,
4857 );
4858 }
4859 if !list.fast_rectangles.is_empty() {
4860 let _gm2 = self.gpu_profiler.start_marker("fast clip rectangles");
4861 self.shaders.borrow_mut().cs_clip_rectangle_fast().bind(
4862 &mut self.device,
4863 projection,
4864 None,
4865 &mut self.renderer_errors,
4866 &mut self.profile,
4867 );
4868 self.draw_instanced_batch(
4869 &list.fast_rectangles,
4870 VertexArrayKind::ClipRect,
4871 &BatchTextures::empty(),
4872 stats,
4873 );
4874 }
4875
4876 for (mask_texture_id, items) in list.box_shadows.iter() {
4878 let _gm2 = self.gpu_profiler.start_marker("box-shadows");
4879 let textures = BatchTextures::composite_rgb(*mask_texture_id);
4880 self.shaders.borrow_mut().cs_clip_box_shadow()
4881 .bind(&mut self.device, projection, None, &mut self.renderer_errors, &mut self.profile);
4882 self.draw_instanced_batch(
4883 items,
4884 VertexArrayKind::ClipBoxShadow,
4885 &textures,
4886 stats,
4887 );
4888 }
4889 }
4890
4891 fn update_deferred_resolves(&mut self, deferred_resolves: &[DeferredResolve]) -> Option<GpuCacheUpdateList> {
4892 if deferred_resolves.is_empty() {
4897 return None;
4898 }
4899
4900 let handler = self.external_image_handler
4901 .as_mut()
4902 .expect("Found external image, but no handler set!");
4903
4904 let mut list = GpuCacheUpdateList {
4905 frame_id: FrameId::INVALID,
4906 clear: false,
4907 height: self.gpu_cache_texture.get_height(),
4908 blocks: Vec::new(),
4909 updates: Vec::new(),
4910 debug_commands: Vec::new(),
4911 };
4912
4913 for (i, deferred_resolve) in deferred_resolves.iter().enumerate() {
4914 self.gpu_profiler.place_marker("deferred resolve");
4915 let props = &deferred_resolve.image_properties;
4916 let ext_image = props
4917 .external_image
4918 .expect("BUG: Deferred resolves must be external images!");
4919 let image = handler.lock(ext_image.id, ext_image.channel_index, deferred_resolve.is_composited);
4921 let texture_target = match ext_image.image_type {
4922 ExternalImageType::TextureHandle(target) => target,
4923 ExternalImageType::Buffer => {
4924 panic!("not a suitable image type in update_deferred_resolves()");
4925 }
4926 };
4927
4928 self.device.reset_state();
4931
4932 let texture = match image.source {
4933 ExternalImageSource::NativeTexture(texture_id) => {
4934 ExternalTexture::new(
4935 texture_id,
4936 texture_target,
4937 image.uv,
4938 deferred_resolve.rendering,
4939 )
4940 }
4941 ExternalImageSource::Invalid => {
4942 warn!("Invalid ext-image");
4943 debug!(
4944 "For ext_id:{:?}, channel:{}.",
4945 ext_image.id,
4946 ext_image.channel_index
4947 );
4948 ExternalTexture::new(
4950 0,
4951 texture_target,
4952 image.uv,
4953 deferred_resolve.rendering,
4954 )
4955 }
4956 ExternalImageSource::RawData(_) => {
4957 panic!("Raw external data is not expected for deferred resolves!");
4958 }
4959 };
4960
4961 self.texture_resolver
4962 .external_images
4963 .insert(DeferredResolveIndex(i as u32), texture);
4964
4965 list.updates.push(GpuCacheUpdate::Copy {
4966 block_index: list.blocks.len(),
4967 block_count: BLOCKS_PER_UV_RECT,
4968 address: deferred_resolve.address,
4969 });
4970 list.blocks.push(image.uv.into());
4971 list.blocks.push([0f32; 4].into());
4972 }
4973
4974 Some(list)
4975 }
4976
4977 fn unlock_external_images(
4978 &mut self,
4979 deferred_resolves: &[DeferredResolve],
4980 ) {
4981 if !self.texture_resolver.external_images.is_empty() {
4982 let handler = self.external_image_handler
4983 .as_mut()
4984 .expect("Found external image, but no handler set!");
4985
4986 for (index, _) in self.texture_resolver.external_images.drain() {
4987 let props = &deferred_resolves[index.0 as usize].image_properties;
4988 let ext_image = props
4989 .external_image
4990 .expect("BUG: Deferred resolves must be external images!");
4991 handler.unlock(ext_image.id, ext_image.channel_index);
4992 }
4993 }
4994 }
4995
4996 fn calculate_dirty_rects(
5000 &mut self,
5001 buffer_age: usize,
5002 composite_state: &CompositeState,
5003 draw_target_dimensions: DeviceIntSize,
5004 results: &mut RenderResults,
5005 ) -> Option<PartialPresentMode> {
5006
5007 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
5008 return None;
5010 }
5011
5012 let mut partial_present_mode = None;
5013
5014 let (max_partial_present_rects, draw_previous_partial_present_regions) = match self.current_compositor_kind {
5015 CompositorKind::Native { .. } => {
5016 (1, false)
5021 }
5022 CompositorKind::Draw { draw_previous_partial_present_regions, max_partial_present_rects } => {
5023 (max_partial_present_rects, draw_previous_partial_present_regions)
5024 }
5025 CompositorKind::Layer { .. } => {
5026 unreachable!();
5027 }
5028 };
5029
5030 if max_partial_present_rects > 0 {
5031 let prev_frames_damage_rect = if let Some(..) = self.compositor_config.partial_present() {
5032 self.buffer_damage_tracker
5033 .get_damage_rect(buffer_age)
5034 .or_else(|| Some(DeviceRect::from_size(draw_target_dimensions.to_f32())))
5035 } else {
5036 None
5037 };
5038
5039 let can_use_partial_present =
5040 composite_state.dirty_rects_are_valid &&
5041 !self.force_redraw &&
5042 !(prev_frames_damage_rect.is_none() && draw_previous_partial_present_regions) &&
5043 !self.debug_overlay_state.is_enabled;
5044
5045 if can_use_partial_present {
5046 let mut combined_dirty_rect = DeviceRect::zero();
5047 let fb_rect = DeviceRect::from_size(draw_target_dimensions.to_f32());
5048
5049 for tile in &composite_state.tiles {
5052 if tile.kind == TileKind::Clear {
5053 continue;
5054 }
5055 let dirty_rect = composite_state.get_device_rect(
5056 &tile.local_dirty_rect,
5057 tile.transform_index,
5058 );
5059
5060 if let Some(dirty_rect) = dirty_rect.intersection(&fb_rect) {
5065 combined_dirty_rect = combined_dirty_rect.union(&dirty_rect);
5066 }
5067 }
5068
5069 let combined_dirty_rect = combined_dirty_rect.round();
5070 let combined_dirty_rect_i32 = combined_dirty_rect.to_i32();
5071 if !combined_dirty_rect.is_empty() {
5074 results.dirty_rects.push(combined_dirty_rect_i32);
5075 }
5076
5077 if draw_previous_partial_present_regions {
5079 self.buffer_damage_tracker.push_dirty_rect(&combined_dirty_rect);
5080 }
5081
5082 let total_dirty_rect = if draw_previous_partial_present_regions {
5088 combined_dirty_rect.union(&prev_frames_damage_rect.unwrap())
5089 } else {
5090 combined_dirty_rect
5091 };
5092
5093 partial_present_mode = Some(PartialPresentMode::Single {
5094 dirty_rect: total_dirty_rect,
5095 });
5096 } else {
5097 let fb_rect = DeviceIntRect::from_size(
5100 draw_target_dimensions,
5101 );
5102 results.dirty_rects.push(fb_rect);
5103
5104 if draw_previous_partial_present_regions {
5105 self.buffer_damage_tracker.push_dirty_rect(&fb_rect.to_f32());
5106 }
5107 }
5108 }
5109
5110 partial_present_mode
5111 }
5112
5113 fn bind_frame_data(&mut self, frame: &mut Frame) {
5114 profile_scope!("bind_frame_data");
5115
5116 let _timer = self.gpu_profiler.start_timer(GPU_TAG_SETUP_DATA);
5117
5118 self.vertex_data_textures[self.current_vertex_data_textures].update(
5119 &mut self.device,
5120 &mut self.texture_upload_pbo_pool,
5121 frame,
5122 );
5123 self.current_vertex_data_textures =
5124 (self.current_vertex_data_textures + 1) % VERTEX_DATA_TEXTURE_COUNT;
5125 }
5126
5127 fn update_native_surfaces(&mut self) {
5128 profile_scope!("update_native_surfaces");
5129
5130 match self.compositor_config {
5131 CompositorConfig::Native { ref mut compositor, .. } => {
5132 for op in self.pending_native_surface_updates.drain(..) {
5133 match op.details {
5134 NativeSurfaceOperationDetails::CreateSurface { id, virtual_offset, tile_size, is_opaque } => {
5135 let _inserted = self.allocated_native_surfaces.insert(id);
5136 debug_assert!(_inserted, "bug: creating existing surface");
5137 compositor.create_surface(
5138 &mut self.device,
5139 id,
5140 virtual_offset,
5141 tile_size,
5142 is_opaque,
5143 );
5144 }
5145 NativeSurfaceOperationDetails::CreateExternalSurface { id, is_opaque } => {
5146 let _inserted = self.allocated_native_surfaces.insert(id);
5147 debug_assert!(_inserted, "bug: creating existing surface");
5148 compositor.create_external_surface(
5149 &mut self.device,
5150 id,
5151 is_opaque,
5152 );
5153 }
5154 NativeSurfaceOperationDetails::CreateBackdropSurface { id, color } => {
5155 let _inserted = self.allocated_native_surfaces.insert(id);
5156 debug_assert!(_inserted, "bug: creating existing surface");
5157 compositor.create_backdrop_surface(
5158 &mut self.device,
5159 id,
5160 color,
5161 );
5162 }
5163 NativeSurfaceOperationDetails::DestroySurface { id } => {
5164 let _existed = self.allocated_native_surfaces.remove(&id);
5165 debug_assert!(_existed, "bug: removing unknown surface");
5166 compositor.destroy_surface(&mut self.device, id);
5167 }
5168 NativeSurfaceOperationDetails::CreateTile { id } => {
5169 compositor.create_tile(&mut self.device, id);
5170 }
5171 NativeSurfaceOperationDetails::DestroyTile { id } => {
5172 compositor.destroy_tile(&mut self.device, id);
5173 }
5174 NativeSurfaceOperationDetails::AttachExternalImage { id, external_image } => {
5175 compositor.attach_external_image(&mut self.device, id, external_image);
5176 }
5177 }
5178 }
5179 }
5180 CompositorConfig::Draw { .. } | CompositorConfig::Layer { .. } => {
5181 debug_assert!(self.pending_native_surface_updates.is_empty());
5184 }
5185 }
5186 }
5187
5188 fn create_gpu_buffer_texture<T: Texel>(
5189 &mut self,
5190 buffer: &GpuBuffer<T>,
5191 sampler: TextureSampler,
5192 ) -> Option<Texture> {
5193 if buffer.is_empty() {
5194 None
5195 } else {
5196 let gpu_buffer_texture = self.device.create_texture(
5197 ImageBufferKind::Texture2D,
5198 buffer.format,
5199 buffer.size.width,
5200 buffer.size.height,
5201 TextureFilter::Nearest,
5202 None,
5203 );
5204
5205 self.device.bind_texture(
5206 sampler,
5207 &gpu_buffer_texture,
5208 Swizzle::default(),
5209 );
5210
5211 self.device.upload_texture_immediate(
5212 &gpu_buffer_texture,
5213 &buffer.data,
5214 );
5215
5216 Some(gpu_buffer_texture)
5217 }
5218 }
5219
5220 fn draw_frame(
5221 &mut self,
5222 frame: &mut Frame,
5223 device_size: Option<DeviceIntSize>,
5224 buffer_age: usize,
5225 results: &mut RenderResults,
5226 ) {
5227 profile_scope!("draw_frame");
5228
5229 #[cfg(not(target_os = "android"))]
5231 let _gm = self.gpu_profiler.start_marker("draw frame");
5232
5233 if frame.passes.is_empty() {
5234 frame.has_been_rendered = true;
5235 return;
5236 }
5237
5238 self.device.disable_depth_write();
5239 self.set_blend(false, FramebufferKind::Other);
5240 self.device.disable_stencil();
5241
5242 self.bind_frame_data(frame);
5243
5244 let gpu_buffer_texture_f = self.create_gpu_buffer_texture(
5247 &frame.gpu_buffer_f,
5248 TextureSampler::GpuBufferF,
5249 );
5250 let gpu_buffer_texture_i = self.create_gpu_buffer_texture(
5251 &frame.gpu_buffer_i,
5252 TextureSampler::GpuBufferI,
5253 );
5254
5255 let bytes_to_mb = 1.0 / 1000000.0;
5256 let gpu_buffer_bytes_f = gpu_buffer_texture_f
5257 .as_ref()
5258 .map(|tex| tex.size_in_bytes())
5259 .unwrap_or(0);
5260 let gpu_buffer_bytes_i = gpu_buffer_texture_i
5261 .as_ref()
5262 .map(|tex| tex.size_in_bytes())
5263 .unwrap_or(0);
5264 let gpu_buffer_mb = (gpu_buffer_bytes_f + gpu_buffer_bytes_i) as f32 * bytes_to_mb;
5265 self.profile.set(profiler::GPU_BUFFER_MEM, gpu_buffer_mb);
5266
5267 let gpu_cache_bytes = self.gpu_cache_texture.gpu_size_in_bytes();
5268 let gpu_cache_mb = gpu_cache_bytes as f32 * bytes_to_mb;
5269 self.profile.set(profiler::GPU_CACHE_MEM, gpu_cache_mb);
5270
5271 let present_mode = device_size.and_then(|device_size| {
5277 self.calculate_dirty_rects(
5278 buffer_age,
5279 &frame.composite_state,
5280 device_size,
5281 results,
5282 )
5283 });
5284
5285 if let CompositorKind::Native { .. } = self.current_compositor_kind {
5294 let compositor = self.compositor_config.compositor().unwrap();
5295 if !frame.has_been_rendered {
5297 for tile in &frame.composite_state.tiles {
5298 if tile.kind == TileKind::Clear {
5299 continue;
5300 }
5301 if !tile.local_dirty_rect.is_empty() {
5302 if let CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { id, .. } } = tile.surface {
5303 let valid_rect = frame.composite_state.get_surface_rect(
5304 &tile.local_valid_rect,
5305 &tile.local_rect,
5306 tile.transform_index,
5307 ).to_i32();
5308
5309 compositor.invalidate_tile(&mut self.device, id, valid_rect);
5310 }
5311 }
5312 }
5313 }
5314 for surface in &frame.composite_state.external_surfaces {
5319 if let Some((native_surface_id, size)) = surface.update_params {
5320 let surface_rect = size.into();
5321 compositor.invalidate_tile(&mut self.device, NativeTileId { surface_id: native_surface_id, x: 0, y: 0 }, surface_rect);
5322 }
5323 }
5324 if device_size.is_some() {
5329 frame.composite_state.composite_native(
5330 self.clear_color,
5331 &results.dirty_rects,
5332 &mut self.device,
5333 &mut **compositor,
5334 );
5335 }
5336 }
5337
5338 for (_pass_index, pass) in frame.passes.iter_mut().enumerate() {
5339 #[cfg(not(target_os = "android"))]
5340 let _gm = self.gpu_profiler.start_marker(&format!("pass {}", _pass_index));
5341
5342 profile_scope!("offscreen target");
5343
5344 if !frame.has_been_rendered {
5348 for (&texture_id, target) in &pass.texture_cache {
5349 self.draw_render_target(
5350 texture_id,
5351 target,
5352 &frame.render_tasks,
5353 &mut results.stats,
5354 );
5355 }
5356
5357 if !pass.picture_cache.is_empty() {
5358 self.profile.inc(profiler::COLOR_PASSES);
5359 }
5360
5361 for picture_target in &pass.picture_cache {
5363 results.stats.color_target_count += 1;
5364
5365 let draw_target = match picture_target.surface {
5366 ResolvedSurfaceTexture::TextureCache { ref texture } => {
5367 let (texture, _) = self.texture_resolver
5368 .resolve(texture)
5369 .expect("bug");
5370
5371 DrawTarget::from_texture(
5372 texture,
5373 true,
5374 )
5375 }
5376 ResolvedSurfaceTexture::Native { id, size } => {
5377 let surface_info = match self.current_compositor_kind {
5378 CompositorKind::Native { .. } => {
5379 let compositor = self.compositor_config.compositor().unwrap();
5380 compositor.bind(
5381 &mut self.device,
5382 id,
5383 picture_target.dirty_rect,
5384 picture_target.valid_rect,
5385 )
5386 }
5387 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
5388 unreachable!();
5389 }
5390 };
5391
5392 DrawTarget::NativeSurface {
5393 offset: surface_info.origin,
5394 external_fbo_id: surface_info.fbo_id,
5395 dimensions: size,
5396 }
5397 }
5398 };
5399
5400 let projection = Transform3D::ortho(
5401 0.0,
5402 draw_target.dimensions().width as f32,
5403 0.0,
5404 draw_target.dimensions().height as f32,
5405 self.device.ortho_near_plane(),
5406 self.device.ortho_far_plane(),
5407 );
5408
5409 self.draw_picture_cache_target(
5410 picture_target,
5411 draw_target,
5412 &projection,
5413 &frame.render_tasks,
5414 &mut results.stats,
5415 );
5416
5417 if let ResolvedSurfaceTexture::Native { .. } = picture_target.surface {
5419 match self.current_compositor_kind {
5420 CompositorKind::Native { .. } => {
5421 let compositor = self.compositor_config.compositor().unwrap();
5422 compositor.unbind(&mut self.device);
5423 }
5424 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
5425 unreachable!();
5426 }
5427 }
5428 }
5429 }
5430 }
5431
5432 for target in &pass.alpha.targets {
5433 results.stats.alpha_target_count += 1;
5434 self.draw_render_target(
5435 target.texture_id(),
5436 target,
5437 &frame.render_tasks,
5438 &mut results.stats,
5439 );
5440 }
5441
5442 for target in &pass.color.targets {
5443 results.stats.color_target_count += 1;
5444 self.draw_render_target(
5445 target.texture_id(),
5446 target,
5447 &frame.render_tasks,
5448 &mut results.stats,
5449 );
5450 }
5451
5452 self.texture_resolver.end_pass(
5458 &mut self.device,
5459 &pass.textures_to_invalidate,
5460 );
5461 }
5462
5463 self.composite_frame(
5464 frame,
5465 device_size,
5466 results,
5467 present_mode,
5468 );
5469
5470 if let Some(gpu_buffer_texture_f) = gpu_buffer_texture_f {
5471 self.device.delete_texture(gpu_buffer_texture_f);
5472 }
5473 if let Some(gpu_buffer_texture_i) = gpu_buffer_texture_i {
5474 self.device.delete_texture(gpu_buffer_texture_i);
5475 }
5476
5477 frame.has_been_rendered = true;
5478 }
5479
5480 fn composite_frame(
5481 &mut self,
5482 frame: &mut Frame,
5483 device_size: Option<DeviceIntSize>,
5484 results: &mut RenderResults,
5485 present_mode: Option<PartialPresentMode>,
5486 ) {
5487 profile_scope!("main target");
5488
5489 if let Some(device_size) = device_size {
5490 results.stats.color_target_count += 1;
5491 results.picture_cache_debug = mem::replace(
5492 &mut frame.composite_state.picture_cache_debug,
5493 PictureCacheDebugInfo::new(),
5494 );
5495
5496 let size = frame.device_rect.size().to_f32();
5497 let surface_origin_is_top_left = self.device.surface_origin_is_top_left();
5498 let (bottom, top) = if surface_origin_is_top_left {
5499 (0.0, size.height)
5500 } else {
5501 (size.height, 0.0)
5502 };
5503
5504 let projection = Transform3D::ortho(
5505 0.0,
5506 size.width,
5507 bottom,
5508 top,
5509 self.device.ortho_near_plane(),
5510 self.device.ortho_far_plane(),
5511 );
5512
5513 let fb_scale = Scale::<_, _, FramebufferPixel>::new(1i32);
5514 let mut fb_rect = frame.device_rect * fb_scale;
5515
5516 if !surface_origin_is_top_left {
5517 let h = fb_rect.height();
5518 fb_rect.min.y = device_size.height - fb_rect.max.y;
5519 fb_rect.max.y = fb_rect.min.y + h;
5520 }
5521
5522 let draw_target = DrawTarget::Default {
5523 rect: fb_rect,
5524 total_size: device_size * fb_scale,
5525 surface_origin_is_top_left,
5526 };
5527
5528 match self.current_compositor_kind {
5531 CompositorKind::Native { .. } => {
5532 self.update_external_native_surfaces(
5536 &frame.composite_state.external_surfaces,
5537 results,
5538 );
5539 }
5540 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
5541 self.composite_simple(
5542 &frame.composite_state,
5543 frame.device_rect.size(),
5544 draw_target,
5545 &projection,
5546 results,
5547 present_mode,
5548 device_size,
5549 );
5550 }
5551 }
5552 self.force_redraw = false;
5554 } else {
5555 self.force_redraw = true;
5558 }
5559 }
5560
5561 pub fn debug_renderer(&mut self) -> Option<&mut DebugRenderer> {
5562 self.debug.get_mut(&mut self.device)
5563 }
5564
5565 pub fn get_debug_flags(&self) -> DebugFlags {
5566 self.debug_flags
5567 }
5568
5569 pub fn set_debug_flags(&mut self, flags: DebugFlags) {
5570 if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_TIME_QUERIES) {
5571 if enabled {
5572 self.gpu_profiler.enable_timers();
5573 } else {
5574 self.gpu_profiler.disable_timers();
5575 }
5576 }
5577 if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_SAMPLE_QUERIES) {
5578 if enabled {
5579 self.gpu_profiler.enable_samplers();
5580 } else {
5581 self.gpu_profiler.disable_samplers();
5582 }
5583 }
5584
5585 self.debug_flags = flags;
5586 }
5587
5588 pub fn set_profiler_ui(&mut self, ui_str: &str) {
5589 self.profiler.set_ui(ui_str);
5590 }
5591
5592 fn draw_frame_debug_items(&mut self, items: &[DebugItem]) {
5593 if items.is_empty() {
5594 return;
5595 }
5596
5597 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5598 Some(render) => render,
5599 None => return,
5600 };
5601
5602 for item in items {
5603 match item {
5604 DebugItem::Rect { rect, outer_color, inner_color, thickness } => {
5605 if inner_color.a > 0.001 {
5606 let rect = rect.inflate(-thickness as f32, -thickness as f32);
5607 debug_renderer.add_quad(
5608 rect.min.x,
5609 rect.min.y,
5610 rect.max.x,
5611 rect.max.y,
5612 (*inner_color).into(),
5613 (*inner_color).into(),
5614 );
5615 }
5616
5617 if outer_color.a > 0.001 {
5618 debug_renderer.add_rect(
5619 &rect.to_i32(),
5620 *thickness,
5621 (*outer_color).into(),
5622 );
5623 }
5624 }
5625 DebugItem::Text { ref msg, position, color } => {
5626 debug_renderer.add_text(
5627 position.x,
5628 position.y,
5629 msg,
5630 (*color).into(),
5631 None,
5632 );
5633 }
5634 }
5635 }
5636 }
5637
5638 fn draw_render_target_debug(&mut self, draw_target: &DrawTarget) {
5639 if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
5640 return;
5641 }
5642
5643 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5644 Some(render) => render,
5645 None => return,
5646 };
5647
5648 let textures = self.texture_resolver
5649 .texture_cache_map
5650 .values()
5651 .filter(|item| item.category == TextureCacheCategory::RenderTarget)
5652 .map(|item| &item.texture)
5653 .collect::<Vec<&Texture>>();
5654
5655 Self::do_debug_blit(
5656 &mut self.device,
5657 debug_renderer,
5658 textures,
5659 draw_target,
5660 0,
5661 &|_| [0.0, 1.0, 0.0, 1.0], );
5663 }
5664
5665 fn draw_zoom_debug(
5666 &mut self,
5667 device_size: DeviceIntSize,
5668 ) {
5669 if !self.debug_flags.contains(DebugFlags::ZOOM_DBG) {
5670 return;
5671 }
5672
5673 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5674 Some(render) => render,
5675 None => return,
5676 };
5677
5678 let source_size = DeviceIntSize::new(64, 64);
5679 let target_size = DeviceIntSize::new(1024, 1024);
5680
5681 let source_origin = DeviceIntPoint::new(
5682 (self.cursor_position.x - source_size.width / 2)
5683 .min(device_size.width - source_size.width)
5684 .max(0),
5685 (self.cursor_position.y - source_size.height / 2)
5686 .min(device_size.height - source_size.height)
5687 .max(0),
5688 );
5689
5690 let source_rect = DeviceIntRect::from_origin_and_size(
5691 source_origin,
5692 source_size,
5693 );
5694
5695 let target_rect = DeviceIntRect::from_origin_and_size(
5696 DeviceIntPoint::new(
5697 device_size.width - target_size.width - 64,
5698 device_size.height - target_size.height - 64,
5699 ),
5700 target_size,
5701 );
5702
5703 let texture_rect = FramebufferIntRect::from_size(
5704 source_rect.size().cast_unit(),
5705 );
5706
5707 debug_renderer.add_rect(
5708 &target_rect.inflate(1, 1),
5709 1,
5710 debug_colors::RED.into(),
5711 );
5712
5713 if self.zoom_debug_texture.is_none() {
5714 let texture = self.device.create_texture(
5715 ImageBufferKind::Texture2D,
5716 ImageFormat::BGRA8,
5717 source_rect.width(),
5718 source_rect.height(),
5719 TextureFilter::Nearest,
5720 Some(RenderTargetInfo { has_depth: false }),
5721 );
5722
5723 self.zoom_debug_texture = Some(texture);
5724 }
5725
5726 let read_target = DrawTarget::new_default(device_size, self.device.surface_origin_is_top_left());
5728 self.device.blit_render_target(
5729 read_target.into(),
5730 read_target.to_framebuffer_rect(source_rect),
5731 DrawTarget::from_texture(
5732 self.zoom_debug_texture.as_ref().unwrap(),
5733 false,
5734 ),
5735 texture_rect,
5736 TextureFilter::Nearest,
5737 );
5738
5739 self.device.blit_render_target(
5741 ReadTarget::from_texture(
5742 self.zoom_debug_texture.as_ref().unwrap(),
5743 ),
5744 texture_rect,
5745 read_target,
5746 read_target.to_framebuffer_rect(target_rect),
5747 TextureFilter::Nearest,
5748 );
5749 }
5750
5751 fn draw_texture_cache_debug(&mut self, draw_target: &DrawTarget) {
5752 if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
5753 return;
5754 }
5755
5756 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5757 Some(render) => render,
5758 None => return,
5759 };
5760
5761 let textures = self.texture_resolver
5762 .texture_cache_map
5763 .values()
5764 .filter(|item| item.category == TextureCacheCategory::Atlas)
5765 .map(|item| &item.texture)
5766 .collect::<Vec<&Texture>>();
5767
5768 fn select_color(texture: &Texture) -> [f32; 4] {
5769 if texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE) {
5770 [1.0, 0.5, 0.0, 1.0] } else {
5772 [1.0, 0.0, 1.0, 1.0] }
5774 }
5775
5776 Self::do_debug_blit(
5777 &mut self.device,
5778 debug_renderer,
5779 textures,
5780 draw_target,
5781 if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) { 544 } else { 0 },
5782 &select_color,
5783 );
5784 }
5785
5786 fn do_debug_blit(
5787 device: &mut Device,
5788 debug_renderer: &mut DebugRenderer,
5789 mut textures: Vec<&Texture>,
5790 draw_target: &DrawTarget,
5791 bottom: i32,
5792 select_color: &dyn Fn(&Texture) -> [f32; 4],
5793 ) {
5794 let mut spacing = 16;
5795 let mut size = 512;
5796
5797 let device_size = draw_target.dimensions();
5798 let fb_width = device_size.width;
5799 let fb_height = device_size.height;
5800 let surface_origin_is_top_left = draw_target.surface_origin_is_top_left();
5801
5802 let num_textures = textures.len() as i32;
5803
5804 if num_textures * (size + spacing) > fb_width {
5805 let factor = fb_width as f32 / (num_textures * (size + spacing)) as f32;
5806 size = (size as f32 * factor) as i32;
5807 spacing = (spacing as f32 * factor) as i32;
5808 }
5809
5810 let text_height = 14; let text_margin = 1;
5812 let tag_height = text_height + text_margin * 2;
5813 let tag_y = fb_height - (bottom + spacing + tag_height);
5814 let image_y = tag_y - size;
5815
5816 textures.sort_by_key(|t| t.size_in_bytes());
5822
5823 let mut i = 0;
5824 for texture in textures.iter() {
5825 let dimensions = texture.get_dimensions();
5826 let src_rect = FramebufferIntRect::from_size(
5827 FramebufferIntSize::new(dimensions.width as i32, dimensions.height as i32),
5828 );
5829
5830 let x = fb_width - (spacing + size) * (i as i32 + 1);
5831
5832 if x > fb_width {
5834 return;
5835 }
5836
5837 let tag_rect = rect(x, tag_y, size, tag_height).to_box2d();
5839 let tag_color = select_color(texture);
5840 device.clear_target(
5841 Some(tag_color),
5842 None,
5843 Some(draw_target.to_framebuffer_rect(tag_rect)),
5844 );
5845
5846 let dim = texture.get_dimensions();
5848 let text_rect = tag_rect.inflate(-text_margin, -text_margin);
5849 debug_renderer.add_text(
5850 text_rect.min.x as f32,
5851 text_rect.max.y as f32, &format!("{}x{}", dim.width, dim.height),
5853 ColorU::new(0, 0, 0, 255),
5854 Some(tag_rect.to_f32())
5855 );
5856
5857 let dest_rect = draw_target.to_framebuffer_rect(rect(x, image_y, size, size).to_box2d());
5859 let read_target = ReadTarget::from_texture(texture);
5860
5861 if surface_origin_is_top_left {
5862 device.blit_render_target(
5863 read_target,
5864 src_rect,
5865 *draw_target,
5866 dest_rect,
5867 TextureFilter::Linear,
5868 );
5869 } else {
5870 device.blit_render_target_invert_y(
5872 read_target,
5873 src_rect,
5874 *draw_target,
5875 dest_rect,
5876 );
5877 }
5878 i += 1;
5879 }
5880 }
5881
5882 fn draw_epoch_debug(&mut self) {
5883 if !self.debug_flags.contains(DebugFlags::EPOCHS) {
5884 return;
5885 }
5886
5887 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5888 Some(render) => render,
5889 None => return,
5890 };
5891
5892 let dy = debug_renderer.line_height();
5893 let x0: f32 = 30.0;
5894 let y0: f32 = 30.0;
5895 let mut y = y0;
5896 let mut text_width = 0.0;
5897 for ((pipeline, document_id), epoch) in &self.pipeline_info.epochs {
5898 y += dy;
5899 let w = debug_renderer.add_text(
5900 x0, y,
5901 &format!("({:?}, {:?}): {:?}", pipeline, document_id, epoch),
5902 ColorU::new(255, 255, 0, 255),
5903 None,
5904 ).size.width;
5905 text_width = f32::max(text_width, w);
5906 }
5907
5908 let margin = 10.0;
5909 debug_renderer.add_quad(
5910 x0 - margin,
5911 y0 - margin,
5912 x0 + text_width + margin,
5913 y + margin,
5914 ColorU::new(25, 25, 25, 200),
5915 ColorU::new(51, 51, 51, 200),
5916 );
5917 }
5918
5919 fn draw_window_visibility_debug(&mut self) {
5920 if !self.debug_flags.contains(DebugFlags::WINDOW_VISIBILITY_DBG) {
5921 return;
5922 }
5923
5924 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5925 Some(render) => render,
5926 None => return,
5927 };
5928
5929 let x: f32 = 30.0;
5930 let y: f32 = 40.0;
5931
5932 if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config {
5933 let visibility = compositor.get_window_visibility(&mut self.device);
5934 let color = if visibility.is_fully_occluded {
5935 ColorU::new(255, 0, 0, 255)
5936
5937 } else {
5938 ColorU::new(0, 0, 255, 255)
5939 };
5940
5941 debug_renderer.add_text(
5942 x, y,
5943 &format!("{:?}", visibility),
5944 color,
5945 None,
5946 );
5947 }
5948
5949
5950 }
5951
5952 fn draw_gpu_cache_debug(&mut self, device_size: DeviceIntSize) {
5953 if !self.debug_flags.contains(DebugFlags::GPU_CACHE_DBG) {
5954 return;
5955 }
5956
5957 let debug_renderer = match self.debug.get_mut(&mut self.device) {
5958 Some(render) => render,
5959 None => return,
5960 };
5961
5962 let (x_off, y_off) = (30f32, 30f32);
5963 let height = self.gpu_cache_texture.get_height()
5964 .min(device_size.height - (y_off as i32) * 2) as usize;
5965 debug_renderer.add_quad(
5966 x_off,
5967 y_off,
5968 x_off + MAX_VERTEX_TEXTURE_WIDTH as f32,
5969 y_off + height as f32,
5970 ColorU::new(80, 80, 80, 80),
5971 ColorU::new(80, 80, 80, 80),
5972 );
5973
5974 let upper = self.gpu_cache_debug_chunks.len().min(height);
5975 for chunk in self.gpu_cache_debug_chunks[0..upper].iter().flatten() {
5976 let color = ColorU::new(250, 0, 0, 200);
5977 debug_renderer.add_quad(
5978 x_off + chunk.address.u as f32,
5979 y_off + chunk.address.v as f32,
5980 x_off + chunk.address.u as f32 + chunk.size as f32,
5981 y_off + chunk.address.v as f32 + 1.0,
5982 color,
5983 color,
5984 );
5985 }
5986 }
5987
5988 pub fn read_pixels_into(&mut self, rect: FramebufferIntRect, format: ImageFormat, output: &mut [u8]) {
5990 self.device.read_pixels_into(rect, format, output);
5991 }
5992
5993 pub fn read_pixels_rgba8(&mut self, rect: FramebufferIntRect) -> Vec<u8> {
5994 let mut pixels = vec![0; (rect.area() * 4) as usize];
5995 self.device.read_pixels_into(rect, ImageFormat::RGBA8, &mut pixels);
5996 pixels
5997 }
5998
5999 pub fn deinit(mut self) {
6001 self.device.begin_frame();
6003 if let CompositorConfig::Native { mut compositor, .. } = self.compositor_config {
6006 for id in self.allocated_native_surfaces.drain() {
6007 compositor.destroy_surface(&mut self.device, id);
6008 }
6009 if self.debug_overlay_state.current_size.is_some() {
6011 compositor.destroy_surface(&mut self.device, NativeSurfaceId::DEBUG_OVERLAY);
6012 }
6013 compositor.deinit(&mut self.device);
6014 }
6015 self.gpu_cache_texture.deinit(&mut self.device);
6016 if let Some(dither_matrix_texture) = self.dither_matrix_texture {
6017 self.device.delete_texture(dither_matrix_texture);
6018 }
6019 if let Some(zoom_debug_texture) = self.zoom_debug_texture {
6020 self.device.delete_texture(zoom_debug_texture);
6021 }
6022 for textures in self.vertex_data_textures.drain(..) {
6023 textures.deinit(&mut self.device);
6024 }
6025 self.texture_upload_pbo_pool.deinit(&mut self.device);
6026 self.staging_texture_pool.delete_textures(&mut self.device);
6027 self.texture_resolver.deinit(&mut self.device);
6028 self.vaos.deinit(&mut self.device);
6029 self.debug.deinit(&mut self.device);
6030
6031 if let Ok(shaders) = Rc::try_unwrap(self.shaders) {
6032 shaders.into_inner().deinit(&mut self.device);
6033 }
6034
6035 if let Some(async_screenshots) = self.async_screenshots.take() {
6036 async_screenshots.deinit(&mut self.device);
6037 }
6038
6039 if let Some(async_frame_recorder) = self.async_frame_recorder.take() {
6040 async_frame_recorder.deinit(&mut self.device);
6041 }
6042
6043 #[cfg(feature = "capture")]
6044 self.device.delete_fbo(self.read_fbo);
6045 #[cfg(feature = "replay")]
6046 for (_, ext) in self.owned_external_images {
6047 self.device.delete_external_texture(ext);
6048 }
6049 self.device.end_frame();
6050 }
6051
6052 pub fn report_memory(&self, swgl: *mut c_void) -> MemoryReport {
6054 let mut report = MemoryReport::default();
6055
6056 self.gpu_cache_texture.report_memory_to(&mut report, self.size_of_ops.as_ref().unwrap());
6058
6059 self.staging_texture_pool.report_memory_to(&mut report, self.size_of_ops.as_ref().unwrap());
6060
6061 for (_id, doc) in &self.active_documents {
6063 let frame_alloc_stats = doc.frame.allocator_memory.get_stats();
6064 report.frame_allocator += frame_alloc_stats.reserved_bytes;
6065 report.render_tasks += doc.frame.render_tasks.report_memory();
6066 }
6067
6068 for textures in &self.vertex_data_textures {
6070 report.vertex_data_textures += textures.size_in_bytes();
6071 }
6072
6073 report += self.texture_resolver.report_memory();
6075
6076 report += self.texture_upload_pbo_pool.report_memory();
6078
6079 report += self.device.report_memory(self.size_of_ops.as_ref().unwrap(), swgl);
6081
6082 report
6083 }
6084
6085 fn set_blend(&mut self, mut blend: bool, framebuffer_kind: FramebufferKind) {
6088 if framebuffer_kind == FramebufferKind::Main &&
6089 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6090 blend = true
6091 }
6092 self.device.set_blend(blend)
6093 }
6094
6095 fn set_blend_mode_multiply(&mut self, framebuffer_kind: FramebufferKind) {
6096 if framebuffer_kind == FramebufferKind::Main &&
6097 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6098 self.device.set_blend_mode_show_overdraw();
6099 } else {
6100 self.device.set_blend_mode_multiply();
6101 }
6102 }
6103
6104 fn set_blend_mode_premultiplied_alpha(&mut self, framebuffer_kind: FramebufferKind) {
6105 if framebuffer_kind == FramebufferKind::Main &&
6106 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
6107 self.device.set_blend_mode_show_overdraw();
6108 } else {
6109 self.device.set_blend_mode_premultiplied_alpha();
6110 }
6111 }
6112
6113 fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
6115 self.device.bind_draw_target(DrawTarget::from_texture(
6116 &texture,
6117 false,
6118 ));
6119 self.device.clear_target(Some(color), None, None);
6120 }
6121}
6122
6123bitflags! {
6124 #[derive(Default, Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
6126 pub struct ShaderPrecacheFlags: u32 {
6127 const EMPTY = 0;
6129
6130 const ASYNC_COMPILE = 1 << 2;
6132
6133 const FULL_COMPILE = 1 << 3;
6135 }
6136}
6137
6138#[derive(Debug, Default)]
6140pub struct FullFrameStats {
6141 pub full_display_list: bool,
6142 pub gecko_display_list_time: f64,
6143 pub wr_display_list_time: f64,
6144 pub scene_build_time: f64,
6145 pub frame_build_time: f64,
6146}
6147
6148impl FullFrameStats {
6149 pub fn merge(&self, other: &FullFrameStats) -> Self {
6150 Self {
6151 full_display_list: self.full_display_list || other.full_display_list,
6152 gecko_display_list_time: self.gecko_display_list_time + other.gecko_display_list_time,
6153 wr_display_list_time: self.wr_display_list_time + other.wr_display_list_time,
6154 scene_build_time: self.scene_build_time + other.scene_build_time,
6155 frame_build_time: self.frame_build_time + other.frame_build_time
6156 }
6157 }
6158
6159 pub fn total(&self) -> f64 {
6160 self.gecko_display_list_time + self.wr_display_list_time + self.scene_build_time + self.frame_build_time
6161 }
6162}
6163
6164#[repr(C)]
6168#[derive(Debug, Default)]
6169pub struct RendererStats {
6170 pub total_draw_calls: usize,
6171 pub alpha_target_count: usize,
6172 pub color_target_count: usize,
6173 pub texture_upload_mb: f64,
6174 pub resource_upload_time: f64,
6175 pub gpu_cache_upload_time: f64,
6176 pub gecko_display_list_time: f64,
6177 pub wr_display_list_time: f64,
6178 pub scene_build_time: f64,
6179 pub frame_build_time: f64,
6180 pub full_display_list: bool,
6181 pub full_paint: bool,
6182}
6183
6184impl RendererStats {
6185 pub fn merge(&mut self, stats: &FullFrameStats) {
6186 self.gecko_display_list_time = stats.gecko_display_list_time;
6187 self.wr_display_list_time = stats.wr_display_list_time;
6188 self.scene_build_time = stats.scene_build_time;
6189 self.frame_build_time = stats.frame_build_time;
6190 self.full_display_list = stats.full_display_list;
6191 self.full_paint = true;
6192 }
6193}
6194
6195#[derive(Debug, Default)]
6198pub struct RenderResults {
6199 pub stats: RendererStats,
6201
6202 pub dirty_rects: Vec<DeviceIntRect>,
6211
6212 pub picture_cache_debug: PictureCacheDebugInfo,
6215}
6216
6217#[cfg(any(feature = "capture", feature = "replay"))]
6218#[cfg_attr(feature = "capture", derive(Serialize))]
6219#[cfg_attr(feature = "replay", derive(Deserialize))]
6220struct PlainTexture {
6221 data: String,
6222 size: DeviceIntSize,
6223 format: ImageFormat,
6224 filter: TextureFilter,
6225 has_depth: bool,
6226 category: Option<TextureCacheCategory>,
6227}
6228
6229
6230#[cfg(any(feature = "capture", feature = "replay"))]
6231#[cfg_attr(feature = "capture", derive(Serialize))]
6232#[cfg_attr(feature = "replay", derive(Deserialize))]
6233struct PlainRenderer {
6234 device_size: Option<DeviceIntSize>,
6235 gpu_cache: PlainTexture,
6236 gpu_cache_frame_id: FrameId,
6237 textures: FastHashMap<CacheTextureId, PlainTexture>,
6238}
6239
6240#[cfg(any(feature = "capture", feature = "replay"))]
6241#[cfg_attr(feature = "capture", derive(Serialize))]
6242#[cfg_attr(feature = "replay", derive(Deserialize))]
6243struct PlainExternalResources {
6244 images: Vec<ExternalCaptureImage>
6245}
6246
6247#[cfg(feature = "replay")]
6248enum CapturedExternalImageData {
6249 NativeTexture(gl::GLuint),
6250 Buffer(Arc<Vec<u8>>),
6251}
6252
6253#[cfg(feature = "replay")]
6254struct DummyExternalImageHandler {
6255 data: FastHashMap<(ExternalImageId, u8), (CapturedExternalImageData, TexelRect)>,
6256}
6257
6258#[cfg(feature = "replay")]
6259impl ExternalImageHandler for DummyExternalImageHandler {
6260 fn lock(&mut self, key: ExternalImageId, channel_index: u8, _is_composited: bool) -> ExternalImage {
6261 let (ref captured_data, ref uv) = self.data[&(key, channel_index)];
6262 ExternalImage {
6263 uv: *uv,
6264 source: match *captured_data {
6265 CapturedExternalImageData::NativeTexture(tid) => ExternalImageSource::NativeTexture(tid),
6266 CapturedExternalImageData::Buffer(ref arc) => ExternalImageSource::RawData(&*arc),
6267 }
6268 }
6269 }
6270 fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
6271}
6272
6273#[derive(Default)]
6274pub struct PipelineInfo {
6275 pub epochs: FastHashMap<(PipelineId, DocumentId), Epoch>,
6276 pub removed_pipelines: Vec<(PipelineId, DocumentId)>,
6277}
6278
6279impl Renderer {
6280 #[cfg(feature = "capture")]
6281 fn save_texture(
6282 texture: &Texture, category: Option<TextureCacheCategory>, name: &str, root: &PathBuf, device: &mut Device
6283 ) -> PlainTexture {
6284 use std::fs;
6285 use std::io::Write;
6286
6287 let short_path = format!("textures/{}.raw", name);
6288
6289 let bytes_per_pixel = texture.get_format().bytes_per_pixel();
6290 let read_format = texture.get_format();
6291 let rect_size = texture.get_dimensions();
6292
6293 let mut file = fs::File::create(root.join(&short_path))
6294 .expect(&format!("Unable to create {}", short_path));
6295 let bytes_per_texture = (rect_size.width * rect_size.height * bytes_per_pixel) as usize;
6296 let mut data = vec![0; bytes_per_texture];
6297
6298 let rect = device_size_as_framebuffer_size(rect_size).into();
6302
6303 device.attach_read_texture(texture);
6304 #[cfg(feature = "png")]
6305 {
6306 let mut png_data;
6307 let (data_ref, format) = match texture.get_format() {
6308 ImageFormat::RGBAF32 => {
6309 png_data = vec![0; (rect_size.width * rect_size.height * 4) as usize];
6310 device.read_pixels_into(rect, ImageFormat::RGBA8, &mut png_data);
6311 (&png_data, ImageFormat::RGBA8)
6312 }
6313 fm => (&data, fm),
6314 };
6315 CaptureConfig::save_png(
6316 root.join(format!("textures/{}-{}.png", name, 0)),
6317 rect_size, format,
6318 None,
6319 data_ref,
6320 );
6321 }
6322 device.read_pixels_into(rect, read_format, &mut data);
6323 file.write_all(&data)
6324 .unwrap();
6325
6326 PlainTexture {
6327 data: short_path,
6328 size: rect_size,
6329 format: texture.get_format(),
6330 filter: texture.get_filter(),
6331 has_depth: texture.supports_depth(),
6332 category,
6333 }
6334 }
6335
6336 #[cfg(feature = "replay")]
6337 fn load_texture(
6338 target: ImageBufferKind,
6339 plain: &PlainTexture,
6340 rt_info: Option<RenderTargetInfo>,
6341 root: &PathBuf,
6342 device: &mut Device
6343 ) -> (Texture, Vec<u8>)
6344 {
6345 use std::fs::File;
6346 use std::io::Read;
6347
6348 let mut texels = Vec::new();
6349 File::open(root.join(&plain.data))
6350 .expect(&format!("Unable to open texture at {}", plain.data))
6351 .read_to_end(&mut texels)
6352 .unwrap();
6353
6354 let texture = device.create_texture(
6355 target,
6356 plain.format,
6357 plain.size.width,
6358 plain.size.height,
6359 plain.filter,
6360 rt_info,
6361 );
6362 device.upload_texture_immediate(&texture, &texels);
6363
6364 (texture, texels)
6365 }
6366
6367 #[cfg(feature = "capture")]
6368 fn save_capture(
6369 &mut self,
6370 config: CaptureConfig,
6371 deferred_images: Vec<ExternalCaptureImage>,
6372 ) {
6373 use std::fs;
6374 use std::io::Write;
6375 use api::ExternalImageData;
6376 use crate::render_api::CaptureBits;
6377
6378 let root = config.resource_root();
6379
6380 self.device.begin_frame();
6381 let _gm = self.gpu_profiler.start_marker("read GPU data");
6382 self.device.bind_read_target_impl(self.read_fbo, DeviceIntPoint::zero());
6383
6384 if config.bits.contains(CaptureBits::EXTERNAL_RESOURCES) && !deferred_images.is_empty() {
6385 info!("saving external images");
6386 let mut arc_map = FastHashMap::<*const u8, String>::default();
6387 let mut tex_map = FastHashMap::<u32, String>::default();
6388 let handler = self.external_image_handler
6389 .as_mut()
6390 .expect("Unable to lock the external image handler!");
6391 for def in &deferred_images {
6392 info!("\t{}", def.short_path);
6393 let ExternalImageData { id, channel_index, image_type, .. } = def.external;
6394 let ext_image = handler.lock(id, channel_index, false);
6396 let (data, short_path) = match ext_image.source {
6397 ExternalImageSource::RawData(data) => {
6398 let arc_id = arc_map.len() + 1;
6399 match arc_map.entry(data.as_ptr()) {
6400 Entry::Occupied(e) => {
6401 (None, e.get().clone())
6402 }
6403 Entry::Vacant(e) => {
6404 let short_path = format!("externals/d{}.raw", arc_id);
6405 (Some(data.to_vec()), e.insert(short_path).clone())
6406 }
6407 }
6408 }
6409 ExternalImageSource::NativeTexture(gl_id) => {
6410 let tex_id = tex_map.len() + 1;
6411 match tex_map.entry(gl_id) {
6412 Entry::Occupied(e) => {
6413 (None, e.get().clone())
6414 }
6415 Entry::Vacant(e) => {
6416 let target = match image_type {
6417 ExternalImageType::TextureHandle(target) => target,
6418 ExternalImageType::Buffer => unreachable!(),
6419 };
6420 info!("\t\tnative texture of target {:?}", target);
6421 self.device.attach_read_texture_external(gl_id, target);
6422 let data = self.device.read_pixels(&def.descriptor);
6423 let short_path = format!("externals/t{}.raw", tex_id);
6424 (Some(data), e.insert(short_path).clone())
6425 }
6426 }
6427 }
6428 ExternalImageSource::Invalid => {
6429 info!("\t\tinvalid source!");
6430 (None, String::new())
6431 }
6432 };
6433 if let Some(bytes) = data {
6434 fs::File::create(root.join(&short_path))
6435 .expect(&format!("Unable to create {}", short_path))
6436 .write_all(&bytes)
6437 .unwrap();
6438 #[cfg(feature = "png")]
6439 CaptureConfig::save_png(
6440 root.join(&short_path).with_extension("png"),
6441 def.descriptor.size,
6442 def.descriptor.format,
6443 def.descriptor.stride,
6444 &bytes,
6445 );
6446 }
6447 let plain = PlainExternalImage {
6448 data: short_path,
6449 external: def.external,
6450 uv: ext_image.uv,
6451 };
6452 config.serialize_for_resource(&plain, &def.short_path);
6453 }
6454 for def in &deferred_images {
6455 handler.unlock(def.external.id, def.external.channel_index);
6456 }
6457 let plain_external = PlainExternalResources {
6458 images: deferred_images,
6459 };
6460 config.serialize_for_resource(&plain_external, "external_resources");
6461 }
6462
6463 if config.bits.contains(CaptureBits::FRAME) {
6464 let path_textures = root.join("textures");
6465 if !path_textures.is_dir() {
6466 fs::create_dir(&path_textures).unwrap();
6467 }
6468
6469 info!("saving GPU cache");
6470 self.update_gpu_cache(); let mut plain_self = PlainRenderer {
6472 device_size: self.device_size,
6473 gpu_cache: Self::save_texture(
6474 self.gpu_cache_texture.get_texture(),
6475 None, "gpu", &root, &mut self.device,
6476 ),
6477 gpu_cache_frame_id: self.gpu_cache_frame_id,
6478 textures: FastHashMap::default(),
6479 };
6480
6481 info!("saving cached textures");
6482 for (id, item) in &self.texture_resolver.texture_cache_map {
6483 let file_name = format!("cache-{}", plain_self.textures.len() + 1);
6484 info!("\t{}", file_name);
6485 let plain = Self::save_texture(&item.texture, Some(item.category), &file_name, &root, &mut self.device);
6486 plain_self.textures.insert(*id, plain);
6487 }
6488
6489 config.serialize_for_resource(&plain_self, "renderer");
6490 }
6491
6492 self.device.reset_read_target();
6493 self.device.end_frame();
6494
6495 let mut stats_file = fs::File::create(config.root.join("profiler-stats.txt"))
6496 .expect(&format!("Unable to create profiler-stats.txt"));
6497 if self.debug_flags.intersects(DebugFlags::PROFILER_DBG | DebugFlags::PROFILER_CAPTURE) {
6498 self.profiler.dump_stats(&mut stats_file).unwrap();
6499 } else {
6500 writeln!(stats_file, "Turn on PROFILER_DBG or PROFILER_CAPTURE to get stats here!").unwrap();
6501 }
6502
6503 info!("done.");
6504 }
6505
6506 #[cfg(feature = "replay")]
6507 fn load_capture(
6508 &mut self,
6509 config: CaptureConfig,
6510 plain_externals: Vec<PlainExternalImage>,
6511 ) {
6512 use std::{fs::File, io::Read};
6513
6514 info!("loading external buffer-backed images");
6515 assert!(self.texture_resolver.external_images.is_empty());
6516 let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
6517 let mut image_handler = DummyExternalImageHandler {
6518 data: FastHashMap::default(),
6519 };
6520
6521 let root = config.resource_root();
6522
6523 for plain_ext in plain_externals {
6528 let data = match raw_map.entry(plain_ext.data) {
6529 Entry::Occupied(e) => e.get().clone(),
6530 Entry::Vacant(e) => {
6531 let mut buffer = Vec::new();
6532 File::open(root.join(e.key()))
6533 .expect(&format!("Unable to open {}", e.key()))
6534 .read_to_end(&mut buffer)
6535 .unwrap();
6536 e.insert(Arc::new(buffer)).clone()
6537 }
6538 };
6539 let ext = plain_ext.external;
6540 let value = (CapturedExternalImageData::Buffer(data), plain_ext.uv);
6541 image_handler.data.insert((ext.id, ext.channel_index), value);
6542 }
6543
6544 if let Some(external_resources) = config.deserialize_for_resource::<PlainExternalResources, _>("external_resources") {
6545 info!("loading external texture-backed images");
6546 let mut native_map = FastHashMap::<String, gl::GLuint>::default();
6547 for ExternalCaptureImage { short_path, external, descriptor } in external_resources.images {
6548 let target = match external.image_type {
6549 ExternalImageType::TextureHandle(target) => target,
6550 ExternalImageType::Buffer => continue,
6551 };
6552 let plain_ext = config.deserialize_for_resource::<PlainExternalImage, _>(&short_path)
6553 .expect(&format!("Unable to read {}.ron", short_path));
6554 let key = (external.id, external.channel_index);
6555
6556 let tid = match native_map.entry(plain_ext.data) {
6557 Entry::Occupied(e) => e.get().clone(),
6558 Entry::Vacant(e) => {
6559 let plain_tex = PlainTexture {
6560 data: e.key().clone(),
6561 size: descriptor.size,
6562 format: descriptor.format,
6563 filter: TextureFilter::Linear,
6564 has_depth: false,
6565 category: None,
6566 };
6567 let t = Self::load_texture(
6568 target,
6569 &plain_tex,
6570 None,
6571 &root,
6572 &mut self.device
6573 );
6574 let extex = t.0.into_external();
6575 self.owned_external_images.insert(key, extex.clone());
6576 e.insert(extex.internal_id()).clone()
6577 }
6578 };
6579
6580 let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv);
6581 image_handler.data.insert(key, value);
6582 }
6583 }
6584
6585 self.device.begin_frame();
6586 self.gpu_cache_texture.remove_texture(&mut self.device);
6587
6588 if let Some(renderer) = config.deserialize_for_resource::<PlainRenderer, _>("renderer") {
6589 info!("loading cached textures");
6590 self.device_size = renderer.device_size;
6591
6592 for (_id, item) in self.texture_resolver.texture_cache_map.drain() {
6593 self.device.delete_texture(item.texture);
6594 }
6595 for (id, texture) in renderer.textures {
6596 info!("\t{}", texture.data);
6597 let target = ImageBufferKind::Texture2D;
6598 let t = Self::load_texture(
6599 target,
6600 &texture,
6601 Some(RenderTargetInfo { has_depth: texture.has_depth }),
6602 &root,
6603 &mut self.device
6604 );
6605 self.texture_resolver.texture_cache_map.insert(id, CacheTexture {
6606 texture: t.0,
6607 category: texture.category.unwrap_or(TextureCacheCategory::Standalone),
6608 });
6609 }
6610
6611 info!("loading gpu cache");
6612 let (t, gpu_cache_data) = Self::load_texture(
6613 ImageBufferKind::Texture2D,
6614 &renderer.gpu_cache,
6615 Some(RenderTargetInfo { has_depth: false }),
6616 &root,
6617 &mut self.device,
6618 );
6619 self.gpu_cache_texture.load_from_data(t, gpu_cache_data);
6620 self.gpu_cache_frame_id = renderer.gpu_cache_frame_id;
6621 } else {
6622 info!("loading cached textures");
6623 self.device.begin_frame();
6624 for (_id, item) in self.texture_resolver.texture_cache_map.drain() {
6625 self.device.delete_texture(item.texture);
6626 }
6627 }
6628 self.device.end_frame();
6629
6630 self.external_image_handler = Some(Box::new(image_handler) as Box<_>);
6631 info!("done.");
6632 }
6633}
6634
6635#[derive(Clone, Copy, PartialEq)]
6636enum FramebufferKind {
6637 Main,
6638 Other,
6639}
6640
6641fn should_skip_batch(kind: &BatchKind, flags: DebugFlags) -> bool {
6642 match kind {
6643 BatchKind::TextRun(_) => {
6644 flags.contains(DebugFlags::DISABLE_TEXT_PRIMS)
6645 }
6646 BatchKind::Brush(BrushBatchKind::LinearGradient) => {
6647 flags.contains(DebugFlags::DISABLE_GRADIENT_PRIMS)
6648 }
6649 _ => false,
6650 }
6651}
6652
6653impl CompositeState {
6654 fn composite_native(
6657 &self,
6658 clear_color: ColorF,
6659 dirty_rects: &[DeviceIntRect],
6660 device: &mut Device,
6661 compositor: &mut dyn Compositor,
6662 ) {
6663 for surface in &self.descriptor.surfaces {
6667 compositor.add_surface(
6668 device,
6669 surface.surface_id.expect("bug: no native surface allocated"),
6670 surface.transform,
6671 surface.clip_rect.to_i32(),
6672 surface.image_rendering,
6673 surface.rounded_clip_rect.to_i32(),
6674 surface.rounded_clip_radii,
6675 );
6676 }
6677 compositor.start_compositing(device, clear_color, dirty_rects, &[]);
6678 }
6679}
6680
6681mod tests {
6682 #[test]
6683 fn test_buffer_damage_tracker() {
6684 use super::BufferDamageTracker;
6685 use api::units::{DevicePoint, DeviceRect, DeviceSize};
6686
6687 let mut tracker = BufferDamageTracker::default();
6688 assert_eq!(tracker.get_damage_rect(0), None);
6689 assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
6690 assert_eq!(tracker.get_damage_rect(2), Some(DeviceRect::zero()));
6691 assert_eq!(tracker.get_damage_rect(3), Some(DeviceRect::zero()));
6692
6693 let damage1 = DeviceRect::from_origin_and_size(DevicePoint::new(10.0, 10.0), DeviceSize::new(10.0, 10.0));
6694 let damage2 = DeviceRect::from_origin_and_size(DevicePoint::new(20.0, 20.0), DeviceSize::new(10.0, 10.0));
6695 let combined = damage1.union(&damage2);
6696
6697 tracker.push_dirty_rect(&damage1);
6698 assert_eq!(tracker.get_damage_rect(0), None);
6699 assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
6700 assert_eq!(tracker.get_damage_rect(2), Some(damage1));
6701 assert_eq!(tracker.get_damage_rect(3), Some(damage1));
6702
6703 tracker.push_dirty_rect(&damage2);
6704 assert_eq!(tracker.get_damage_rect(0), None);
6705 assert_eq!(tracker.get_damage_rect(1), Some(DeviceRect::zero()));
6706 assert_eq!(tracker.get_damage_rect(2), Some(damage2));
6707 assert_eq!(tracker.get_damage_rect(3), Some(combined));
6708 }
6709}