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