1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 //! The high-level module responsible for interfacing with the GPU.
6 //!
7 //! Much of WebRender's design is driven by separating work into different
8 //! threads. To avoid the complexities of multi-threaded GPU access, we restrict
9 //! all communication with the GPU to one thread, the render thread. But since
10 //! issuing GPU commands is often a bottleneck, we move everything else (i.e.
11 //! the computation of what commands to issue) to another thread, the
12 //! RenderBackend thread. The RenderBackend, in turn, may delegate work to other
13 //! thread (like the SceneBuilder threads or Rayon workers), but the
14 //! Render-vs-RenderBackend distinction is the most important.
15 //!
16 //! The consumer is responsible for initializing the render thread before
17 //! calling into WebRender, which means that this module also serves as the
18 //! initial entry point into WebRender, and is responsible for spawning the
19 //! various other threads discussed above. That said, WebRender initialization
20 //! returns both the `Renderer` instance as well as a channel for communicating
21 //! directly with the `RenderBackend`. Aside from a few high-level operations
22 //! like 'render now', most of interesting commands from the consumer go over
23 //! that channel and operate on the `RenderBackend`.
24
25 use api::{BlobImageHandler, ColorF, ColorU, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
26 use api::{DocumentId, Epoch, ExternalImageId};
27 use api::{ExternalImageType, FontRenderMode, FrameMsg, ImageFormat, PipelineId};
28 use api::{ImageRendering, Checkpoint, NotificationRequest};
29 use api::{MemoryReport, VoidPtrToSizeFn};
30 use api::{RenderApiSender, RenderNotifier, TexelRect, TextureTarget};
31 use api::{channel};
32 use api::DebugCommand;
33 pub use api::DebugFlags;
34 use api::channel::PayloadReceiverHelperMethods;
35 use batch::{BatchKind, BatchTextures, BrushBatchKind};
36 #[cfg(any(feature = "capture", feature = "replay"))]
37 use capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
38 use debug_colors;
39 use debug_render::{DebugItem, DebugRenderer};
40 use device::{DepthFunction, Device, GpuFrameId, Program, UploadMethod, Texture, PBO};
41 use device::{DrawTarget, ExternalTexture, FBOId, ReadTarget, TextureSlot};
42 use device::{ShaderError, TextureFilter, TextureFlags,
43 VertexUsageHint, VAO, VBO, CustomVAO};
44 use device::{ProgramCache, ReadPixelsFormat};
45 use device::query::GpuTimer;
46 use euclid::rect;
47 use euclid::Transform3D;
48 use frame_builder::{ChasePrimitive, FrameBuilderConfig};
49 use gleam::gl;
50 use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
51 use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
52 use gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
53 #[cfg(feature = "pathfinder")]
54 use gpu_glyph_renderer::GpuGlyphRenderer;
55 use gpu_types::ScalingInstance;
56 use internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
57 use internal_types::{CacheTextureId, DebugOutput, FastHashMap, LayerIndex, RenderedDocument, ResultMsg};
58 use internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource};
59 use internal_types::{RenderTargetInfo, SavedTargetIndex};
60 use malloc_size_of::MallocSizeOfOps;
61 use picture::{RecordedDirtyRegion, TileCache};
62 use prim_store::DeferredResolve;
63 use profiler::{BackendProfileCounters, FrameProfileCounters, TimeProfileCounter,
64 GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
65 use profiler::{Profiler, ChangeIndicator};
66 use device::query::GpuProfiler;
67 use rayon::{ThreadPool, ThreadPoolBuilder};
68 use record::ApiRecordingReceiver;
69 use render_backend::{FrameId, RenderBackend};
70 use scene_builder::{SceneBuilder, LowPrioritySceneBuilder};
71 use shade::{Shaders, WrShaders};
72 use smallvec::SmallVec;
73 use render_task::{RenderTask, RenderTaskKind, RenderTaskTree};
74 use resource_cache::ResourceCache;
75 use util::drain_filter;
76
77 use std;
78 use std::cmp;
79 use std::collections::VecDeque;
80 use std::collections::hash_map::Entry;
81 use std::f32;
82 use std::mem;
83 use std::os::raw::c_void;
84 use std::path::PathBuf;
85 use std::rc::Rc;
86 use std::sync::Arc;
87 use std::sync::atomic::{AtomicBool, Ordering};
88 use std::sync::mpsc::{channel, Receiver};
89 use std::thread;
90 use std::cell::RefCell;
91 use texture_cache::TextureCache;
92 use thread_profiler::{register_thread_with_profiler, write_profile};
93 use tiling::{AlphaRenderTarget, ColorRenderTarget};
94 use tiling::{BlitJob, BlitJobSource, RenderPass, RenderPassKind, RenderTargetList};
95 use tiling::{Frame, RenderTarget, RenderTargetKind, TextureCacheRenderTarget};
96 #[cfg(not(feature = "pathfinder"))]
97 use tiling::GlyphJob;
98 use time::precise_time_ns;
99
100 cfg_if! {
101 if #[cfg(feature = "debugger")] {
102 use serde_json;
103 use debug_server::{self, DebugServer};
104 } else {
105 use api::ApiMsg;
106 use api::channel::MsgSender;
107 }
108 }
109
110 /// Is only false if no WR instances have ever been created.
111 static HAS_BEEN_INITIALIZED: AtomicBool = AtomicBool::new(false);
112
113 /// Returns true if a WR instance has ever been initialized in this process.
wr_has_been_initialized() -> bool114 pub fn wr_has_been_initialized() -> bool {
115 HAS_BEEN_INITIALIZED.load(Ordering::SeqCst)
116 }
117
118 pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
119 /// Enabling this toggle would force the GPU cache scattered texture to
120 /// be resized every frame, which enables GPU debuggers to see if this
121 /// is performed correctly.
122 const GPU_CACHE_RESIZE_TEST: bool = false;
123
124 /// Number of GPU blocks per UV rectangle provided for an image.
125 pub const BLOCKS_PER_UV_RECT: usize = 2;
126
127 const GPU_TAG_BRUSH_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
128 label: "B_LinearGradient",
129 color: debug_colors::POWDERBLUE,
130 };
131 const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
132 label: "B_RadialGradient",
133 color: debug_colors::LIGHTPINK,
134 };
135 const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
136 label: "B_YuvImage",
137 color: debug_colors::DARKGREEN,
138 };
139 const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag {
140 label: "B_MixBlend",
141 color: debug_colors::MAGENTA,
142 };
143 const GPU_TAG_BRUSH_BLEND: GpuProfileTag = GpuProfileTag {
144 label: "B_Blend",
145 color: debug_colors::ORANGE,
146 };
147 const GPU_TAG_BRUSH_IMAGE: GpuProfileTag = GpuProfileTag {
148 label: "B_Image",
149 color: debug_colors::SPRINGGREEN,
150 };
151 const GPU_TAG_BRUSH_SOLID: GpuProfileTag = GpuProfileTag {
152 label: "B_Solid",
153 color: debug_colors::RED,
154 };
155 const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
156 label: "C_Clip",
157 color: debug_colors::PURPLE,
158 };
159 const GPU_TAG_CACHE_BORDER: GpuProfileTag = GpuProfileTag {
160 label: "C_Border",
161 color: debug_colors::CORNSILK,
162 };
163 const GPU_TAG_CACHE_LINE_DECORATION: GpuProfileTag = GpuProfileTag {
164 label: "C_LineDecoration",
165 color: debug_colors::YELLOWGREEN,
166 };
167 const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
168 label: "target init",
169 color: debug_colors::SLATEGREY,
170 };
171 const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag {
172 label: "data init",
173 color: debug_colors::LIGHTGREY,
174 };
175 const GPU_TAG_PRIM_SPLIT_COMPOSITE: GpuProfileTag = GpuProfileTag {
176 label: "SplitComposite",
177 color: debug_colors::DARKBLUE,
178 };
179 const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag {
180 label: "TextRun",
181 color: debug_colors::BLUE,
182 };
183 const GPU_TAG_BLUR: GpuProfileTag = GpuProfileTag {
184 label: "Blur",
185 color: debug_colors::VIOLET,
186 };
187 const GPU_TAG_BLIT: GpuProfileTag = GpuProfileTag {
188 label: "Blit",
189 color: debug_colors::LIME,
190 };
191 const GPU_TAG_SCALE: GpuProfileTag = GpuProfileTag {
192 label: "Scale",
193 color: debug_colors::GHOSTWHITE,
194 };
195
196 const GPU_SAMPLER_TAG_ALPHA: GpuProfileTag = GpuProfileTag {
197 label: "Alpha Targets",
198 color: debug_colors::BLACK,
199 };
200 const GPU_SAMPLER_TAG_OPAQUE: GpuProfileTag = GpuProfileTag {
201 label: "Opaque Pass",
202 color: debug_colors::BLACK,
203 };
204 const GPU_SAMPLER_TAG_TRANSPARENT: GpuProfileTag = GpuProfileTag {
205 label: "Transparent Pass",
206 color: debug_colors::BLACK,
207 };
208
209 /// The clear color used for the texture cache when the debug display is enabled.
210 /// We use a shade of blue so that we can still identify completely blue items in
211 /// the texture cache.
212 const TEXTURE_CACHE_DBG_CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.8, 1.0];
213
214 impl BatchKind {
215 #[cfg(feature = "debugger")]
debug_name(&self) -> &'static str216 fn debug_name(&self) -> &'static str {
217 match *self {
218 BatchKind::SplitComposite => "SplitComposite",
219 BatchKind::Brush(kind) => {
220 match kind {
221 BrushBatchKind::Solid => "Brush (Solid)",
222 BrushBatchKind::Image(..) => "Brush (Image)",
223 BrushBatchKind::Blend => "Brush (Blend)",
224 BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
225 BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
226 BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
227 BrushBatchKind::LinearGradient => "Brush (LinearGradient)",
228 }
229 }
230 BatchKind::TextRun(_) => "TextRun",
231 }
232 }
233
sampler_tag(&self) -> GpuProfileTag234 fn sampler_tag(&self) -> GpuProfileTag {
235 match *self {
236 BatchKind::SplitComposite => GPU_TAG_PRIM_SPLIT_COMPOSITE,
237 BatchKind::Brush(kind) => {
238 match kind {
239 BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
240 BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
241 BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
242 BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
243 BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
244 BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT,
245 BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT,
246 }
247 }
248 BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN,
249 }
250 }
251 }
252
flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool>253 fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
254 if before & select != after & select {
255 Some(after.contains(select))
256 } else {
257 None
258 }
259 }
260
261 #[repr(C)]
262 #[derive(Copy, Clone, Debug)]
263 pub enum ShaderColorMode {
264 FromRenderPassMode = 0,
265 Alpha = 1,
266 SubpixelConstantTextColor = 2,
267 SubpixelWithBgColorPass0 = 3,
268 SubpixelWithBgColorPass1 = 4,
269 SubpixelWithBgColorPass2 = 5,
270 SubpixelDualSource = 6,
271 Bitmap = 7,
272 ColorBitmap = 8,
273 Image = 9,
274 }
275
276 impl From<GlyphFormat> for ShaderColorMode {
from(format: GlyphFormat) -> ShaderColorMode277 fn from(format: GlyphFormat) -> ShaderColorMode {
278 match format {
279 GlyphFormat::Alpha | GlyphFormat::TransformedAlpha => ShaderColorMode::Alpha,
280 GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => {
281 panic!("Subpixel glyph formats must be handled separately.");
282 }
283 GlyphFormat::Bitmap => ShaderColorMode::Bitmap,
284 GlyphFormat::ColorBitmap => ShaderColorMode::ColorBitmap,
285 }
286 }
287 }
288
289 /// Enumeration of the texture samplers used across the various WebRender shaders.
290 ///
291 /// Each variant corresponds to a uniform declared in shader source. We only bind
292 /// the variants we need for a given shader, so not every variant is bound for every
293 /// batch.
294 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
295 pub(crate) enum TextureSampler {
296 Color0,
297 Color1,
298 Color2,
299 PrevPassAlpha,
300 PrevPassColor,
301 GpuCache,
302 TransformPalette,
303 RenderTasks,
304 Dither,
305 PrimitiveHeadersF,
306 PrimitiveHeadersI,
307 }
308
309 impl TextureSampler {
color(n: usize) -> TextureSampler310 pub(crate) fn color(n: usize) -> TextureSampler {
311 match n {
312 0 => TextureSampler::Color0,
313 1 => TextureSampler::Color1,
314 2 => TextureSampler::Color2,
315 _ => {
316 panic!("There are only 3 color samplers.");
317 }
318 }
319 }
320 }
321
322 impl Into<TextureSlot> for TextureSampler {
into(self) -> TextureSlot323 fn into(self) -> TextureSlot {
324 match self {
325 TextureSampler::Color0 => TextureSlot(0),
326 TextureSampler::Color1 => TextureSlot(1),
327 TextureSampler::Color2 => TextureSlot(2),
328 TextureSampler::PrevPassAlpha => TextureSlot(3),
329 TextureSampler::PrevPassColor => TextureSlot(4),
330 TextureSampler::GpuCache => TextureSlot(5),
331 TextureSampler::TransformPalette => TextureSlot(6),
332 TextureSampler::RenderTasks => TextureSlot(7),
333 TextureSampler::Dither => TextureSlot(8),
334 TextureSampler::PrimitiveHeadersF => TextureSlot(9),
335 TextureSampler::PrimitiveHeadersI => TextureSlot(10),
336 }
337 }
338 }
339
340 #[derive(Debug, Clone, Copy)]
341 #[repr(C)]
342 pub struct PackedVertex {
343 pub pos: [f32; 2],
344 }
345
346 pub(crate) mod desc {
347 use device::{VertexAttribute, VertexAttributeKind, VertexDescriptor};
348
349 pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor {
350 vertex_attributes: &[
351 VertexAttribute {
352 name: "aPosition",
353 count: 2,
354 kind: VertexAttributeKind::F32,
355 },
356 ],
357 instance_attributes: &[
358 VertexAttribute {
359 name: "aData",
360 count: 4,
361 kind: VertexAttributeKind::I32,
362 },
363 ],
364 };
365
366 pub const BLUR: VertexDescriptor = VertexDescriptor {
367 vertex_attributes: &[
368 VertexAttribute {
369 name: "aPosition",
370 count: 2,
371 kind: VertexAttributeKind::F32,
372 },
373 ],
374 instance_attributes: &[
375 VertexAttribute {
376 name: "aBlurRenderTaskAddress",
377 count: 1,
378 kind: VertexAttributeKind::I32,
379 },
380 VertexAttribute {
381 name: "aBlurSourceTaskAddress",
382 count: 1,
383 kind: VertexAttributeKind::I32,
384 },
385 VertexAttribute {
386 name: "aBlurDirection",
387 count: 1,
388 kind: VertexAttributeKind::I32,
389 },
390 ],
391 };
392
393 pub const LINE: VertexDescriptor = VertexDescriptor {
394 vertex_attributes: &[
395 VertexAttribute {
396 name: "aPosition",
397 count: 2,
398 kind: VertexAttributeKind::F32,
399 },
400 ],
401 instance_attributes: &[
402 VertexAttribute {
403 name: "aTaskRect",
404 count: 4,
405 kind: VertexAttributeKind::F32,
406 },
407 VertexAttribute {
408 name: "aLocalSize",
409 count: 2,
410 kind: VertexAttributeKind::F32,
411 },
412 VertexAttribute {
413 name: "aWavyLineThickness",
414 count: 1,
415 kind: VertexAttributeKind::F32,
416 },
417 VertexAttribute {
418 name: "aStyle",
419 count: 1,
420 kind: VertexAttributeKind::I32,
421 },
422 VertexAttribute {
423 name: "aOrientation",
424 count: 1,
425 kind: VertexAttributeKind::I32,
426 },
427 ],
428 };
429
430 pub const BORDER: VertexDescriptor = VertexDescriptor {
431 vertex_attributes: &[
432 VertexAttribute {
433 name: "aPosition",
434 count: 2,
435 kind: VertexAttributeKind::F32,
436 },
437 ],
438 instance_attributes: &[
439 VertexAttribute {
440 name: "aTaskOrigin",
441 count: 2,
442 kind: VertexAttributeKind::F32,
443 },
444 VertexAttribute {
445 name: "aRect",
446 count: 4,
447 kind: VertexAttributeKind::F32,
448 },
449 VertexAttribute {
450 name: "aColor0",
451 count: 4,
452 kind: VertexAttributeKind::F32,
453 },
454 VertexAttribute {
455 name: "aColor1",
456 count: 4,
457 kind: VertexAttributeKind::F32,
458 },
459 VertexAttribute {
460 name: "aFlags",
461 count: 1,
462 kind: VertexAttributeKind::I32,
463 },
464 VertexAttribute {
465 name: "aWidths",
466 count: 2,
467 kind: VertexAttributeKind::F32,
468 },
469 VertexAttribute {
470 name: "aRadii",
471 count: 2,
472 kind: VertexAttributeKind::F32,
473 },
474 VertexAttribute {
475 name: "aClipParams1",
476 count: 4,
477 kind: VertexAttributeKind::F32,
478 },
479 VertexAttribute {
480 name: "aClipParams2",
481 count: 4,
482 kind: VertexAttributeKind::F32,
483 },
484 ],
485 };
486
487 pub const SCALE: VertexDescriptor = VertexDescriptor {
488 vertex_attributes: &[
489 VertexAttribute {
490 name: "aPosition",
491 count: 2,
492 kind: VertexAttributeKind::F32,
493 },
494 ],
495 instance_attributes: &[
496 VertexAttribute {
497 name: "aScaleRenderTaskAddress",
498 count: 1,
499 kind: VertexAttributeKind::I32,
500 },
501 VertexAttribute {
502 name: "aScaleSourceTaskAddress",
503 count: 1,
504 kind: VertexAttributeKind::I32,
505 },
506 ],
507 };
508
509 pub const CLIP: VertexDescriptor = VertexDescriptor {
510 vertex_attributes: &[
511 VertexAttribute {
512 name: "aPosition",
513 count: 2,
514 kind: VertexAttributeKind::F32,
515 },
516 ],
517 instance_attributes: &[
518 VertexAttribute {
519 name: "aClipRenderTaskAddress",
520 count: 1,
521 kind: VertexAttributeKind::I32,
522 },
523 VertexAttribute {
524 name: "aClipTransformId",
525 count: 1,
526 kind: VertexAttributeKind::I32,
527 },
528 VertexAttribute {
529 name: "aPrimTransformId",
530 count: 1,
531 kind: VertexAttributeKind::I32,
532 },
533 VertexAttribute {
534 name: "aClipDataResourceAddress",
535 count: 4,
536 kind: VertexAttributeKind::U16,
537 },
538 VertexAttribute {
539 name: "aClipLocalPos",
540 count: 2,
541 kind: VertexAttributeKind::F32,
542 },
543 VertexAttribute {
544 name: "aClipTileRect",
545 count: 4,
546 kind: VertexAttributeKind::F32,
547 },
548 VertexAttribute {
549 name: "aClipDeviceArea",
550 count: 4,
551 kind: VertexAttributeKind::F32,
552 },
553 VertexAttribute {
554 name: "aClipSnapOffsets",
555 count: 4,
556 kind: VertexAttributeKind::F32,
557 }
558 ],
559 };
560
561 pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor {
562 vertex_attributes: &[
563 VertexAttribute {
564 name: "aPosition",
565 count: 2,
566 kind: VertexAttributeKind::U16Norm,
567 },
568 VertexAttribute {
569 name: "aValue",
570 count: 4,
571 kind: VertexAttributeKind::F32,
572 },
573 ],
574 instance_attributes: &[],
575 };
576
577 pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor {
578 vertex_attributes: &[
579 VertexAttribute {
580 name: "aPosition",
581 count: 2,
582 kind: VertexAttributeKind::F32,
583 },
584 ],
585 instance_attributes: &[
586 VertexAttribute {
587 name: "aFromPosition",
588 count: 2,
589 kind: VertexAttributeKind::F32,
590 },
591 VertexAttribute {
592 name: "aCtrlPosition",
593 count: 2,
594 kind: VertexAttributeKind::F32,
595 },
596 VertexAttribute {
597 name: "aToPosition",
598 count: 2,
599 kind: VertexAttributeKind::F32,
600 },
601 VertexAttribute {
602 name: "aFromNormal",
603 count: 2,
604 kind: VertexAttributeKind::F32,
605 },
606 VertexAttribute {
607 name: "aCtrlNormal",
608 count: 2,
609 kind: VertexAttributeKind::F32,
610 },
611 VertexAttribute {
612 name: "aToNormal",
613 count: 2,
614 kind: VertexAttributeKind::F32,
615 },
616 VertexAttribute {
617 name: "aPathID",
618 count: 1,
619 kind: VertexAttributeKind::U16,
620 },
621 VertexAttribute {
622 name: "aPad",
623 count: 1,
624 kind: VertexAttributeKind::U16,
625 },
626 ],
627 };
628
629 pub const VECTOR_COVER: VertexDescriptor = VertexDescriptor {
630 vertex_attributes: &[
631 VertexAttribute {
632 name: "aPosition",
633 count: 2,
634 kind: VertexAttributeKind::F32,
635 },
636 ],
637 instance_attributes: &[
638 VertexAttribute {
639 name: "aTargetRect",
640 count: 4,
641 kind: VertexAttributeKind::I32,
642 },
643 VertexAttribute {
644 name: "aStencilOrigin",
645 count: 2,
646 kind: VertexAttributeKind::I32,
647 },
648 VertexAttribute {
649 name: "aSubpixel",
650 count: 1,
651 kind: VertexAttributeKind::U16,
652 },
653 VertexAttribute {
654 name: "aPad",
655 count: 1,
656 kind: VertexAttributeKind::U16,
657 },
658 ],
659 };
660 }
661
662 #[derive(Debug, Copy, Clone)]
663 pub(crate) enum VertexArrayKind {
664 Primitive,
665 Blur,
666 Clip,
667 VectorStencil,
668 VectorCover,
669 Border,
670 Scale,
671 LineDecoration,
672 }
673
674 #[derive(Clone, Debug, PartialEq)]
675 pub enum GraphicsApi {
676 OpenGL,
677 }
678
679 #[derive(Clone, Debug)]
680 pub struct GraphicsApiInfo {
681 pub kind: GraphicsApi,
682 pub renderer: String,
683 pub version: String,
684 }
685
686 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
687 #[cfg_attr(feature = "capture", derive(Serialize))]
688 #[cfg_attr(feature = "replay", derive(Deserialize))]
689 pub enum ImageBufferKind {
690 Texture2D = 0,
691 TextureRect = 1,
692 TextureExternal = 2,
693 Texture2DArray = 3,
694 }
695
696 //TODO: those types are the same, so let's merge them
697 impl From<TextureTarget> for ImageBufferKind {
from(target: TextureTarget) -> Self698 fn from(target: TextureTarget) -> Self {
699 match target {
700 TextureTarget::Default => ImageBufferKind::Texture2D,
701 TextureTarget::Rect => ImageBufferKind::TextureRect,
702 TextureTarget::Array => ImageBufferKind::Texture2DArray,
703 TextureTarget::External => ImageBufferKind::TextureExternal,
704 }
705 }
706 }
707
708 #[derive(Debug, Copy, Clone)]
709 pub enum RendererKind {
710 Native,
711 OSMesa,
712 }
713
714 #[derive(Debug)]
715 pub struct GpuProfile {
716 pub frame_id: GpuFrameId,
717 pub paint_time_ns: u64,
718 }
719
720 impl GpuProfile {
new<T>(frame_id: GpuFrameId, timers: &[GpuTimer<T>]) -> GpuProfile721 fn new<T>(frame_id: GpuFrameId, timers: &[GpuTimer<T>]) -> GpuProfile {
722 let mut paint_time_ns = 0;
723 for timer in timers {
724 paint_time_ns += timer.time_ns;
725 }
726 GpuProfile {
727 frame_id,
728 paint_time_ns,
729 }
730 }
731 }
732
733 #[derive(Debug)]
734 pub struct CpuProfile {
735 pub frame_id: GpuFrameId,
736 pub backend_time_ns: u64,
737 pub composite_time_ns: u64,
738 pub draw_calls: usize,
739 }
740
741 impl CpuProfile {
new( frame_id: GpuFrameId, backend_time_ns: u64, composite_time_ns: u64, draw_calls: usize, ) -> CpuProfile742 fn new(
743 frame_id: GpuFrameId,
744 backend_time_ns: u64,
745 composite_time_ns: u64,
746 draw_calls: usize,
747 ) -> CpuProfile {
748 CpuProfile {
749 frame_id,
750 backend_time_ns,
751 composite_time_ns,
752 draw_calls,
753 }
754 }
755 }
756
757 #[cfg(not(feature = "pathfinder"))]
758 pub struct GpuGlyphRenderer;
759
760 #[cfg(not(feature = "pathfinder"))]
761 impl GpuGlyphRenderer {
new(_: &mut Device, _: &VAO, _: ShaderPrecacheFlags) -> Result<GpuGlyphRenderer, RendererError>762 fn new(_: &mut Device, _: &VAO, _: ShaderPrecacheFlags) -> Result<GpuGlyphRenderer, RendererError> {
763 Ok(GpuGlyphRenderer)
764 }
765 }
766
767 #[cfg(not(feature = "pathfinder"))]
768 struct StenciledGlyphPage;
769
770 /// A Texture that has been initialized by the `device` module and is ready to
771 /// be used.
772 struct ActiveTexture {
773 texture: Texture,
774 saved_index: Option<SavedTargetIndex>,
775 }
776
777 /// Helper struct for resolving device Textures for use during rendering passes.
778 ///
779 /// Manages the mapping between the at-a-distance texture handles used by the
780 /// `RenderBackend` (which does not directly interface with the GPU) and actual
781 /// device texture handles.
782 struct TextureResolver {
783 /// A map to resolve texture cache IDs to native textures.
784 texture_cache_map: FastHashMap<CacheTextureId, Texture>,
785
786 /// Map of external image IDs to native textures.
787 external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
788
789 /// A special 1x1 dummy texture used for shaders that expect to work with
790 /// the output of the previous pass but are actually running in the first
791 /// pass.
792 dummy_cache_texture: Texture,
793
794 /// The outputs of the previous pass, if applicable.
795 prev_pass_color: Option<ActiveTexture>,
796 prev_pass_alpha: Option<ActiveTexture>,
797
798 /// Saved render targets from previous passes. This is used when a pass
799 /// needs access to the result of a pass other than the immediately-preceding
800 /// one. In this case, the `RenderTask` will get a a non-`None` `saved_index`,
801 /// which will cause the resulting render target to be persisted in this list
802 /// (at that index) until the end of the frame.
803 saved_targets: Vec<Texture>,
804
805 /// Pool of idle render target textures ready for re-use.
806 ///
807 /// Naively, it would seem like we only ever need two pairs of (color,
808 /// alpha) render targets: one for the output of the previous pass (serving
809 /// as input to the current pass), and one for the output of the current
810 /// pass. However, there are cases where the output of one pass is used as
811 /// the input to multiple future passes. For example, drop-shadows draw the
812 /// picture in pass X, then reference it in pass X+1 to create the blurred
813 /// shadow, and pass the results of both X and X+1 to pass X+2 draw the
814 /// actual content.
815 ///
816 /// See the comments in `allocate_target_texture` for more insight on why
817 /// reuse is a win.
818 render_target_pool: Vec<Texture>,
819 }
820
821 impl TextureResolver {
new(device: &mut Device) -> TextureResolver822 fn new(device: &mut Device) -> TextureResolver {
823 let dummy_cache_texture = device
824 .create_texture(
825 TextureTarget::Array,
826 ImageFormat::BGRA8,
827 1,
828 1,
829 TextureFilter::Linear,
830 None,
831 1,
832 );
833
834 TextureResolver {
835 texture_cache_map: FastHashMap::default(),
836 external_images: FastHashMap::default(),
837 dummy_cache_texture,
838 prev_pass_alpha: None,
839 prev_pass_color: None,
840 saved_targets: Vec::default(),
841 render_target_pool: Vec::new(),
842 }
843 }
844
deinit(self, device: &mut Device)845 fn deinit(self, device: &mut Device) {
846 device.delete_texture(self.dummy_cache_texture);
847
848 for (_id, texture) in self.texture_cache_map {
849 device.delete_texture(texture);
850 }
851
852 for texture in self.render_target_pool {
853 device.delete_texture(texture);
854 }
855 }
856
begin_frame(&mut self)857 fn begin_frame(&mut self) {
858 assert!(self.prev_pass_color.is_none());
859 assert!(self.prev_pass_alpha.is_none());
860 assert!(self.saved_targets.is_empty());
861 }
862
end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId)863 fn end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId) {
864 // return the cached targets to the pool
865 self.end_pass(device, None, None);
866 // return the saved targets as well
867 while let Some(target) = self.saved_targets.pop() {
868 self.return_to_pool(device, target);
869 }
870
871 // GC the render target pool.
872 //
873 // We use a simple scheme whereby we drop any texture that hasn't been used
874 // in the last 30 frames. This should generally prevent any sustained build-
875 // up of unused textures, unless we don't generate frames for a long period.
876 // This can happen when the window is minimized, and we probably want to
877 // flush all the WebRender caches in that case [1].
878 //
879 // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1494099
880 self.retain_targets(device, |texture| texture.used_recently(frame_id, 30));
881 }
882
883 /// Transfers ownership of a render target back to the pool.
return_to_pool(&mut self, device: &mut Device, target: Texture)884 fn return_to_pool(&mut self, device: &mut Device, target: Texture) {
885 device.invalidate_render_target(&target);
886 self.render_target_pool.push(target);
887 }
888
889 /// Drops all targets from the render target pool that do not satisfy the predicate.
retain_targets<F: Fn(&Texture) -> bool>(&mut self, device: &mut Device, f: F)890 pub fn retain_targets<F: Fn(&Texture) -> bool>(&mut self, device: &mut Device, f: F) {
891 // We can't just use retain() because `Texture` requires manual cleanup.
892 let mut tmp = SmallVec::<[Texture; 8]>::new();
893 for target in self.render_target_pool.drain(..) {
894 if f(&target) {
895 tmp.push(target);
896 } else {
897 device.delete_texture(target);
898 }
899 }
900 self.render_target_pool.extend(tmp);
901 }
902
end_pass( &mut self, device: &mut Device, a8_texture: Option<ActiveTexture>, rgba8_texture: Option<ActiveTexture>, )903 fn end_pass(
904 &mut self,
905 device: &mut Device,
906 a8_texture: Option<ActiveTexture>,
907 rgba8_texture: Option<ActiveTexture>,
908 ) {
909 // If we have cache textures from previous pass, return them to the pool.
910 // Also assign the pool index of those cache textures to last pass's index because this is
911 // the result of last pass.
912 // Note: the order here is important, needs to match the logic in `RenderPass::build()`.
913 if let Some(at) = self.prev_pass_color.take() {
914 if let Some(index) = at.saved_index {
915 assert_eq!(self.saved_targets.len(), index.0);
916 self.saved_targets.push(at.texture);
917 } else {
918 self.return_to_pool(device, at.texture);
919 }
920 }
921 if let Some(at) = self.prev_pass_alpha.take() {
922 if let Some(index) = at.saved_index {
923 assert_eq!(self.saved_targets.len(), index.0);
924 self.saved_targets.push(at.texture);
925 } else {
926 self.return_to_pool(device, at.texture);
927 }
928 }
929
930 // We have another pass to process, make these textures available
931 // as inputs to the next pass.
932 self.prev_pass_color = rgba8_texture;
933 self.prev_pass_alpha = a8_texture;
934 }
935
936 // Bind a source texture to the device.
bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device)937 fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) {
938 match *texture_id {
939 TextureSource::Invalid => {}
940 TextureSource::PrevPassAlpha => {
941 let texture = match self.prev_pass_alpha {
942 Some(ref at) => &at.texture,
943 None => &self.dummy_cache_texture,
944 };
945 device.bind_texture(sampler, texture);
946 }
947 TextureSource::PrevPassColor => {
948 let texture = match self.prev_pass_color {
949 Some(ref at) => &at.texture,
950 None => &self.dummy_cache_texture,
951 };
952 device.bind_texture(sampler, texture);
953 }
954 TextureSource::External(external_image) => {
955 let texture = self.external_images
956 .get(&(external_image.id, external_image.channel_index))
957 .expect(&format!("BUG: External image should be resolved by now"));
958 device.bind_external_texture(sampler, texture);
959 }
960 TextureSource::TextureCache(index) => {
961 let texture = &self.texture_cache_map[&index];
962 device.bind_texture(sampler, texture);
963 }
964 TextureSource::RenderTaskCache(saved_index) => {
965 let texture = &self.saved_targets[saved_index.0];
966 device.bind_texture(sampler, texture)
967 }
968 }
969 }
970
971 // Get the real (OpenGL) texture ID for a given source texture.
972 // For a texture cache texture, the IDs are stored in a vector
973 // map for fast access.
resolve(&self, texture_id: &TextureSource) -> Option<&Texture>974 fn resolve(&self, texture_id: &TextureSource) -> Option<&Texture> {
975 match *texture_id {
976 TextureSource::Invalid => None,
977 TextureSource::PrevPassAlpha => Some(
978 match self.prev_pass_alpha {
979 Some(ref at) => &at.texture,
980 None => &self.dummy_cache_texture,
981 }
982 ),
983 TextureSource::PrevPassColor => Some(
984 match self.prev_pass_color {
985 Some(ref at) => &at.texture,
986 None => &self.dummy_cache_texture,
987 }
988 ),
989 TextureSource::External(..) => {
990 panic!("BUG: External textures cannot be resolved, they can only be bound.");
991 }
992 TextureSource::TextureCache(index) => {
993 Some(&self.texture_cache_map[&index])
994 }
995 TextureSource::RenderTaskCache(saved_index) => {
996 Some(&self.saved_targets[saved_index.0])
997 }
998 }
999 }
1000
report_memory(&self) -> MemoryReport1001 fn report_memory(&self) -> MemoryReport {
1002 let mut report = MemoryReport::default();
1003
1004 // We're reporting GPU memory rather than heap-allocations, so we don't
1005 // use size_of_op.
1006 for t in self.texture_cache_map.values() {
1007 report.texture_cache_textures += t.size_in_bytes();
1008 }
1009 for t in self.render_target_pool.iter() {
1010 report.render_target_textures += t.size_in_bytes();
1011 }
1012
1013 report
1014 }
1015 }
1016
1017 #[derive(Debug, Copy, Clone, PartialEq)]
1018 #[cfg_attr(feature = "capture", derive(Serialize))]
1019 #[cfg_attr(feature = "replay", derive(Deserialize))]
1020 pub enum BlendMode {
1021 None,
1022 Alpha,
1023 PremultipliedAlpha,
1024 PremultipliedDestOut,
1025 SubpixelDualSource,
1026 SubpixelConstantTextColor(ColorF),
1027 SubpixelWithBgColor,
1028 }
1029
1030 /// Tracks the state of each row in the GPU cache texture.
1031 struct CacheRow {
1032 /// Mirrored block data on CPU for this row. We store a copy of
1033 /// the data on the CPU side to improve upload batching.
1034 cpu_blocks: Box<[GpuBlockData; MAX_VERTEX_TEXTURE_WIDTH]>,
1035 /// True if this row is dirty.
1036 is_dirty: bool,
1037 }
1038
1039 impl CacheRow {
new() -> Self1040 fn new() -> Self {
1041 CacheRow {
1042 cpu_blocks: Box::new([GpuBlockData::EMPTY; MAX_VERTEX_TEXTURE_WIDTH]),
1043 is_dirty: false,
1044 }
1045 }
1046 }
1047
1048 /// The bus over which CPU and GPU versions of the GPU cache
1049 /// get synchronized.
1050 enum GpuCacheBus {
1051 /// PBO-based updates, currently operate on a row granularity.
1052 /// Therefore, are subject to fragmentation issues.
1053 PixelBuffer {
1054 /// PBO used for transfers.
1055 buffer: PBO,
1056 /// Per-row data.
1057 rows: Vec<CacheRow>,
1058 },
1059 /// Shader-based scattering updates. Currently rendered by a set
1060 /// of points into the GPU texture, each carrying a `GpuBlockData`.
1061 Scatter {
1062 /// Special program to run the scattered update.
1063 program: Program,
1064 /// VAO containing the source vertex buffers.
1065 vao: CustomVAO,
1066 /// VBO for positional data, supplied as normalized `u16`.
1067 buf_position: VBO<[u16; 2]>,
1068 /// VBO for gpu block data.
1069 buf_value: VBO<GpuBlockData>,
1070 /// Currently stored block count.
1071 count: usize,
1072 },
1073 }
1074
1075 /// The device-specific representation of the cache texture in gpu_cache.rs
1076 struct GpuCacheTexture {
1077 texture: Option<Texture>,
1078 bus: GpuCacheBus,
1079 }
1080
1081 impl GpuCacheTexture {
1082
1083 /// Ensures that we have an appropriately-sized texture. Returns true if a
1084 /// new texture was created.
ensure_texture(&mut self, device: &mut Device, height: i32)1085 fn ensure_texture(&mut self, device: &mut Device, height: i32) {
1086 // If we already have a texture that works, we're done.
1087 if self.texture.as_ref().map_or(false, |t| t.get_dimensions().height >= height) {
1088 if GPU_CACHE_RESIZE_TEST {
1089 // Special debug mode - resize the texture even though it's fine.
1090 } else {
1091 return;
1092 }
1093 }
1094
1095 // Take the old texture, if any.
1096 let blit_source = self.texture.take();
1097
1098 // Create the new texture.
1099 assert!(height >= 2, "Height is too small for ANGLE");
1100 let new_size = DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as _, height);
1101 let rt_info = Some(RenderTargetInfo { has_depth: false });
1102 let mut texture = device.create_texture(
1103 TextureTarget::Default,
1104 ImageFormat::RGBAF32,
1105 new_size.width,
1106 new_size.height,
1107 TextureFilter::Nearest,
1108 rt_info,
1109 1,
1110 );
1111
1112 // Blit the contents of the previous texture, if applicable.
1113 if let Some(blit_source) = blit_source {
1114 device.blit_renderable_texture(&mut texture, &blit_source);
1115 device.delete_texture(blit_source);
1116 }
1117
1118 self.texture = Some(texture);
1119 }
1120
new(device: &mut Device, use_scatter: bool) -> Result<Self, RendererError>1121 fn new(device: &mut Device, use_scatter: bool) -> Result<Self, RendererError> {
1122 let bus = if use_scatter {
1123 let program = device.create_program_linked(
1124 "gpu_cache_update",
1125 String::new(),
1126 &desc::GPU_CACHE_UPDATE,
1127 )?;
1128 let buf_position = device.create_vbo();
1129 let buf_value = device.create_vbo();
1130 //Note: the vertex attributes have to be supplied in the same order
1131 // as for program creation, but each assigned to a different stream.
1132 let vao = device.create_custom_vao(&[
1133 buf_position.stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[0..1]),
1134 buf_value .stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[1..2]),
1135 ]);
1136 GpuCacheBus::Scatter {
1137 program,
1138 vao,
1139 buf_position,
1140 buf_value,
1141 count: 0,
1142 }
1143 } else {
1144 let buffer = device.create_pbo();
1145 GpuCacheBus::PixelBuffer {
1146 buffer,
1147 rows: Vec::new(),
1148 }
1149 };
1150
1151 Ok(GpuCacheTexture {
1152 texture: None,
1153 bus,
1154 })
1155 }
1156
deinit(mut self, device: &mut Device)1157 fn deinit(mut self, device: &mut Device) {
1158 if let Some(t) = self.texture.take() {
1159 device.delete_texture(t);
1160 }
1161 match self.bus {
1162 GpuCacheBus::PixelBuffer { buffer, ..} => {
1163 device.delete_pbo(buffer);
1164 }
1165 GpuCacheBus::Scatter { program, vao, buf_position, buf_value, ..} => {
1166 device.delete_program(program);
1167 device.delete_custom_vao(vao);
1168 device.delete_vbo(buf_position);
1169 device.delete_vbo(buf_value);
1170 }
1171 }
1172 }
1173
get_height(&self) -> i321174 fn get_height(&self) -> i32 {
1175 self.texture.as_ref().map_or(0, |t| t.get_dimensions().height)
1176 }
1177
prepare_for_updates( &mut self, device: &mut Device, total_block_count: usize, max_height: i32, )1178 fn prepare_for_updates(
1179 &mut self,
1180 device: &mut Device,
1181 total_block_count: usize,
1182 max_height: i32,
1183 ) {
1184 self.ensure_texture(device, max_height);
1185 match self.bus {
1186 GpuCacheBus::PixelBuffer { .. } => {},
1187 GpuCacheBus::Scatter {
1188 ref mut buf_position,
1189 ref mut buf_value,
1190 ref mut count,
1191 ..
1192 } => {
1193 *count = 0;
1194 if total_block_count > buf_value.allocated_count() {
1195 device.allocate_vbo(buf_position, total_block_count, VertexUsageHint::Stream);
1196 device.allocate_vbo(buf_value, total_block_count, VertexUsageHint::Stream);
1197 }
1198 }
1199 }
1200 }
1201
update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList)1202 fn update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList) {
1203 match self.bus {
1204 GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
1205 for update in &updates.updates {
1206 match *update {
1207 GpuCacheUpdate::Copy {
1208 block_index,
1209 block_count,
1210 address,
1211 } => {
1212 let row = address.v as usize;
1213
1214 // Ensure that the CPU-side shadow copy of the GPU cache data has enough
1215 // rows to apply this patch.
1216 while rows.len() <= row {
1217 // Add a new row.
1218 rows.push(CacheRow::new());
1219 }
1220
1221 // This row is dirty (needs to be updated in GPU texture).
1222 rows[row].is_dirty = true;
1223
1224 // Copy the blocks from the patch array in the shadow CPU copy.
1225 let block_offset = address.u as usize;
1226 let data = &mut rows[row].cpu_blocks;
1227 for i in 0 .. block_count {
1228 data[block_offset + i] = updates.blocks[block_index + i];
1229 }
1230 }
1231 }
1232 }
1233 }
1234 GpuCacheBus::Scatter {
1235 ref buf_position,
1236 ref buf_value,
1237 ref mut count,
1238 ..
1239 } => {
1240 //TODO: re-use this heap allocation
1241 // Unused positions will be left as 0xFFFF, which translates to
1242 // (1.0, 1.0) in the vertex output position and gets culled out
1243 let mut position_data = vec![[!0u16; 2]; updates.blocks.len()];
1244 let size = self.texture.as_ref().unwrap().get_dimensions().to_usize();
1245
1246 for update in &updates.updates {
1247 match *update {
1248 GpuCacheUpdate::Copy {
1249 block_index,
1250 block_count,
1251 address,
1252 } => {
1253 // Convert the absolute texel position into normalized
1254 let y = ((2*address.v as usize + 1) << 15) / size.height;
1255 for i in 0 .. block_count {
1256 let x = ((2*address.u as usize + 2*i + 1) << 15) / size.width;
1257 position_data[block_index + i] = [x as _, y as _];
1258 }
1259 }
1260 }
1261 }
1262
1263 device.fill_vbo(buf_value, &updates.blocks, *count);
1264 device.fill_vbo(buf_position, &position_data, *count);
1265 *count += position_data.len();
1266 }
1267 }
1268 }
1269
flush(&mut self, device: &mut Device) -> usize1270 fn flush(&mut self, device: &mut Device) -> usize {
1271 let texture = self.texture.as_ref().unwrap();
1272 match self.bus {
1273 GpuCacheBus::PixelBuffer { ref buffer, ref mut rows } => {
1274 let rows_dirty = rows
1275 .iter()
1276 .filter(|row| row.is_dirty)
1277 .count();
1278 if rows_dirty == 0 {
1279 return 0
1280 }
1281
1282 let mut uploader = device.upload_texture(
1283 texture,
1284 buffer,
1285 rows_dirty * MAX_VERTEX_TEXTURE_WIDTH,
1286 );
1287
1288 for (row_index, row) in rows.iter_mut().enumerate() {
1289 if !row.is_dirty {
1290 continue;
1291 }
1292
1293 let rect = DeviceIntRect::new(
1294 DeviceIntPoint::new(0, row_index as i32),
1295 DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32, 1),
1296 );
1297
1298 uploader.upload(rect, 0, None, &*row.cpu_blocks);
1299
1300 row.is_dirty = false;
1301 }
1302
1303 rows_dirty
1304 }
1305 GpuCacheBus::Scatter { ref program, ref vao, count, .. } => {
1306 device.disable_depth();
1307 device.set_blend(false);
1308 device.bind_program(program);
1309 device.bind_custom_vao(vao);
1310 device.bind_draw_target(
1311 DrawTarget::Texture {
1312 texture,
1313 layer: 0,
1314 with_depth: false,
1315 },
1316 );
1317 device.draw_nonindexed_points(0, count as _);
1318 0
1319 }
1320 }
1321 }
1322 }
1323
1324 struct VertexDataTexture {
1325 texture: Option<Texture>,
1326 format: ImageFormat,
1327 pbo: PBO,
1328 }
1329
1330 impl VertexDataTexture {
new( device: &mut Device, format: ImageFormat, ) -> VertexDataTexture1331 fn new(
1332 device: &mut Device,
1333 format: ImageFormat,
1334 ) -> VertexDataTexture {
1335 let pbo = device.create_pbo();
1336 VertexDataTexture { texture: None, format, pbo }
1337 }
1338
1339 /// Returns a borrow of the GPU texture. Panics if it hasn't been initialized.
texture(&self) -> &Texture1340 fn texture(&self) -> &Texture {
1341 self.texture.as_ref().unwrap()
1342 }
1343
1344 /// Returns an estimate of the GPU memory consumed by this VertexDataTexture.
size_in_bytes(&self) -> usize1345 fn size_in_bytes(&self) -> usize {
1346 self.texture.as_ref().map_or(0, |t| t.size_in_bytes())
1347 }
1348
update<T>(&mut self, device: &mut Device, data: &mut Vec<T>)1349 fn update<T>(&mut self, device: &mut Device, data: &mut Vec<T>) {
1350 debug_assert!(mem::size_of::<T>() % 16 == 0);
1351 let texels_per_item = mem::size_of::<T>() / 16;
1352 let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item;
1353
1354 // Ensure we always end up with a texture when leaving this method.
1355 if data.is_empty() {
1356 if self.texture.is_some() {
1357 return;
1358 }
1359 data.push(unsafe { mem::uninitialized() });
1360 }
1361
1362 // Extend the data array to be a multiple of the row size.
1363 // This ensures memory safety when the array is passed to
1364 // OpenGL to upload to the GPU.
1365 if items_per_row != 0 {
1366 while data.len() % items_per_row != 0 {
1367 data.push(unsafe { mem::uninitialized() });
1368 }
1369 }
1370
1371 let width =
1372 (MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)) as i32;
1373 let needed_height = (data.len() / items_per_row) as i32;
1374 let existing_height = self.texture.as_ref().map_or(0, |t| t.get_dimensions().height);
1375
1376 // Create a new texture if needed.
1377 //
1378 // These textures are generally very small, which is why we don't bother
1379 // with incremental updates and just re-upload every frame. For most pages
1380 // they're one row each, and on stress tests like css-francine they end up
1381 // in the 6-14 range. So we size the texture tightly to what we need (usually
1382 // 1), and shrink it if the waste would be more than 10 rows. This helps
1383 // with memory overhead, especially because there are several instances of
1384 // these textures per Renderer.
1385 if needed_height > existing_height || needed_height + 10 < existing_height {
1386 // Drop the existing texture, if any.
1387 if let Some(t) = self.texture.take() {
1388 device.delete_texture(t);
1389 }
1390
1391 let texture = device.create_texture(
1392 TextureTarget::Default,
1393 self.format,
1394 width,
1395 // Ensure height is at least two to work around
1396 // https://bugs.chromium.org/p/angleproject/issues/detail?id=3039
1397 needed_height.max(2),
1398 TextureFilter::Nearest,
1399 None,
1400 1,
1401 );
1402 self.texture = Some(texture);
1403 }
1404
1405 let rect = DeviceIntRect::new(
1406 DeviceIntPoint::zero(),
1407 DeviceIntSize::new(width, needed_height),
1408 );
1409 device
1410 .upload_texture(self.texture(), &self.pbo, 0)
1411 .upload(rect, 0, None, data);
1412 }
1413
deinit(mut self, device: &mut Device)1414 fn deinit(mut self, device: &mut Device) {
1415 device.delete_pbo(self.pbo);
1416 if let Some(t) = self.texture.take() {
1417 device.delete_texture(t);
1418 }
1419 }
1420 }
1421
1422 struct FrameOutput {
1423 last_access: GpuFrameId,
1424 fbo_id: FBOId,
1425 }
1426
1427 #[derive(PartialEq)]
1428 struct TargetSelector {
1429 size: DeviceIntSize,
1430 num_layers: usize,
1431 format: ImageFormat,
1432 }
1433
1434 struct LazyInitializedDebugRenderer {
1435 debug_renderer: Option<DebugRenderer>,
1436 failed: bool,
1437 }
1438
1439 impl LazyInitializedDebugRenderer {
new() -> Self1440 pub fn new() -> Self {
1441 Self {
1442 debug_renderer: None,
1443 failed: false,
1444 }
1445 }
1446
get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer>1447 pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> {
1448 if self.failed {
1449 return None;
1450 }
1451 if self.debug_renderer.is_none() {
1452 match DebugRenderer::new(device) {
1453 Ok(renderer) => { self.debug_renderer = Some(renderer); }
1454 Err(_) => {
1455 // The shader compilation code already logs errors.
1456 self.failed = true;
1457 }
1458 }
1459 }
1460
1461 self.debug_renderer.as_mut()
1462 }
1463
1464 /// Returns mut ref to `DebugRenderer` if one already exists, otherwise returns `None`.
try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer>1465 pub fn try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer> {
1466 self.debug_renderer.as_mut()
1467 }
1468
deinit(self, device: &mut Device)1469 pub fn deinit(self, device: &mut Device) {
1470 if let Some(debug_renderer) = self.debug_renderer {
1471 debug_renderer.deinit(device);
1472 }
1473 }
1474 }
1475
1476 // NB: If you add more VAOs here, be sure to deinitialize them in
1477 // `Renderer::deinit()` below.
1478 pub struct RendererVAOs {
1479 prim_vao: VAO,
1480 blur_vao: VAO,
1481 clip_vao: VAO,
1482 border_vao: VAO,
1483 line_vao: VAO,
1484 scale_vao: VAO,
1485 }
1486
1487 /// The renderer is responsible for submitting to the GPU the work prepared by the
1488 /// RenderBackend.
1489 ///
1490 /// We have a separate `Renderer` instance for each instance of WebRender (generally
1491 /// one per OS window), and all instances share the same thread.
1492 pub struct Renderer {
1493 result_rx: Receiver<ResultMsg>,
1494 debug_server: DebugServer,
1495 pub device: Device,
1496 pending_texture_updates: Vec<TextureUpdateList>,
1497 pending_gpu_cache_updates: Vec<GpuCacheUpdateList>,
1498 pending_gpu_cache_clear: bool,
1499 pending_shader_updates: Vec<PathBuf>,
1500 active_documents: Vec<(DocumentId, RenderedDocument)>,
1501
1502 shaders: Rc<RefCell<Shaders>>,
1503
1504 pub gpu_glyph_renderer: GpuGlyphRenderer,
1505
1506 max_recorded_profiles: usize,
1507
1508 clear_color: Option<ColorF>,
1509 enable_clear_scissor: bool,
1510 debug: LazyInitializedDebugRenderer,
1511 debug_flags: DebugFlags,
1512 backend_profile_counters: BackendProfileCounters,
1513 profile_counters: RendererProfileCounters,
1514 resource_upload_time: u64,
1515 gpu_cache_upload_time: u64,
1516 profiler: Profiler,
1517 new_frame_indicator: ChangeIndicator,
1518 new_scene_indicator: ChangeIndicator,
1519 slow_frame_indicator: ChangeIndicator,
1520
1521 last_time: u64,
1522
1523 pub gpu_profile: GpuProfiler<GpuProfileTag>,
1524 vaos: RendererVAOs,
1525
1526 prim_header_f_texture: VertexDataTexture,
1527 prim_header_i_texture: VertexDataTexture,
1528 transforms_texture: VertexDataTexture,
1529 render_task_texture: VertexDataTexture,
1530 gpu_cache_texture: GpuCacheTexture,
1531
1532 /// When the GPU cache debugger is enabled, we keep track of the live blocks
1533 /// in the GPU cache so that we can use them for the debug display. This
1534 /// member stores those live blocks, indexed by row.
1535 gpu_cache_debug_chunks: Vec<Vec<GpuCacheDebugChunk>>,
1536
1537 gpu_cache_frame_id: FrameId,
1538 gpu_cache_overflow: bool,
1539
1540 pipeline_info: PipelineInfo,
1541
1542 // Manages and resolves source textures IDs to real texture IDs.
1543 texture_resolver: TextureResolver,
1544
1545 // A PBO used to do asynchronous texture cache uploads.
1546 texture_cache_upload_pbo: PBO,
1547
1548 dither_matrix_texture: Option<Texture>,
1549
1550 /// Optional trait object that allows the client
1551 /// application to provide external buffers for image data.
1552 external_image_handler: Option<Box<ExternalImageHandler>>,
1553
1554 /// Optional trait object that allows the client
1555 /// application to provide a texture handle to
1556 /// copy the WR output to.
1557 output_image_handler: Option<Box<OutputImageHandler>>,
1558
1559 /// Optional function pointers for measuring memory used by a given
1560 /// heap-allocated pointer.
1561 size_of_ops: Option<MallocSizeOfOps>,
1562
1563 // Currently allocated FBOs for output frames.
1564 output_targets: FastHashMap<u32, FrameOutput>,
1565
1566 pub renderer_errors: Vec<RendererError>,
1567
1568 /// List of profile results from previous frames. Can be retrieved
1569 /// via get_frame_profiles().
1570 cpu_profiles: VecDeque<CpuProfile>,
1571 gpu_profiles: VecDeque<GpuProfile>,
1572
1573 /// Notification requests to be fulfilled after rendering.
1574 notifications: Vec<NotificationRequest>,
1575
1576 framebuffer_size: Option<DeviceIntSize>,
1577
1578 /// A lazily created texture for the zoom debugging widget.
1579 zoom_debug_texture: Option<Texture>,
1580
1581 /// The current mouse position. This is used for debugging
1582 /// functionality only, such as the debug zoom widget.
1583 cursor_position: DeviceIntPoint,
1584
1585 #[cfg(feature = "capture")]
1586 read_fbo: FBOId,
1587 #[cfg(feature = "replay")]
1588 owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>,
1589 }
1590
1591 #[derive(Debug)]
1592 pub enum RendererError {
1593 Shader(ShaderError),
1594 Thread(std::io::Error),
1595 Resource(ResourceCacheError),
1596 MaxTextureSize,
1597 }
1598
1599 impl From<ShaderError> for RendererError {
from(err: ShaderError) -> Self1600 fn from(err: ShaderError) -> Self {
1601 RendererError::Shader(err)
1602 }
1603 }
1604
1605 impl From<std::io::Error> for RendererError {
from(err: std::io::Error) -> Self1606 fn from(err: std::io::Error) -> Self {
1607 RendererError::Thread(err)
1608 }
1609 }
1610
1611 impl From<ResourceCacheError> for RendererError {
from(err: ResourceCacheError) -> Self1612 fn from(err: ResourceCacheError) -> Self {
1613 RendererError::Resource(err)
1614 }
1615 }
1616
1617 impl Renderer {
1618 /// Initializes WebRender and creates a `Renderer` and `RenderApiSender`.
1619 ///
1620 /// # Examples
1621 /// Initializes a `Renderer` with some reasonable values. For more information see
1622 /// [`RendererOptions`][rendereroptions].
1623 ///
1624 /// ```rust,ignore
1625 /// # use webrender::renderer::Renderer;
1626 /// # use std::path::PathBuf;
1627 /// let opts = webrender::RendererOptions {
1628 /// device_pixel_ratio: 1.0,
1629 /// resource_override_path: None,
1630 /// enable_aa: false,
1631 /// };
1632 /// let (renderer, sender) = Renderer::new(opts);
1633 /// ```
1634 /// [rendereroptions]: struct.RendererOptions.html
new( gl: Rc<gl::Gl>, notifier: Box<RenderNotifier>, mut options: RendererOptions, shaders: Option<&mut WrShaders> ) -> Result<(Self, RenderApiSender), RendererError>1635 pub fn new(
1636 gl: Rc<gl::Gl>,
1637 notifier: Box<RenderNotifier>,
1638 mut options: RendererOptions,
1639 shaders: Option<&mut WrShaders>
1640 ) -> Result<(Self, RenderApiSender), RendererError> {
1641 HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
1642
1643 let (api_tx, api_rx) = channel::msg_channel()?;
1644 let (payload_tx, payload_rx) = channel::payload_channel()?;
1645 let (result_tx, result_rx) = channel();
1646 let gl_type = gl.get_type();
1647
1648 let debug_server = DebugServer::new(api_tx.clone());
1649
1650 let mut device = Device::new(
1651 gl,
1652 options.resource_override_path.clone(),
1653 options.upload_method.clone(),
1654 options.cached_programs.take(),
1655 );
1656
1657 let ext_dual_source_blending = !options.disable_dual_source_blending &&
1658 device.supports_extension("GL_ARB_blend_func_extended") &&
1659 device.supports_extension("GL_ARB_explicit_attrib_location");
1660
1661 // 512 is the minimum that the texture cache can work with.
1662 const MIN_TEXTURE_SIZE: i32 = 512;
1663 if let Some(user_limit) = options.max_texture_size {
1664 assert!(user_limit >= MIN_TEXTURE_SIZE);
1665 device.clamp_max_texture_size(user_limit);
1666 }
1667 if device.max_texture_size() < MIN_TEXTURE_SIZE {
1668 // Broken GL contexts can return a max texture size of zero (See #1260).
1669 // Better to gracefully fail now than panic as soon as a texture is allocated.
1670 error!(
1671 "Device reporting insufficient max texture size ({})",
1672 device.max_texture_size()
1673 );
1674 return Err(RendererError::MaxTextureSize);
1675 }
1676 let max_texture_size = device.max_texture_size();
1677 let max_texture_layers = device.max_texture_layers();
1678
1679 register_thread_with_profiler("Compositor".to_owned());
1680
1681 device.begin_frame();
1682
1683 let shaders = match shaders {
1684 Some(shaders) => Rc::clone(&shaders.shaders),
1685 None => Rc::new(RefCell::new(Shaders::new(&mut device, gl_type, &options)?)),
1686 };
1687
1688 let backend_profile_counters = BackendProfileCounters::new();
1689
1690 let dither_matrix_texture = if options.enable_dithering {
1691 let dither_matrix: [u8; 64] = [
1692 00,
1693 48,
1694 12,
1695 60,
1696 03,
1697 51,
1698 15,
1699 63,
1700 32,
1701 16,
1702 44,
1703 28,
1704 35,
1705 19,
1706 47,
1707 31,
1708 08,
1709 56,
1710 04,
1711 52,
1712 11,
1713 59,
1714 07,
1715 55,
1716 40,
1717 24,
1718 36,
1719 20,
1720 43,
1721 27,
1722 39,
1723 23,
1724 02,
1725 50,
1726 14,
1727 62,
1728 01,
1729 49,
1730 13,
1731 61,
1732 34,
1733 18,
1734 46,
1735 30,
1736 33,
1737 17,
1738 45,
1739 29,
1740 10,
1741 58,
1742 06,
1743 54,
1744 09,
1745 57,
1746 05,
1747 53,
1748 42,
1749 26,
1750 38,
1751 22,
1752 41,
1753 25,
1754 37,
1755 21,
1756 ];
1757
1758 let mut texture = device.create_texture(
1759 TextureTarget::Default,
1760 ImageFormat::R8,
1761 8,
1762 8,
1763 TextureFilter::Nearest,
1764 None,
1765 1,
1766 );
1767 device.upload_texture_immediate(&texture, &dither_matrix);
1768
1769 Some(texture)
1770 } else {
1771 None
1772 };
1773
1774 let x0 = 0.0;
1775 let y0 = 0.0;
1776 let x1 = 1.0;
1777 let y1 = 1.0;
1778
1779 let quad_indices: [u16; 6] = [0, 1, 2, 2, 1, 3];
1780 let quad_vertices = [
1781 PackedVertex { pos: [x0, y0] },
1782 PackedVertex { pos: [x1, y0] },
1783 PackedVertex { pos: [x0, y1] },
1784 PackedVertex { pos: [x1, y1] },
1785 ];
1786
1787 let prim_vao = device.create_vao(&desc::PRIM_INSTANCES);
1788 device.bind_vao(&prim_vao);
1789 device.update_vao_indices(&prim_vao, &quad_indices, VertexUsageHint::Static);
1790 device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static);
1791
1792 let gpu_glyph_renderer = try!(GpuGlyphRenderer::new(&mut device,
1793 &prim_vao,
1794 options.precache_flags));
1795
1796 let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao);
1797 let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao);
1798 let border_vao = device.create_vao_with_new_instances(&desc::BORDER, &prim_vao);
1799 let scale_vao = device.create_vao_with_new_instances(&desc::SCALE, &prim_vao);
1800 let line_vao = device.create_vao_with_new_instances(&desc::LINE, &prim_vao);
1801 let texture_cache_upload_pbo = device.create_pbo();
1802
1803 let texture_resolver = TextureResolver::new(&mut device);
1804
1805 let prim_header_f_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
1806 let prim_header_i_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAI32);
1807 let transforms_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
1808 let render_task_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
1809
1810 let gpu_cache_texture = GpuCacheTexture::new(
1811 &mut device,
1812 options.scatter_gpu_cache_updates,
1813 )?;
1814
1815 device.end_frame();
1816
1817 let backend_notifier = notifier.clone();
1818
1819 let default_font_render_mode = match (options.enable_aa, options.enable_subpixel_aa) {
1820 (true, true) => FontRenderMode::Subpixel,
1821 (true, false) => FontRenderMode::Alpha,
1822 (false, _) => FontRenderMode::Mono,
1823 };
1824
1825 let config = FrameBuilderConfig {
1826 default_font_render_mode,
1827 dual_source_blending_is_enabled: true,
1828 dual_source_blending_is_supported: ext_dual_source_blending,
1829 chase_primitive: options.chase_primitive,
1830 enable_picture_caching: options.enable_picture_caching,
1831 testing: options.testing,
1832 };
1833
1834 let device_pixel_ratio = options.device_pixel_ratio;
1835 let debug_flags = options.debug_flags;
1836 let payload_rx_for_backend = payload_rx.to_mpsc_receiver();
1837 let size_of_op = options.size_of_op;
1838 let enclosing_size_of_op = options.enclosing_size_of_op;
1839 let make_size_of_ops =
1840 move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op));
1841 let recorder = options.recorder;
1842 let thread_listener = Arc::new(options.thread_listener);
1843 let thread_listener_for_rayon_start = thread_listener.clone();
1844 let thread_listener_for_rayon_end = thread_listener.clone();
1845 let workers = options
1846 .workers
1847 .take()
1848 .unwrap_or_else(|| {
1849 let worker = ThreadPoolBuilder::new()
1850 .thread_name(|idx|{ format!("WRWorker#{}", idx) })
1851 .start_handler(move |idx| {
1852 register_thread_with_profiler(format!("WRWorker#{}", idx));
1853 if let Some(ref thread_listener) = *thread_listener_for_rayon_start {
1854 thread_listener.thread_started(&format!("WRWorker#{}", idx));
1855 }
1856 })
1857 .exit_handler(move |idx| {
1858 if let Some(ref thread_listener) = *thread_listener_for_rayon_end {
1859 thread_listener.thread_stopped(&format!("WRWorker#{}", idx));
1860 }
1861 })
1862 .build();
1863 Arc::new(worker.unwrap())
1864 });
1865 let sampler = options.sampler;
1866 let namespace_alloc_by_client = options.namespace_alloc_by_client;
1867
1868 let blob_image_handler = options.blob_image_handler.take();
1869 let thread_listener_for_render_backend = thread_listener.clone();
1870 let thread_listener_for_scene_builder = thread_listener.clone();
1871 let thread_listener_for_lp_scene_builder = thread_listener.clone();
1872 let scene_builder_hooks = options.scene_builder_hooks;
1873 let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
1874 let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
1875 let lp_scene_thread_name = format!("WRSceneBuilderLP#{}", options.renderer_id.unwrap_or(0));
1876 let glyph_rasterizer = GlyphRasterizer::new(workers)?;
1877
1878 let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(
1879 config,
1880 api_tx.clone(),
1881 scene_builder_hooks,
1882 make_size_of_ops(),
1883 );
1884 thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
1885 register_thread_with_profiler(scene_thread_name.clone());
1886 if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
1887 thread_listener.thread_started(&scene_thread_name);
1888 }
1889
1890 let mut scene_builder = scene_builder;
1891 scene_builder.run();
1892
1893 if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
1894 thread_listener.thread_stopped(&scene_thread_name);
1895 }
1896 })?;
1897
1898 let low_priority_scene_tx = if options.support_low_priority_transactions {
1899 let (low_priority_scene_tx, low_priority_scene_rx) = channel();
1900 let lp_builder = LowPrioritySceneBuilder {
1901 rx: low_priority_scene_rx,
1902 tx: scene_tx.clone(),
1903 simulate_slow_ms: 0,
1904 };
1905
1906 thread::Builder::new().name(lp_scene_thread_name.clone()).spawn(move || {
1907 register_thread_with_profiler(lp_scene_thread_name.clone());
1908 if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder {
1909 thread_listener.thread_started(&lp_scene_thread_name);
1910 }
1911
1912 let mut scene_builder = lp_builder;
1913 scene_builder.run();
1914
1915 if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder {
1916 thread_listener.thread_stopped(&lp_scene_thread_name);
1917 }
1918 })?;
1919
1920 low_priority_scene_tx
1921 } else {
1922 scene_tx.clone()
1923 };
1924
1925 thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
1926 register_thread_with_profiler(rb_thread_name.clone());
1927 if let Some(ref thread_listener) = *thread_listener_for_render_backend {
1928 thread_listener.thread_started(&rb_thread_name);
1929 }
1930
1931 let texture_cache = TextureCache::new(
1932 max_texture_size,
1933 max_texture_layers,
1934 TileCache::tile_dimensions(config.testing),
1935 );
1936
1937 let resource_cache = ResourceCache::new(
1938 texture_cache,
1939 glyph_rasterizer,
1940 blob_image_handler,
1941 );
1942
1943 let mut backend = RenderBackend::new(
1944 api_rx,
1945 payload_rx_for_backend,
1946 result_tx,
1947 scene_tx,
1948 low_priority_scene_tx,
1949 scene_rx,
1950 device_pixel_ratio,
1951 resource_cache,
1952 backend_notifier,
1953 config,
1954 recorder,
1955 sampler,
1956 make_size_of_ops(),
1957 debug_flags,
1958 namespace_alloc_by_client,
1959 );
1960 backend.run(backend_profile_counters);
1961 if let Some(ref thread_listener) = *thread_listener_for_render_backend {
1962 thread_listener.thread_stopped(&rb_thread_name);
1963 }
1964 })?;
1965
1966 let ext_debug_marker = device.supports_extension("GL_EXT_debug_marker");
1967 let gpu_profile = GpuProfiler::new(Rc::clone(device.rc_gl()), ext_debug_marker);
1968 #[cfg(feature = "capture")]
1969 let read_fbo = device.create_fbo();
1970
1971 let mut renderer = Renderer {
1972 result_rx,
1973 debug_server,
1974 device,
1975 active_documents: Vec::new(),
1976 pending_texture_updates: Vec::new(),
1977 pending_gpu_cache_updates: Vec::new(),
1978 pending_gpu_cache_clear: false,
1979 pending_shader_updates: Vec::new(),
1980 shaders,
1981 debug: LazyInitializedDebugRenderer::new(),
1982 debug_flags: DebugFlags::empty(),
1983 backend_profile_counters: BackendProfileCounters::new(),
1984 profile_counters: RendererProfileCounters::new(),
1985 resource_upload_time: 0,
1986 gpu_cache_upload_time: 0,
1987 profiler: Profiler::new(),
1988 new_frame_indicator: ChangeIndicator::new(),
1989 new_scene_indicator: ChangeIndicator::new(),
1990 slow_frame_indicator: ChangeIndicator::new(),
1991 max_recorded_profiles: options.max_recorded_profiles,
1992 clear_color: options.clear_color,
1993 enable_clear_scissor: options.enable_clear_scissor,
1994 last_time: 0,
1995 gpu_profile,
1996 gpu_glyph_renderer,
1997 vaos: RendererVAOs {
1998 prim_vao,
1999 blur_vao,
2000 clip_vao,
2001 border_vao,
2002 scale_vao,
2003 line_vao,
2004 },
2005 transforms_texture,
2006 prim_header_i_texture,
2007 prim_header_f_texture,
2008 render_task_texture,
2009 pipeline_info: PipelineInfo::default(),
2010 dither_matrix_texture,
2011 external_image_handler: None,
2012 output_image_handler: None,
2013 size_of_ops: make_size_of_ops(),
2014 output_targets: FastHashMap::default(),
2015 cpu_profiles: VecDeque::new(),
2016 gpu_profiles: VecDeque::new(),
2017 gpu_cache_texture,
2018 gpu_cache_debug_chunks: Vec::new(),
2019 gpu_cache_frame_id: FrameId::INVALID,
2020 gpu_cache_overflow: false,
2021 texture_cache_upload_pbo,
2022 texture_resolver,
2023 renderer_errors: Vec::new(),
2024 #[cfg(feature = "capture")]
2025 read_fbo,
2026 #[cfg(feature = "replay")]
2027 owned_external_images: FastHashMap::default(),
2028 notifications: Vec::new(),
2029 framebuffer_size: None,
2030 zoom_debug_texture: None,
2031 cursor_position: DeviceIntPoint::zero(),
2032 };
2033
2034 // We initially set the flags to default and then now call set_debug_flags
2035 // to ensure any potential transition when enabling a flag is run.
2036 renderer.set_debug_flags(debug_flags);
2037
2038 let sender = RenderApiSender::new(api_tx, payload_tx);
2039 Ok((renderer, sender))
2040 }
2041
2042 /// Update the current position of the debug cursor.
set_cursor_position( &mut self, position: DeviceIntPoint, )2043 pub fn set_cursor_position(
2044 &mut self,
2045 position: DeviceIntPoint,
2046 ) {
2047 self.cursor_position = position;
2048 }
2049
get_max_texture_size(&self) -> i322050 pub fn get_max_texture_size(&self) -> i32 {
2051 self.device.max_texture_size()
2052 }
2053
get_graphics_api_info(&self) -> GraphicsApiInfo2054 pub fn get_graphics_api_info(&self) -> GraphicsApiInfo {
2055 GraphicsApiInfo {
2056 kind: GraphicsApi::OpenGL,
2057 version: self.device.gl().get_string(gl::VERSION),
2058 renderer: self.device.gl().get_string(gl::RENDERER),
2059 }
2060 }
2061
2062 /// Returns the Epoch of the current frame in a pipeline.
current_epoch(&self, pipeline_id: PipelineId) -> Option<Epoch>2063 pub fn current_epoch(&self, pipeline_id: PipelineId) -> Option<Epoch> {
2064 self.pipeline_info.epochs.get(&pipeline_id).cloned()
2065 }
2066
flush_pipeline_info(&mut self) -> PipelineInfo2067 pub fn flush_pipeline_info(&mut self) -> PipelineInfo {
2068 mem::replace(&mut self.pipeline_info, PipelineInfo::default())
2069 }
2070
2071 // update the program cache with new binaries, e.g. when some of the lazy loaded
2072 // shader programs got activated in the mean time
update_program_cache(&mut self, cached_programs: Rc<ProgramCache>)2073 pub fn update_program_cache(&mut self, cached_programs: Rc<ProgramCache>) {
2074 self.device.update_program_cache(cached_programs);
2075 }
2076
2077 /// Processes the result queue.
2078 ///
2079 /// Should be called before `render()`, as texture cache updates are done here.
update(&mut self)2080 pub fn update(&mut self) {
2081 profile_scope!("update");
2082 // Pull any pending results and return the most recent.
2083 while let Ok(msg) = self.result_rx.try_recv() {
2084 match msg {
2085 ResultMsg::PublishPipelineInfo(mut pipeline_info) => {
2086 for (pipeline_id, epoch) in pipeline_info.epochs {
2087 self.pipeline_info.epochs.insert(pipeline_id, epoch);
2088 }
2089 self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..));
2090 }
2091 ResultMsg::PublishDocument(
2092 document_id,
2093 mut doc,
2094 texture_update_list,
2095 profile_counters,
2096 ) => {
2097 if doc.is_new_scene {
2098 self.new_scene_indicator.changed();
2099 }
2100
2101 // Add a new document to the active set, expressed as a `Vec` in order
2102 // to re-order based on `DocumentLayer` during rendering.
2103 match self.active_documents.iter().position(|&(id, _)| id == document_id) {
2104 Some(pos) => {
2105 // If the document we are replacing must be drawn
2106 // (in order to update the texture cache), issue
2107 // a render just to off-screen targets.
2108 if self.active_documents[pos].1.frame.must_be_drawn() {
2109 let framebuffer_size = self.framebuffer_size;
2110 self.render_impl(framebuffer_size).ok();
2111 }
2112 self.active_documents[pos].1 = doc;
2113 }
2114 None => self.active_documents.push((document_id, doc)),
2115 }
2116
2117 // IMPORTANT: The pending texture cache updates must be applied
2118 // *after* the previous frame has been rendered above
2119 // (if neceessary for a texture cache update). For
2120 // an example of why this is required:
2121 // 1) Previous frame contains a render task that
2122 // targets Texture X.
2123 // 2) New frame contains a texture cache update which
2124 // frees Texture X.
2125 // 3) bad stuff happens.
2126
2127 //TODO: associate `document_id` with target window
2128 self.pending_texture_updates.push(texture_update_list);
2129 self.backend_profile_counters = profile_counters;
2130 }
2131 ResultMsg::UpdateGpuCache(mut list) => {
2132 if list.clear {
2133 self.pending_gpu_cache_clear = true;
2134 }
2135 if list.clear {
2136 self.gpu_cache_debug_chunks = Vec::new();
2137 }
2138 for cmd in mem::replace(&mut list.debug_commands, Vec::new()) {
2139 match cmd {
2140 GpuCacheDebugCmd::Alloc(chunk) => {
2141 let row = chunk.address.v as usize;
2142 if row >= self.gpu_cache_debug_chunks.len() {
2143 self.gpu_cache_debug_chunks.resize(row + 1, Vec::new());
2144 }
2145 self.gpu_cache_debug_chunks[row].push(chunk);
2146 },
2147 GpuCacheDebugCmd::Free(address) => {
2148 let chunks = &mut self.gpu_cache_debug_chunks[address.v as usize];
2149 let pos = chunks.iter()
2150 .position(|x| x.address == address).unwrap();
2151 chunks.remove(pos);
2152 },
2153 }
2154 }
2155 self.pending_gpu_cache_updates.push(list);
2156 }
2157 ResultMsg::UpdateResources {
2158 updates,
2159 memory_pressure,
2160 } => {
2161 self.pending_texture_updates.push(updates);
2162 self.device.begin_frame();
2163
2164 self.update_texture_cache();
2165
2166 // Flush the render target pool on memory pressure.
2167 //
2168 // This needs to be separate from the block below because
2169 // the device module asserts if we delete textures while
2170 // not in a frame.
2171 if memory_pressure {
2172 self.texture_resolver.retain_targets(&mut self.device, |_| false);
2173 }
2174
2175 self.device.end_frame();
2176 // If we receive a `PublishDocument` message followed by this one
2177 // within the same update we need to cancel the frame because we
2178 // might have deleted the resources in use in the frame due to a
2179 // memory pressure event.
2180 if memory_pressure {
2181 self.active_documents.clear();
2182 }
2183 }
2184 ResultMsg::AppendNotificationRequests(mut notifications) => {
2185 if self.pending_texture_updates.is_empty() {
2186 drain_filter(
2187 &mut notifications,
2188 |n| { n.when() == Checkpoint::FrameTexturesUpdated },
2189 |n| { n.notify(); },
2190 );
2191 }
2192 self.notifications.append(&mut notifications);
2193 }
2194 ResultMsg::RefreshShader(path) => {
2195 self.pending_shader_updates.push(path);
2196 }
2197 ResultMsg::DebugOutput(output) => match output {
2198 DebugOutput::FetchDocuments(string) |
2199 DebugOutput::FetchClipScrollTree(string) => {
2200 self.debug_server.send(string);
2201 }
2202 #[cfg(feature = "capture")]
2203 DebugOutput::SaveCapture(config, deferred) => {
2204 self.save_capture(config, deferred);
2205 }
2206 #[cfg(feature = "replay")]
2207 DebugOutput::LoadCapture(root, plain_externals) => {
2208 self.active_documents.clear();
2209 self.load_capture(root, plain_externals);
2210 }
2211 },
2212 ResultMsg::DebugCommand(command) => {
2213 self.handle_debug_command(command);
2214 }
2215 }
2216 }
2217 }
2218
2219 #[cfg(not(feature = "debugger"))]
get_screenshot_for_debugger(&mut self) -> String2220 fn get_screenshot_for_debugger(&mut self) -> String {
2221 // Avoid unused param warning.
2222 let _ = &self.debug_server;
2223 String::new()
2224 }
2225
2226
2227 #[cfg(feature = "debugger")]
get_screenshot_for_debugger(&mut self) -> String2228 fn get_screenshot_for_debugger(&mut self) -> String {
2229 use api::ImageDescriptor;
2230
2231 let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true, false);
2232 let data = self.device.read_pixels(&desc);
2233 let screenshot = debug_server::Screenshot::new(desc.size, data);
2234
2235 serde_json::to_string(&screenshot).unwrap()
2236 }
2237
2238 #[cfg(not(feature = "debugger"))]
get_passes_for_debugger(&self) -> String2239 fn get_passes_for_debugger(&self) -> String {
2240 // Avoid unused param warning.
2241 let _ = &self.debug_server;
2242 String::new()
2243 }
2244
2245 #[cfg(feature = "debugger")]
debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target2246 fn debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target {
2247 let mut debug_target = debug_server::Target::new("A8");
2248
2249 debug_target.add(
2250 debug_server::BatchKind::Cache,
2251 "Scalings",
2252 target.scalings.len(),
2253 );
2254 debug_target.add(
2255 debug_server::BatchKind::Cache,
2256 "Zero Clears",
2257 target.zero_clears.len(),
2258 );
2259 debug_target.add(
2260 debug_server::BatchKind::Clip,
2261 "BoxShadows",
2262 target.clip_batcher.box_shadows.len(),
2263 );
2264 debug_target.add(
2265 debug_server::BatchKind::Cache,
2266 "Vertical Blur",
2267 target.vertical_blurs.len(),
2268 );
2269 debug_target.add(
2270 debug_server::BatchKind::Cache,
2271 "Horizontal Blur",
2272 target.horizontal_blurs.len(),
2273 );
2274 debug_target.add(
2275 debug_server::BatchKind::Clip,
2276 "Rectangles",
2277 target.clip_batcher.rectangles.len(),
2278 );
2279 for (_, items) in target.clip_batcher.images.iter() {
2280 debug_target.add(debug_server::BatchKind::Clip, "Image mask", items.len());
2281 }
2282
2283 debug_target
2284 }
2285
2286 #[cfg(feature = "debugger")]
debug_color_target(target: &ColorRenderTarget) -> debug_server::Target2287 fn debug_color_target(target: &ColorRenderTarget) -> debug_server::Target {
2288 let mut debug_target = debug_server::Target::new("RGBA8");
2289
2290 debug_target.add(
2291 debug_server::BatchKind::Cache,
2292 "Scalings",
2293 target.scalings.len(),
2294 );
2295 debug_target.add(
2296 debug_server::BatchKind::Cache,
2297 "Readbacks",
2298 target.readbacks.len(),
2299 );
2300 debug_target.add(
2301 debug_server::BatchKind::Cache,
2302 "Vertical Blur",
2303 target.vertical_blurs.len(),
2304 );
2305 debug_target.add(
2306 debug_server::BatchKind::Cache,
2307 "Horizontal Blur",
2308 target.horizontal_blurs.len(),
2309 );
2310
2311 for alpha_batch_container in &target.alpha_batch_containers {
2312 for batch in alpha_batch_container.opaque_batches.iter().rev() {
2313 debug_target.add(
2314 debug_server::BatchKind::Opaque,
2315 batch.key.kind.debug_name(),
2316 batch.instances.len(),
2317 );
2318 }
2319
2320 for batch in &alpha_batch_container.alpha_batches {
2321 debug_target.add(
2322 debug_server::BatchKind::Alpha,
2323 batch.key.kind.debug_name(),
2324 batch.instances.len(),
2325 );
2326 }
2327 }
2328
2329 debug_target
2330 }
2331
2332 #[cfg(feature = "debugger")]
debug_texture_cache_target(target: &TextureCacheRenderTarget) -> debug_server::Target2333 fn debug_texture_cache_target(target: &TextureCacheRenderTarget) -> debug_server::Target {
2334 let mut debug_target = debug_server::Target::new("Texture Cache");
2335
2336 debug_target.add(
2337 debug_server::BatchKind::Cache,
2338 "Horizontal Blur",
2339 target.horizontal_blurs.len(),
2340 );
2341
2342 debug_target
2343 }
2344
2345 #[cfg(feature = "debugger")]
get_passes_for_debugger(&self) -> String2346 fn get_passes_for_debugger(&self) -> String {
2347 let mut debug_passes = debug_server::PassList::new();
2348
2349 for &(_, ref render_doc) in &self.active_documents {
2350 for pass in &render_doc.frame.passes {
2351 let mut debug_targets = Vec::new();
2352 match pass.kind {
2353 RenderPassKind::MainFramebuffer(ref target) => {
2354 debug_targets.push(Self::debug_color_target(target));
2355 }
2356 RenderPassKind::OffScreen { ref alpha, ref color, ref texture_cache } => {
2357 debug_targets.extend(alpha.targets.iter().map(Self::debug_alpha_target));
2358 debug_targets.extend(color.targets.iter().map(Self::debug_color_target));
2359 debug_targets.extend(texture_cache.iter().map(|(_, target)| Self::debug_texture_cache_target(target)))
2360 }
2361 }
2362
2363 debug_passes.add(debug_server::Pass { targets: debug_targets });
2364 }
2365 }
2366
2367 serde_json::to_string(&debug_passes).unwrap()
2368 }
2369
2370 #[cfg(not(feature = "debugger"))]
get_render_tasks_for_debugger(&self) -> String2371 fn get_render_tasks_for_debugger(&self) -> String {
2372 String::new()
2373 }
2374
2375 #[cfg(feature = "debugger")]
get_render_tasks_for_debugger(&self) -> String2376 fn get_render_tasks_for_debugger(&self) -> String {
2377 let mut debug_root = debug_server::RenderTaskList::new();
2378
2379 for &(_, ref render_doc) in &self.active_documents {
2380 let debug_node = debug_server::TreeNode::new("document render tasks");
2381 let mut builder = debug_server::TreeNodeBuilder::new(debug_node);
2382
2383 let render_tasks = &render_doc.frame.render_tasks;
2384 match render_tasks.tasks.last() {
2385 Some(main_task) => main_task.print_with(&mut builder, render_tasks),
2386 None => continue,
2387 };
2388
2389 debug_root.add(builder.build());
2390 }
2391
2392 serde_json::to_string(&debug_root).unwrap()
2393 }
2394
handle_debug_command(&mut self, command: DebugCommand)2395 fn handle_debug_command(&mut self, command: DebugCommand) {
2396 match command {
2397 DebugCommand::EnableDualSourceBlending(_) => {
2398 panic!("Should be handled by render backend");
2399 }
2400 DebugCommand::FetchDocuments |
2401 DebugCommand::FetchClipScrollTree => {}
2402 DebugCommand::FetchRenderTasks => {
2403 let json = self.get_render_tasks_for_debugger();
2404 self.debug_server.send(json);
2405 }
2406 DebugCommand::FetchPasses => {
2407 let json = self.get_passes_for_debugger();
2408 self.debug_server.send(json);
2409 }
2410 DebugCommand::FetchScreenshot => {
2411 let json = self.get_screenshot_for_debugger();
2412 self.debug_server.send(json);
2413 }
2414 DebugCommand::SaveCapture(..) |
2415 DebugCommand::LoadCapture(..) => {
2416 panic!("Capture commands are not welcome here! Did you build with 'capture' feature?")
2417 }
2418 DebugCommand::ClearCaches(_)
2419 | DebugCommand::SimulateLongSceneBuild(_)
2420 | DebugCommand::SimulateLongLowPrioritySceneBuild(_) => {}
2421 DebugCommand::InvalidateGpuCache => {
2422 match self.gpu_cache_texture.bus {
2423 GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
2424 info!("Invalidating GPU caches");
2425 for row in rows {
2426 row.is_dirty = true;
2427 }
2428 }
2429 GpuCacheBus::Scatter { .. } => {
2430 warn!("Unable to invalidate scattered GPU cache");
2431 }
2432 }
2433 }
2434 DebugCommand::SetFlags(flags) => {
2435 self.set_debug_flags(flags);
2436 }
2437 }
2438 }
2439
2440 /// Set a callback for handling external images.
set_external_image_handler(&mut self, handler: Box<ExternalImageHandler>)2441 pub fn set_external_image_handler(&mut self, handler: Box<ExternalImageHandler>) {
2442 self.external_image_handler = Some(handler);
2443 }
2444
2445 /// Set a callback for handling external outputs.
set_output_image_handler(&mut self, handler: Box<OutputImageHandler>)2446 pub fn set_output_image_handler(&mut self, handler: Box<OutputImageHandler>) {
2447 self.output_image_handler = Some(handler);
2448 }
2449
2450 /// Retrieve (and clear) the current list of recorded frame profiles.
get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>)2451 pub fn get_frame_profiles(&mut self) -> (Vec<CpuProfile>, Vec<GpuProfile>) {
2452 let cpu_profiles = self.cpu_profiles.drain(..).collect();
2453 let gpu_profiles = self.gpu_profiles.drain(..).collect();
2454 (cpu_profiles, gpu_profiles)
2455 }
2456
2457 /// Returns `true` if the active rendered documents (that need depth buffer)
2458 /// intersect on the main framebuffer, in which case we don't clear
2459 /// the whole depth and instead clear each document area separately.
are_documents_intersecting_depth(&self) -> bool2460 fn are_documents_intersecting_depth(&self) -> bool {
2461 let document_rects = self.active_documents
2462 .iter()
2463 .filter_map(|&(_, ref render_doc)| {
2464 match render_doc.frame.passes.last() {
2465 Some(&RenderPass { kind: RenderPassKind::MainFramebuffer(ref target), .. })
2466 if target.needs_depth() => Some(render_doc.frame.inner_rect),
2467 _ => None,
2468 }
2469 })
2470 .collect::<Vec<_>>();
2471
2472 for (i, rect) in document_rects.iter().enumerate() {
2473 for other in &document_rects[i+1 ..] {
2474 if rect.intersects(other) {
2475 return true
2476 }
2477 }
2478 }
2479
2480 false
2481 }
2482
notify_slow_frame(&mut self)2483 pub fn notify_slow_frame(&mut self) {
2484 self.slow_frame_indicator.changed();
2485 }
2486
2487 /// Renders the current frame.
2488 ///
2489 /// A Frame is supplied by calling [`generate_frame()`][webrender_api::Transaction::generate_frame].
render( &mut self, framebuffer_size: DeviceIntSize, ) -> Result<RenderResults, Vec<RendererError>>2490 pub fn render(
2491 &mut self,
2492 framebuffer_size: DeviceIntSize,
2493 ) -> Result<RenderResults, Vec<RendererError>> {
2494 self.framebuffer_size = Some(framebuffer_size);
2495
2496 let result = self.render_impl(Some(framebuffer_size));
2497
2498 drain_filter(
2499 &mut self.notifications,
2500 |n| { n.when() == Checkpoint::FrameRendered },
2501 |n| { n.notify(); },
2502 );
2503
2504 // This is the end of the rendering pipeline. If some notifications are is still there,
2505 // just clear them and they will autimatically fire the Checkpoint::TransactionDropped
2506 // event. Otherwise they would just pile up in this vector forever.
2507 self.notifications.clear();
2508
2509 result
2510 }
2511
2512 // If framebuffer_size is None, don't render
2513 // to the main frame buffer. This is useful
2514 // to update texture cache render tasks but
2515 // avoid doing a full frame render.
render_impl( &mut self, framebuffer_size: Option<DeviceIntSize>, ) -> Result<RenderResults, Vec<RendererError>>2516 fn render_impl(
2517 &mut self,
2518 framebuffer_size: Option<DeviceIntSize>,
2519 ) -> Result<RenderResults, Vec<RendererError>> {
2520 profile_scope!("render");
2521 let mut results = RenderResults::default();
2522 if self.active_documents.is_empty() {
2523 self.last_time = precise_time_ns();
2524 return Ok(results);
2525 }
2526
2527 let mut frame_profiles = Vec::new();
2528 let mut profile_timers = RendererProfileTimers::new();
2529
2530 let profile_samplers = {
2531 let _gm = self.gpu_profile.start_marker("build samples");
2532 // Block CPU waiting for last frame's GPU profiles to arrive.
2533 // In general this shouldn't block unless heavily GPU limited.
2534 let (gpu_frame_id, timers, samplers) = self.gpu_profile.build_samples();
2535
2536 if self.max_recorded_profiles > 0 {
2537 while self.gpu_profiles.len() >= self.max_recorded_profiles {
2538 self.gpu_profiles.pop_front();
2539 }
2540 self.gpu_profiles
2541 .push_back(GpuProfile::new(gpu_frame_id, &timers));
2542 }
2543 profile_timers.gpu_samples = timers;
2544 samplers
2545 };
2546
2547
2548 let cpu_frame_id = profile_timers.cpu_time.profile(|| {
2549 let _gm = self.gpu_profile.start_marker("begin frame");
2550 let frame_id = self.device.begin_frame();
2551 self.gpu_profile.begin_frame(frame_id);
2552
2553 self.device.disable_scissor();
2554 self.device.disable_depth();
2555 self.set_blend(false, FramebufferKind::Main);
2556 //self.update_shaders();
2557
2558 self.update_texture_cache();
2559
2560 frame_id
2561 });
2562
2563 profile_timers.cpu_time.profile(|| {
2564 let clear_depth_value = if self.are_documents_intersecting_depth() {
2565 None
2566 } else {
2567 Some(1.0)
2568 };
2569
2570 //Note: another borrowck dance
2571 let mut active_documents = mem::replace(&mut self.active_documents, Vec::default());
2572 // sort by the document layer id
2573 active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer);
2574
2575 // don't clear the framebuffer if one of the rendered documents will overwrite it
2576 if let Some(framebuffer_size) = framebuffer_size {
2577 let needs_color_clear = !active_documents
2578 .iter()
2579 .any(|&(_, RenderedDocument { ref frame, .. })| {
2580 frame.background_color.is_some() &&
2581 frame.inner_rect.origin == DeviceIntPoint::zero() &&
2582 frame.inner_rect.size == framebuffer_size
2583 });
2584
2585 if needs_color_clear || clear_depth_value.is_some() {
2586 let clear_color = if needs_color_clear {
2587 self.clear_color.map(|color| color.to_array())
2588 } else {
2589 None
2590 };
2591 self.device.reset_draw_target();
2592 self.device.enable_depth_write();
2593 self.device.clear_target(clear_color, clear_depth_value, None);
2594 self.device.disable_depth_write();
2595 }
2596 }
2597
2598 #[cfg(feature = "replay")]
2599 self.texture_resolver.external_images.extend(
2600 self.owned_external_images.iter().map(|(key, value)| (*key, value.clone()))
2601 );
2602
2603 for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents {
2604 frame.profile_counters.reset_targets();
2605 self.prepare_gpu_cache(frame);
2606 assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
2607 "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
2608 frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
2609
2610 self.draw_tile_frame(
2611 frame,
2612 framebuffer_size,
2613 clear_depth_value.is_some(),
2614 cpu_frame_id,
2615 &mut results.stats
2616 );
2617
2618 if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
2619 frame_profiles.push(frame.profile_counters.clone());
2620 }
2621
2622 let dirty_regions =
2623 mem::replace(&mut frame.recorded_dirty_regions, Vec::new());
2624 results.recorded_dirty_regions.extend(dirty_regions);
2625 }
2626
2627 self.unlock_external_images();
2628 self.active_documents = active_documents;
2629 });
2630
2631 let current_time = precise_time_ns();
2632 if framebuffer_size.is_some() {
2633 let ns = current_time - self.last_time;
2634 self.profile_counters.frame_time.set(ns);
2635 }
2636
2637 if self.max_recorded_profiles > 0 {
2638 while self.cpu_profiles.len() >= self.max_recorded_profiles {
2639 self.cpu_profiles.pop_front();
2640 }
2641 let cpu_profile = CpuProfile::new(
2642 cpu_frame_id,
2643 self.backend_profile_counters.total_time.get(),
2644 profile_timers.cpu_time.get(),
2645 self.profile_counters.draw_calls.get(),
2646 );
2647 self.cpu_profiles.push_back(cpu_profile);
2648 }
2649
2650 if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
2651 if let Some(framebuffer_size) = framebuffer_size {
2652 //TODO: take device/pixel ratio into equation?
2653 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
2654 let screen_fraction = 1.0 / framebuffer_size.to_f32().area();
2655 self.profiler.draw_profile(
2656 &frame_profiles,
2657 &self.backend_profile_counters,
2658 &self.profile_counters,
2659 &mut profile_timers,
2660 &profile_samplers,
2661 screen_fraction,
2662 debug_renderer,
2663 self.debug_flags.contains(DebugFlags::COMPACT_PROFILER),
2664 );
2665 }
2666 }
2667 }
2668
2669 let mut x = 0.0;
2670 if self.debug_flags.contains(DebugFlags::NEW_FRAME_INDICATOR) {
2671 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
2672 self.new_frame_indicator.changed();
2673 self.new_frame_indicator.draw(
2674 x, 0.0,
2675 ColorU::new(0, 110, 220, 255),
2676 debug_renderer,
2677 );
2678 x += ChangeIndicator::width();
2679 }
2680 }
2681
2682 if self.debug_flags.contains(DebugFlags::NEW_SCENE_INDICATOR) {
2683 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
2684 self.new_scene_indicator.draw(
2685 x, 0.0,
2686 ColorU::new(0, 220, 110, 255),
2687 debug_renderer,
2688 );
2689 x += ChangeIndicator::width();
2690 }
2691 }
2692
2693 if self.debug_flags.contains(DebugFlags::SLOW_FRAME_INDICATOR) {
2694 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
2695 self.slow_frame_indicator.draw(
2696 x, 0.0,
2697 ColorU::new(220, 30, 10, 255),
2698 debug_renderer,
2699 );
2700 }
2701 }
2702
2703 if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
2704 self.device.echo_driver_messages();
2705 }
2706
2707 results.stats.texture_upload_kb = self.profile_counters.texture_data_uploaded.get();
2708 self.backend_profile_counters.reset();
2709 self.profile_counters.reset();
2710 self.profile_counters.frame_counter.inc();
2711 results.stats.resource_upload_time = self.resource_upload_time;
2712 self.resource_upload_time = 0;
2713 results.stats.gpu_cache_upload_time = self.gpu_cache_upload_time;
2714 self.gpu_cache_upload_time = 0;
2715
2716 profile_timers.cpu_time.profile(|| {
2717 let _gm = self.gpu_profile.start_marker("end frame");
2718 self.gpu_profile.end_frame();
2719 if let Some(debug_renderer) = self.debug.try_get_mut() {
2720 debug_renderer.render(&mut self.device, framebuffer_size);
2721 }
2722 self.device.end_frame();
2723 });
2724 if framebuffer_size.is_some() {
2725 self.last_time = current_time;
2726 }
2727
2728 if self.renderer_errors.is_empty() {
2729 Ok(results)
2730 } else {
2731 Err(mem::replace(&mut self.renderer_errors, Vec::new()))
2732 }
2733 }
2734
update_gpu_cache(&mut self)2735 fn update_gpu_cache(&mut self) {
2736 let _gm = self.gpu_profile.start_marker("gpu cache update");
2737
2738 // For an artificial stress test of GPU cache resizing,
2739 // always pass an extra update list with at least one block in it.
2740 let gpu_cache_height = self.gpu_cache_texture.get_height();
2741 if gpu_cache_height != 0 && GPU_CACHE_RESIZE_TEST {
2742 self.pending_gpu_cache_updates.push(GpuCacheUpdateList {
2743 frame_id: FrameId::INVALID,
2744 clear: false,
2745 height: gpu_cache_height,
2746 blocks: vec![[1f32; 4].into()],
2747 updates: Vec::new(),
2748 debug_commands: Vec::new(),
2749 });
2750 }
2751
2752 let (updated_blocks, max_requested_height) = self
2753 .pending_gpu_cache_updates
2754 .iter()
2755 .fold((0, gpu_cache_height), |(count, height), list| {
2756 (count + list.blocks.len(), cmp::max(height, list.height))
2757 });
2758
2759 if max_requested_height > self.get_max_texture_size() && !self.gpu_cache_overflow {
2760 self.gpu_cache_overflow = true;
2761 self.renderer_errors.push(RendererError::MaxTextureSize);
2762 }
2763
2764 // Note: if we decide to switch to scatter-style GPU cache update
2765 // permanently, we can have this code nicer with `BufferUploader` kind
2766 // of helper, similarly to how `TextureUploader` API is used.
2767 self.gpu_cache_texture.prepare_for_updates(
2768 &mut self.device,
2769 updated_blocks,
2770 max_requested_height,
2771 );
2772
2773 for update_list in self.pending_gpu_cache_updates.drain(..) {
2774 assert!(update_list.height <= max_requested_height);
2775 if update_list.frame_id > self.gpu_cache_frame_id {
2776 self.gpu_cache_frame_id = update_list.frame_id
2777 }
2778 self.gpu_cache_texture
2779 .update(&mut self.device, &update_list);
2780 }
2781
2782 let mut upload_time = TimeProfileCounter::new("GPU cache upload time", false);
2783 let updated_rows = upload_time.profile(|| {
2784 return self.gpu_cache_texture.flush(&mut self.device);
2785 });
2786 self.gpu_cache_upload_time += upload_time.get();
2787
2788 let counters = &mut self.backend_profile_counters.resources.gpu_cache;
2789 counters.updated_rows.set(updated_rows);
2790 counters.updated_blocks.set(updated_blocks);
2791 }
2792
prepare_gpu_cache(&mut self, frame: &Frame)2793 fn prepare_gpu_cache(&mut self, frame: &Frame) {
2794 if self.pending_gpu_cache_clear {
2795 let use_scatter =
2796 matches!(self.gpu_cache_texture.bus, GpuCacheBus::Scatter { .. });
2797 let new_cache = GpuCacheTexture::new(&mut self.device, use_scatter).unwrap();
2798 let old_cache = mem::replace(&mut self.gpu_cache_texture, new_cache);
2799 old_cache.deinit(&mut self.device);
2800 self.pending_gpu_cache_clear = false;
2801 }
2802
2803 let deferred_update_list = self.update_deferred_resolves(&frame.deferred_resolves);
2804 self.pending_gpu_cache_updates.extend(deferred_update_list);
2805
2806 self.update_gpu_cache();
2807
2808 // Note: the texture might have changed during the `update`,
2809 // so we need to bind it here.
2810 self.device.bind_texture(
2811 TextureSampler::GpuCache,
2812 self.gpu_cache_texture.texture.as_ref().unwrap(),
2813 );
2814 }
2815
update_texture_cache(&mut self)2816 fn update_texture_cache(&mut self) {
2817 let _gm = self.gpu_profile.start_marker("texture cache update");
2818 let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
2819
2820 let mut upload_time = TimeProfileCounter::new("Resource upload time", false);
2821 upload_time.profile(|| {
2822 for update_list in pending_texture_updates.drain(..) {
2823 for allocation in update_list.allocations {
2824 let is_realloc = matches!(allocation.kind, TextureCacheAllocationKind::Realloc(..));
2825 match allocation.kind {
2826 TextureCacheAllocationKind::Alloc(info) |
2827 TextureCacheAllocationKind::Realloc(info) => {
2828 // Create a new native texture, as requested by the texture cache.
2829 //
2830 // Ensure no PBO is bound when creating the texture storage,
2831 // or GL will attempt to read data from there.
2832 let mut texture = self.device.create_texture(
2833 TextureTarget::Array,
2834 info.format,
2835 info.width,
2836 info.height,
2837 info.filter,
2838 // This needs to be a render target because some render
2839 // tasks get rendered into the texture cache.
2840 Some(RenderTargetInfo { has_depth: false }),
2841 info.layer_count,
2842 );
2843
2844 if info.is_shared_cache {
2845 texture.flags_mut()
2846 .insert(TextureFlags::IS_SHARED_TEXTURE_CACHE);
2847
2848 // Textures in the cache generally don't need to be cleared,
2849 // but we do so if the debug display is active to make it
2850 // easier to identify unallocated regions.
2851 if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
2852 self.clear_texture(&texture, TEXTURE_CACHE_DBG_CLEAR_COLOR);
2853 }
2854 }
2855
2856 let old = self.texture_resolver.texture_cache_map.insert(allocation.id, texture);
2857 assert_eq!(old.is_some(), is_realloc, "Renderer and RenderBackend disagree");
2858 if let Some(old) = old {
2859 self.device.blit_renderable_texture(
2860 self.texture_resolver.texture_cache_map.get_mut(&allocation.id).unwrap(),
2861 &old
2862 );
2863 self.device.delete_texture(old);
2864 }
2865 },
2866 TextureCacheAllocationKind::Free => {
2867 let texture = self.texture_resolver.texture_cache_map.remove(&allocation.id).unwrap();
2868 self.device.delete_texture(texture);
2869 },
2870 }
2871 }
2872
2873 for update in update_list.updates {
2874 let TextureCacheUpdate { id, rect, stride, offset, layer_index, source } = update;
2875 let texture = &self.texture_resolver.texture_cache_map[&id];
2876
2877 let bytes_uploaded = match source {
2878 TextureUpdateSource::Bytes { data } => {
2879 let mut uploader = self.device.upload_texture(
2880 texture,
2881 &self.texture_cache_upload_pbo,
2882 0,
2883 );
2884 uploader.upload(
2885 rect, layer_index, stride,
2886 &data[offset as usize ..],
2887 )
2888 }
2889 TextureUpdateSource::External { id, channel_index } => {
2890 let mut uploader = self.device.upload_texture(
2891 texture,
2892 &self.texture_cache_upload_pbo,
2893 0,
2894 );
2895 let handler = self.external_image_handler
2896 .as_mut()
2897 .expect("Found external image, but no handler set!");
2898 // The filter is only relevant for NativeTexture external images.
2899 let size = match handler.lock(id, channel_index, ImageRendering::Auto).source {
2900 ExternalImageSource::RawData(data) => {
2901 uploader.upload(
2902 rect, layer_index, stride,
2903 &data[offset as usize ..],
2904 )
2905 }
2906 ExternalImageSource::Invalid => {
2907 // Create a local buffer to fill the pbo.
2908 let bpp = texture.get_format().bytes_per_pixel();
2909 let width = stride.unwrap_or(rect.size.width * bpp);
2910 let total_size = width * rect.size.height;
2911 // WR haven't support RGBAF32 format in texture_cache, so
2912 // we use u8 type here.
2913 let dummy_data: Vec<u8> = vec![255; total_size as usize];
2914 uploader.upload(rect, layer_index, stride, &dummy_data)
2915 }
2916 ExternalImageSource::NativeTexture(eid) => {
2917 panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
2918 }
2919 };
2920 handler.unlock(id, channel_index);
2921 size
2922 }
2923 TextureUpdateSource::DebugClear => {
2924 self.device.bind_draw_target(DrawTarget::Texture {
2925 texture,
2926 layer: layer_index as usize,
2927 with_depth: false,
2928 });
2929 self.device.clear_target(
2930 Some(TEXTURE_CACHE_DBG_CLEAR_COLOR),
2931 None,
2932 Some(rect.to_i32())
2933 );
2934 0
2935 }
2936 };
2937 self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
2938 }
2939 }
2940
2941 drain_filter(
2942 &mut self.notifications,
2943 |n| { n.when() == Checkpoint::FrameTexturesUpdated },
2944 |n| { n.notify(); },
2945 );
2946 });
2947 self.resource_upload_time += upload_time.get();
2948 }
2949
draw_instanced_batch<T>( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, textures: &BatchTextures, stats: &mut RendererStats, )2950 pub(crate) fn draw_instanced_batch<T>(
2951 &mut self,
2952 data: &[T],
2953 vertex_array_kind: VertexArrayKind,
2954 textures: &BatchTextures,
2955 stats: &mut RendererStats,
2956 ) {
2957 for i in 0 .. textures.colors.len() {
2958 self.texture_resolver.bind(
2959 &textures.colors[i],
2960 TextureSampler::color(i),
2961 &mut self.device,
2962 );
2963 }
2964
2965 // TODO: this probably isn't the best place for this.
2966 if let Some(ref texture) = self.dither_matrix_texture {
2967 self.device.bind_texture(TextureSampler::Dither, texture);
2968 }
2969
2970 self.draw_instanced_batch_with_previously_bound_textures(data, vertex_array_kind, stats)
2971 }
2972
draw_instanced_batch_with_previously_bound_textures<T>( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, stats: &mut RendererStats, )2973 pub(crate) fn draw_instanced_batch_with_previously_bound_textures<T>(
2974 &mut self,
2975 data: &[T],
2976 vertex_array_kind: VertexArrayKind,
2977 stats: &mut RendererStats,
2978 ) {
2979 // If we end up with an empty draw call here, that means we have
2980 // probably introduced unnecessary batch breaks during frame
2981 // building - so we should be catching this earlier and removing
2982 // the batch.
2983 debug_assert!(!data.is_empty());
2984
2985 let vao = get_vao(vertex_array_kind, &self.vaos, &self.gpu_glyph_renderer);
2986
2987 self.device.bind_vao(vao);
2988
2989 let batched = !self.debug_flags.contains(DebugFlags::DISABLE_BATCHING);
2990
2991 if batched {
2992 self.device
2993 .update_vao_instances(vao, data, VertexUsageHint::Stream);
2994 self.device
2995 .draw_indexed_triangles_instanced_u16(6, data.len() as i32);
2996 self.profile_counters.draw_calls.inc();
2997 stats.total_draw_calls += 1;
2998 } else {
2999 for i in 0 .. data.len() {
3000 self.device
3001 .update_vao_instances(vao, &data[i .. i + 1], VertexUsageHint::Stream);
3002 self.device.draw_triangles_u16(0, 6);
3003 self.profile_counters.draw_calls.inc();
3004 stats.total_draw_calls += 1;
3005 }
3006 }
3007
3008 self.profile_counters.vertices.add(6 * data.len());
3009 }
3010
handle_readback_composite( &mut self, draw_target: DrawTarget, uses_scissor: bool, source: &RenderTask, backdrop: &RenderTask, readback: &RenderTask, )3011 fn handle_readback_composite(
3012 &mut self,
3013 draw_target: DrawTarget,
3014 uses_scissor: bool,
3015 source: &RenderTask,
3016 backdrop: &RenderTask,
3017 readback: &RenderTask,
3018 ) {
3019 if uses_scissor {
3020 self.device.disable_scissor();
3021 }
3022
3023 let cache_texture = self.texture_resolver
3024 .resolve(&TextureSource::PrevPassColor)
3025 .unwrap();
3026
3027 // Before submitting the composite batch, do the
3028 // framebuffer readbacks that are needed for each
3029 // composite operation in this batch.
3030 let (readback_rect, readback_layer) = readback.get_target_rect();
3031 let (backdrop_rect, _) = backdrop.get_target_rect();
3032 let backdrop_screen_origin = match backdrop.kind {
3033 RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
3034 _ => panic!("bug: composite on non-picture?"),
3035 };
3036 let source_screen_origin = match source.kind {
3037 RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
3038 _ => panic!("bug: composite on non-picture?"),
3039 };
3040
3041 // Bind the FBO to blit the backdrop to.
3042 // Called per-instance in case the layer (and therefore FBO)
3043 // changes. The device will skip the GL call if the requested
3044 // target is already bound.
3045 let cache_draw_target = DrawTarget::Texture {
3046 texture: cache_texture,
3047 layer: readback_layer.0 as usize,
3048 with_depth: false,
3049 };
3050 self.device.bind_draw_target(cache_draw_target);
3051
3052 let mut src = DeviceIntRect::new(
3053 source_screen_origin + (backdrop_rect.origin - backdrop_screen_origin),
3054 readback_rect.size,
3055 );
3056 let mut dest = readback_rect.to_i32();
3057
3058 // Need to invert the y coordinates and flip the image vertically when
3059 // reading back from the framebuffer.
3060 if draw_target.is_default() {
3061 src.origin.y = draw_target.dimensions().height as i32 - src.size.height - src.origin.y;
3062 dest.origin.y += dest.size.height;
3063 dest.size.height = -dest.size.height;
3064 }
3065
3066 self.device.bind_read_target(draw_target.into());
3067 self.device.blit_render_target(src, dest, TextureFilter::Linear);
3068
3069 // Restore draw target to current pass render target + layer, and reset
3070 // the read target.
3071 self.device.bind_draw_target(draw_target);
3072 self.device.reset_read_target();
3073
3074 if uses_scissor {
3075 self.device.enable_scissor();
3076 }
3077 }
3078
handle_blits( &mut self, blits: &[BlitJob], render_tasks: &RenderTaskTree, )3079 fn handle_blits(
3080 &mut self,
3081 blits: &[BlitJob],
3082 render_tasks: &RenderTaskTree,
3083 ) {
3084 if blits.is_empty() {
3085 return;
3086 }
3087
3088 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLIT);
3089
3090 // TODO(gw): For now, we don't bother batching these by source texture.
3091 // If if ever shows up as an issue, we can easily batch them.
3092 for blit in blits {
3093 let source_rect = match blit.source {
3094 BlitJobSource::Texture(texture_id, layer, source_rect) => {
3095 // A blit from a texture into this target.
3096 let texture = self.texture_resolver
3097 .resolve(&texture_id)
3098 .expect("BUG: invalid source texture");
3099 self.device.bind_read_target(ReadTarget::Texture { texture, layer: layer as usize });
3100 source_rect
3101 }
3102 BlitJobSource::RenderTask(task_id) => {
3103 // A blit from the child render task into this target.
3104 // TODO(gw): Support R8 format here once we start
3105 // creating mips for alpha masks.
3106 let texture = self.texture_resolver
3107 .resolve(&TextureSource::PrevPassColor)
3108 .expect("BUG: invalid source texture");
3109 let source = &render_tasks[task_id];
3110 let (source_rect, layer) = source.get_target_rect();
3111 self.device.bind_read_target(ReadTarget::Texture { texture, layer: layer.0 });
3112 source_rect
3113 }
3114 };
3115 debug_assert_eq!(source_rect.size, blit.target_rect.size);
3116 self.device.blit_render_target(
3117 source_rect,
3118 blit.target_rect,
3119 TextureFilter::Linear,
3120 );
3121 }
3122 }
3123
handle_scaling( &mut self, scalings: &[ScalingInstance], source: TextureSource, projection: &Transform3D<f32>, stats: &mut RendererStats, )3124 fn handle_scaling(
3125 &mut self,
3126 scalings: &[ScalingInstance],
3127 source: TextureSource,
3128 projection: &Transform3D<f32>,
3129 stats: &mut RendererStats,
3130 ) {
3131 if scalings.is_empty() {
3132 return
3133 }
3134
3135 let _timer = self.gpu_profile.start_timer(GPU_TAG_SCALE);
3136
3137 match source {
3138 TextureSource::PrevPassColor => {
3139 self.shaders.borrow_mut().cs_scale_rgba8.bind(&mut self.device,
3140 &projection,
3141 &mut self.renderer_errors);
3142 }
3143 TextureSource::PrevPassAlpha => {
3144 self.shaders.borrow_mut().cs_scale_a8.bind(&mut self.device,
3145 &projection,
3146 &mut self.renderer_errors);
3147 }
3148 _ => unreachable!(),
3149 }
3150
3151 self.draw_instanced_batch(
3152 &scalings,
3153 VertexArrayKind::Scale,
3154 &BatchTextures::no_texture(),
3155 stats,
3156 );
3157 }
3158
draw_color_target( &mut self, draw_target: DrawTarget, target: &ColorRenderTarget, framebuffer_target_rect: DeviceIntRect, depth_is_ready: bool, clear_color: Option<[f32; 4]>, render_tasks: &RenderTaskTree, projection: &Transform3D<f32>, frame_id: GpuFrameId, stats: &mut RendererStats, )3159 fn draw_color_target(
3160 &mut self,
3161 draw_target: DrawTarget,
3162 target: &ColorRenderTarget,
3163 framebuffer_target_rect: DeviceIntRect,
3164 depth_is_ready: bool,
3165 clear_color: Option<[f32; 4]>,
3166 render_tasks: &RenderTaskTree,
3167 projection: &Transform3D<f32>,
3168 frame_id: GpuFrameId,
3169 stats: &mut RendererStats,
3170 ) {
3171 self.profile_counters.color_targets.inc();
3172 let _gm = self.gpu_profile.start_marker("color target");
3173
3174 // sanity check for the depth buffer
3175 if let DrawTarget::Texture { texture, .. } = draw_target {
3176 assert!(texture.supports_depth() >= target.needs_depth());
3177 }
3178
3179 let framebuffer_kind = if draw_target.is_default() {
3180 FramebufferKind::Main
3181 } else {
3182 FramebufferKind::Other
3183 };
3184
3185 {
3186 let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
3187 self.device.bind_draw_target(draw_target);
3188 self.device.disable_depth();
3189 self.set_blend(false, framebuffer_kind);
3190
3191 let depth_clear = if !depth_is_ready && target.needs_depth() {
3192 self.device.enable_depth_write();
3193 Some(1.0)
3194 } else {
3195 None
3196 };
3197
3198 let clear_rect = if !draw_target.is_default() {
3199 if self.enable_clear_scissor {
3200 // TODO(gw): Applying a scissor rect and minimal clear here
3201 // is a very large performance win on the Intel and nVidia
3202 // GPUs that I have tested with. It's possible it may be a
3203 // performance penalty on other GPU types - we should test this
3204 // and consider different code paths.
3205 //
3206 // Note: The above measurements were taken when render
3207 // target slices were minimum 2048x2048. Now that we size
3208 // them adaptively, this may be less of a win (except perhaps
3209 // on a mostly-unused last slice of a large texture array).
3210 Some(target.used_rect())
3211 } else {
3212 None
3213 }
3214 } else if framebuffer_target_rect == DeviceIntRect::new(DeviceIntPoint::zero(), draw_target.dimensions()) {
3215 // whole screen is covered, no need for scissor
3216 None
3217 } else {
3218 let mut rect = framebuffer_target_rect.to_i32();
3219 // Note: `framebuffer_target_rect` needs a Y-flip before going to GL
3220 // Note: at this point, the target rectangle is not guaranteed to be within the main framebuffer bounds
3221 // but `clear_target_rect` is totally fine with negative origin, as long as width & height are positive
3222 rect.origin.y = draw_target.dimensions().height as i32 - rect.origin.y - rect.size.height;
3223 Some(rect)
3224 };
3225
3226 self.device.clear_target(clear_color, depth_clear, clear_rect);
3227
3228 if depth_clear.is_some() {
3229 self.device.disable_depth_write();
3230 }
3231 }
3232
3233 // Handle any blits from the texture cache to this target.
3234 self.handle_blits(&target.blits, render_tasks);
3235
3236 // Draw any blurs for this target.
3237 // Blurs are rendered as a standard 2-pass
3238 // separable implementation.
3239 // TODO(gw): In the future, consider having
3240 // fast path blur shaders for common
3241 // blur radii with fixed weights.
3242 if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
3243 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
3244
3245 self.set_blend(false, framebuffer_kind);
3246 self.shaders.borrow_mut().cs_blur_rgba8
3247 .bind(&mut self.device, projection, &mut self.renderer_errors);
3248
3249 if !target.vertical_blurs.is_empty() {
3250 self.draw_instanced_batch(
3251 &target.vertical_blurs,
3252 VertexArrayKind::Blur,
3253 &BatchTextures::no_texture(),
3254 stats,
3255 );
3256 }
3257
3258 if !target.horizontal_blurs.is_empty() {
3259 self.draw_instanced_batch(
3260 &target.horizontal_blurs,
3261 VertexArrayKind::Blur,
3262 &BatchTextures::no_texture(),
3263 stats,
3264 );
3265 }
3266 }
3267
3268 self.handle_scaling(&target.scalings, TextureSource::PrevPassColor, projection, stats);
3269
3270 // Small helper fn to iterate a regions list, also invoking the closure
3271 // if there are no regions.
iterate_regions<F>( regions: &[DeviceIntRect], mut f: F, ) where F: FnMut(Option<DeviceIntRect>)3272 fn iterate_regions<F>(
3273 regions: &[DeviceIntRect],
3274 mut f: F,
3275 ) where F: FnMut(Option<DeviceIntRect>) {
3276 if regions.is_empty() {
3277 f(None)
3278 } else {
3279 for region in regions {
3280 f(Some(*region))
3281 }
3282 }
3283 }
3284
3285 for alpha_batch_container in &target.alpha_batch_containers {
3286 let uses_scissor = alpha_batch_container.task_scissor_rect.is_some() ||
3287 !alpha_batch_container.regions.is_empty();
3288
3289 if uses_scissor {
3290 self.device.enable_scissor();
3291 let scissor_rect = draw_target.build_scissor_rect(
3292 alpha_batch_container.task_scissor_rect,
3293 framebuffer_target_rect,
3294 );
3295 self.device.set_scissor_rect(scissor_rect)
3296 }
3297
3298 if !alpha_batch_container.opaque_batches.is_empty() {
3299 let _gl = self.gpu_profile.start_marker("opaque batches");
3300 let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
3301 self.set_blend(false, framebuffer_kind);
3302 //Note: depth equality is needed for split planes
3303 self.device.set_depth_func(DepthFunction::LessEqual);
3304 self.device.enable_depth();
3305 self.device.enable_depth_write();
3306
3307 // Draw opaque batches front-to-back for maximum
3308 // z-buffer efficiency!
3309 for batch in alpha_batch_container
3310 .opaque_batches
3311 .iter()
3312 .rev()
3313 {
3314 self.shaders.borrow_mut()
3315 .get(&batch.key, self.debug_flags)
3316 .bind(
3317 &mut self.device, projection,
3318 &mut self.renderer_errors,
3319 );
3320
3321 let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
3322
3323 iterate_regions(
3324 &alpha_batch_container.regions,
3325 |region| {
3326 if let Some(region) = region {
3327 let scissor_rect = draw_target.build_scissor_rect(
3328 Some(region),
3329 framebuffer_target_rect,
3330 );
3331 self.device.set_scissor_rect(scissor_rect);
3332 }
3333
3334 self.draw_instanced_batch(
3335 &batch.instances,
3336 VertexArrayKind::Primitive,
3337 &batch.key.textures,
3338 stats
3339 );
3340 }
3341 );
3342 }
3343
3344 self.device.disable_depth_write();
3345 self.gpu_profile.finish_sampler(opaque_sampler);
3346 }
3347
3348 if !alpha_batch_container.alpha_batches.is_empty() {
3349 let _gl = self.gpu_profile.start_marker("alpha batches");
3350 let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
3351 self.set_blend(true, framebuffer_kind);
3352 let mut prev_blend_mode = BlendMode::None;
3353
3354 for batch in &alpha_batch_container.alpha_batches {
3355 self.shaders.borrow_mut()
3356 .get(&batch.key, self.debug_flags)
3357 .bind(
3358 &mut self.device, projection,
3359 &mut self.renderer_errors,
3360 );
3361
3362 if batch.key.blend_mode != prev_blend_mode {
3363 match batch.key.blend_mode {
3364 _ if self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) &&
3365 framebuffer_kind == FramebufferKind::Main => {
3366 self.device.set_blend_mode_show_overdraw();
3367 }
3368 BlendMode::None => {
3369 unreachable!("bug: opaque blend in alpha pass");
3370 }
3371 BlendMode::Alpha => {
3372 self.device.set_blend_mode_alpha();
3373 }
3374 BlendMode::PremultipliedAlpha => {
3375 self.device.set_blend_mode_premultiplied_alpha();
3376 }
3377 BlendMode::PremultipliedDestOut => {
3378 self.device.set_blend_mode_premultiplied_dest_out();
3379 }
3380 BlendMode::SubpixelDualSource => {
3381 self.device.set_blend_mode_subpixel_dual_source();
3382 }
3383 BlendMode::SubpixelConstantTextColor(color) => {
3384 self.device.set_blend_mode_subpixel_constant_text_color(color);
3385 }
3386 BlendMode::SubpixelWithBgColor => {
3387 // Using the three pass "component alpha with font smoothing
3388 // background color" rendering technique:
3389 //
3390 // /webrender/doc/text-rendering.md
3391 //
3392 self.device.set_blend_mode_subpixel_with_bg_color_pass0();
3393 self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
3394 }
3395 }
3396 prev_blend_mode = batch.key.blend_mode;
3397 }
3398
3399 // Handle special case readback for composites.
3400 if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = batch.key.kind {
3401 // composites can't be grouped together because
3402 // they may overlap and affect each other.
3403 debug_assert_eq!(batch.instances.len(), 1);
3404 self.handle_readback_composite(
3405 draw_target,
3406 uses_scissor,
3407 &render_tasks[source_id],
3408 &render_tasks[task_id],
3409 &render_tasks[backdrop_id],
3410 );
3411 }
3412
3413 let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
3414
3415 iterate_regions(
3416 &alpha_batch_container.regions,
3417 |region| {
3418 if let Some(region) = region {
3419 let scissor_rect = draw_target.build_scissor_rect(
3420 Some(region),
3421 framebuffer_target_rect,
3422 );
3423 self.device.set_scissor_rect(scissor_rect);
3424 }
3425
3426 self.draw_instanced_batch(
3427 &batch.instances,
3428 VertexArrayKind::Primitive,
3429 &batch.key.textures,
3430 stats
3431 );
3432
3433 if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
3434 self.set_blend_mode_subpixel_with_bg_color_pass1(framebuffer_kind);
3435 self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass1 as _);
3436
3437 // When drawing the 2nd and 3rd passes, we know that the VAO, textures etc
3438 // are all set up from the previous draw_instanced_batch call,
3439 // so just issue a draw call here to avoid re-uploading the
3440 // instances and re-binding textures etc.
3441 self.device
3442 .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
3443
3444 self.set_blend_mode_subpixel_with_bg_color_pass2(framebuffer_kind);
3445 self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _);
3446
3447 self.device
3448 .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
3449 }
3450 }
3451 );
3452
3453 if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
3454 prev_blend_mode = BlendMode::None;
3455 }
3456 }
3457
3458 self.device.disable_depth();
3459 self.set_blend(false, framebuffer_kind);
3460 self.gpu_profile.finish_sampler(transparent_sampler);
3461 }
3462
3463 if uses_scissor {
3464 self.device.disable_scissor();
3465 }
3466
3467 // At the end of rendering a container, blit across any cache tiles
3468 // to the texture cache for use on subsequent frames.
3469 if !alpha_batch_container.tile_blits.is_empty() {
3470 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLIT);
3471
3472 self.device.bind_read_target(draw_target.into());
3473
3474 for blit in &alpha_batch_container.tile_blits {
3475 let texture = self.texture_resolver
3476 .resolve(&blit.target.texture_id)
3477 .expect("BUG: invalid target texture");
3478
3479 self.device.bind_draw_target(DrawTarget::Texture {
3480 texture,
3481 layer: blit.target.texture_layer as usize,
3482 with_depth: false,
3483 });
3484
3485 let mut src_rect = DeviceIntRect::new(
3486 blit.src_offset,
3487 blit.size,
3488 );
3489
3490 let target_rect = blit.target.uv_rect.to_i32();
3491
3492 let mut dest_rect = DeviceIntRect::new(
3493 DeviceIntPoint::new(
3494 blit.dest_offset.x + target_rect.origin.x,
3495 blit.dest_offset.y + target_rect.origin.y,
3496 ),
3497 blit.size,
3498 );
3499
3500 // Modify the src/dest rects since we are blitting from the framebuffer
3501 src_rect.origin.y = draw_target.dimensions().height as i32 - src_rect.size.height - src_rect.origin.y;
3502 dest_rect.origin.y += dest_rect.size.height;
3503 dest_rect.size.height = -dest_rect.size.height;
3504
3505 self.device.blit_render_target(
3506 src_rect,
3507 dest_rect,
3508 TextureFilter::Linear,
3509 );
3510 }
3511
3512 self.device.bind_draw_target(draw_target);
3513 }
3514 }
3515
3516 // For any registered image outputs on this render target,
3517 // get the texture from caller and blit it.
3518 for output in &target.outputs {
3519 let handler = self.output_image_handler
3520 .as_mut()
3521 .expect("Found output image, but no handler set!");
3522 if let Some((texture_id, output_size)) = handler.lock(output.pipeline_id) {
3523 let fbo_id = match self.output_targets.entry(texture_id) {
3524 Entry::Vacant(entry) => {
3525 let fbo_id = self.device.create_fbo_for_external_texture(texture_id);
3526 entry.insert(FrameOutput {
3527 fbo_id,
3528 last_access: frame_id,
3529 });
3530 fbo_id
3531 }
3532 Entry::Occupied(mut entry) => {
3533 let target = entry.get_mut();
3534 target.last_access = frame_id;
3535 target.fbo_id
3536 }
3537 };
3538 let (src_rect, _) = render_tasks[output.task_id].get_target_rect();
3539 let mut dest_rect = DeviceIntRect::new(DeviceIntPoint::zero(), output_size);
3540
3541 // Invert Y coordinates, to correctly convert between coordinate systems.
3542 dest_rect.origin.y += dest_rect.size.height;
3543 dest_rect.size.height *= -1;
3544
3545 self.device.bind_read_target(draw_target.into());
3546 self.device.bind_external_draw_target(fbo_id);
3547 self.device.blit_render_target(src_rect, dest_rect, TextureFilter::Linear);
3548 handler.unlock(output.pipeline_id);
3549 }
3550 }
3551 }
3552
draw_alpha_target( &mut self, draw_target: DrawTarget, target: &AlphaRenderTarget, projection: &Transform3D<f32>, render_tasks: &RenderTaskTree, stats: &mut RendererStats, )3553 fn draw_alpha_target(
3554 &mut self,
3555 draw_target: DrawTarget,
3556 target: &AlphaRenderTarget,
3557 projection: &Transform3D<f32>,
3558 render_tasks: &RenderTaskTree,
3559 stats: &mut RendererStats,
3560 ) {
3561 self.profile_counters.alpha_targets.inc();
3562 let _gm = self.gpu_profile.start_marker("alpha target");
3563 let alpha_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_ALPHA);
3564
3565 {
3566 let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
3567 self.device.bind_draw_target(draw_target);
3568 self.device.disable_depth();
3569 self.device.disable_depth_write();
3570
3571 // TODO(gw): Applying a scissor rect and minimal clear here
3572 // is a very large performance win on the Intel and nVidia
3573 // GPUs that I have tested with. It's possible it may be a
3574 // performance penalty on other GPU types - we should test this
3575 // and consider different code paths.
3576 let clear_color = [1.0, 1.0, 1.0, 0.0];
3577 self.device.clear_target(
3578 Some(clear_color),
3579 None,
3580 Some(target.used_rect()),
3581 );
3582
3583 let zero_color = [0.0, 0.0, 0.0, 0.0];
3584 for &task_id in &target.zero_clears {
3585 let (rect, _) = render_tasks[task_id].get_target_rect();
3586 self.device.clear_target(
3587 Some(zero_color),
3588 None,
3589 Some(rect),
3590 );
3591 }
3592 }
3593
3594 // Draw any blurs for this target.
3595 // Blurs are rendered as a standard 2-pass
3596 // separable implementation.
3597 // TODO(gw): In the future, consider having
3598 // fast path blur shaders for common
3599 // blur radii with fixed weights.
3600 if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
3601 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
3602
3603 self.set_blend(false, FramebufferKind::Other);
3604 self.shaders.borrow_mut().cs_blur_a8
3605 .bind(&mut self.device, projection, &mut self.renderer_errors);
3606
3607 if !target.vertical_blurs.is_empty() {
3608 self.draw_instanced_batch(
3609 &target.vertical_blurs,
3610 VertexArrayKind::Blur,
3611 &BatchTextures::no_texture(),
3612 stats,
3613 );
3614 }
3615
3616 if !target.horizontal_blurs.is_empty() {
3617 self.draw_instanced_batch(
3618 &target.horizontal_blurs,
3619 VertexArrayKind::Blur,
3620 &BatchTextures::no_texture(),
3621 stats,
3622 );
3623 }
3624 }
3625
3626 self.handle_scaling(&target.scalings, TextureSource::PrevPassAlpha, projection, stats);
3627
3628 // Draw the clip items into the tiled alpha mask.
3629 {
3630 let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_CLIP);
3631
3632 // switch to multiplicative blending
3633 self.set_blend(true, FramebufferKind::Other);
3634 self.set_blend_mode_multiply(FramebufferKind::Other);
3635
3636 // draw rounded cornered rectangles
3637 if !target.clip_batcher.rectangles.is_empty() {
3638 let _gm2 = self.gpu_profile.start_marker("clip rectangles");
3639 self.shaders.borrow_mut().cs_clip_rectangle.bind(
3640 &mut self.device,
3641 projection,
3642 &mut self.renderer_errors,
3643 );
3644 self.draw_instanced_batch(
3645 &target.clip_batcher.rectangles,
3646 VertexArrayKind::Clip,
3647 &BatchTextures::no_texture(),
3648 stats,
3649 );
3650 }
3651 // draw box-shadow clips
3652 for (mask_texture_id, items) in target.clip_batcher.box_shadows.iter() {
3653 let _gm2 = self.gpu_profile.start_marker("box-shadows");
3654 let textures = BatchTextures {
3655 colors: [
3656 mask_texture_id.clone(),
3657 TextureSource::Invalid,
3658 TextureSource::Invalid,
3659 ],
3660 };
3661 self.shaders.borrow_mut().cs_clip_box_shadow
3662 .bind(&mut self.device, projection, &mut self.renderer_errors);
3663 self.draw_instanced_batch(
3664 items,
3665 VertexArrayKind::Clip,
3666 &textures,
3667 stats,
3668 );
3669 }
3670
3671 // draw image masks
3672 for (mask_texture_id, items) in target.clip_batcher.images.iter() {
3673 let _gm2 = self.gpu_profile.start_marker("clip images");
3674 let textures = BatchTextures {
3675 colors: [
3676 mask_texture_id.clone(),
3677 TextureSource::Invalid,
3678 TextureSource::Invalid,
3679 ],
3680 };
3681 self.shaders.borrow_mut().cs_clip_image
3682 .bind(&mut self.device, projection, &mut self.renderer_errors);
3683 self.draw_instanced_batch(
3684 items,
3685 VertexArrayKind::Clip,
3686 &textures,
3687 stats,
3688 );
3689 }
3690 }
3691
3692 self.gpu_profile.finish_sampler(alpha_sampler);
3693 }
3694
draw_texture_cache_target( &mut self, texture: &CacheTextureId, layer: LayerIndex, target: &TextureCacheRenderTarget, render_tasks: &RenderTaskTree, stats: &mut RendererStats, )3695 fn draw_texture_cache_target(
3696 &mut self,
3697 texture: &CacheTextureId,
3698 layer: LayerIndex,
3699 target: &TextureCacheRenderTarget,
3700 render_tasks: &RenderTaskTree,
3701 stats: &mut RendererStats,
3702 ) {
3703 let texture_source = TextureSource::TextureCache(*texture);
3704 let (target_size, projection) = {
3705 let texture = self.texture_resolver
3706 .resolve(&texture_source)
3707 .expect("BUG: invalid target texture");
3708 let target_size = texture.get_dimensions();
3709 let projection = Transform3D::ortho(
3710 0.0,
3711 target_size.width as f32,
3712 0.0,
3713 target_size.height as f32,
3714 ORTHO_NEAR_PLANE,
3715 ORTHO_FAR_PLANE,
3716 );
3717 (target_size, projection)
3718 };
3719
3720 self.device.disable_depth();
3721 self.device.disable_depth_write();
3722
3723 self.set_blend(false, FramebufferKind::Other);
3724
3725 // Handle any Pathfinder glyphs.
3726 let stencil_page = self.stencil_glyphs(&target.glyphs, &projection, &target_size, stats);
3727
3728 {
3729 let texture = self.texture_resolver
3730 .resolve(&texture_source)
3731 .expect("BUG: invalid target texture");
3732 self.device.bind_draw_target(DrawTarget::Texture {
3733 texture,
3734 layer,
3735 with_depth: false,
3736 });
3737 }
3738
3739 self.device.disable_depth();
3740 self.device.disable_depth_write();
3741 self.set_blend(false, FramebufferKind::Other);
3742
3743 for rect in &target.clears {
3744 self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, Some(*rect));
3745 }
3746
3747 // Handle any blits to this texture from child tasks.
3748 self.handle_blits(&target.blits, render_tasks);
3749
3750 // Draw any borders for this target.
3751 if !target.border_segments_solid.is_empty() ||
3752 !target.border_segments_complex.is_empty()
3753 {
3754 let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_BORDER);
3755
3756 self.set_blend(true, FramebufferKind::Other);
3757 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
3758
3759 if !target.border_segments_solid.is_empty() {
3760 self.shaders.borrow_mut().cs_border_solid.bind(
3761 &mut self.device,
3762 &projection,
3763 &mut self.renderer_errors,
3764 );
3765
3766 self.draw_instanced_batch(
3767 &target.border_segments_solid,
3768 VertexArrayKind::Border,
3769 &BatchTextures::no_texture(),
3770 stats,
3771 );
3772 }
3773
3774 if !target.border_segments_complex.is_empty() {
3775 self.shaders.borrow_mut().cs_border_segment.bind(
3776 &mut self.device,
3777 &projection,
3778 &mut self.renderer_errors,
3779 );
3780
3781 self.draw_instanced_batch(
3782 &target.border_segments_complex,
3783 VertexArrayKind::Border,
3784 &BatchTextures::no_texture(),
3785 stats,
3786 );
3787 }
3788
3789 self.set_blend(false, FramebufferKind::Other);
3790 }
3791
3792 // Draw any line decorations for this target.
3793 if !target.line_decorations.is_empty() {
3794 let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_LINE_DECORATION);
3795
3796 self.set_blend(true, FramebufferKind::Other);
3797 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
3798
3799 if !target.line_decorations.is_empty() {
3800 self.shaders.borrow_mut().cs_line_decoration.bind(
3801 &mut self.device,
3802 &projection,
3803 &mut self.renderer_errors,
3804 );
3805
3806 self.draw_instanced_batch(
3807 &target.line_decorations,
3808 VertexArrayKind::LineDecoration,
3809 &BatchTextures::no_texture(),
3810 stats,
3811 );
3812 }
3813
3814 self.set_blend(false, FramebufferKind::Other);
3815 }
3816
3817 // Draw any blurs for this target.
3818 if !target.horizontal_blurs.is_empty() {
3819 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
3820
3821 {
3822 let mut shaders = self.shaders.borrow_mut();
3823 match target.target_kind {
3824 RenderTargetKind::Alpha => &mut shaders.cs_blur_a8,
3825 RenderTargetKind::Color => &mut shaders.cs_blur_rgba8,
3826 }.bind(&mut self.device, &projection, &mut self.renderer_errors);
3827 }
3828
3829 self.draw_instanced_batch(
3830 &target.horizontal_blurs,
3831 VertexArrayKind::Blur,
3832 &BatchTextures::no_texture(),
3833 stats,
3834 );
3835 }
3836
3837 // Blit any Pathfinder glyphs to the cache texture.
3838 if let Some(stencil_page) = stencil_page {
3839 self.cover_glyphs(stencil_page, &projection, stats);
3840 }
3841 }
3842
3843 #[cfg(not(feature = "pathfinder"))]
stencil_glyphs(&mut self, _: &[GlyphJob], _: &Transform3D<f32>, _: &DeviceIntSize, _: &mut RendererStats) -> Option<StenciledGlyphPage>3844 fn stencil_glyphs(&mut self,
3845 _: &[GlyphJob],
3846 _: &Transform3D<f32>,
3847 _: &DeviceIntSize,
3848 _: &mut RendererStats)
3849 -> Option<StenciledGlyphPage> {
3850 None
3851 }
3852
3853 #[cfg(not(feature = "pathfinder"))]
cover_glyphs(&mut self, _: StenciledGlyphPage, _: &Transform3D<f32>, _: &mut RendererStats)3854 fn cover_glyphs(&mut self,
3855 _: StenciledGlyphPage,
3856 _: &Transform3D<f32>,
3857 _: &mut RendererStats) {}
3858
update_deferred_resolves(&mut self, deferred_resolves: &[DeferredResolve]) -> Option<GpuCacheUpdateList>3859 fn update_deferred_resolves(&mut self, deferred_resolves: &[DeferredResolve]) -> Option<GpuCacheUpdateList> {
3860 // The first thing we do is run through any pending deferred
3861 // resolves, and use a callback to get the UV rect for this
3862 // custom item. Then we patch the resource_rects structure
3863 // here before it's uploaded to the GPU.
3864 if deferred_resolves.is_empty() {
3865 return None;
3866 }
3867
3868 let handler = self.external_image_handler
3869 .as_mut()
3870 .expect("Found external image, but no handler set!");
3871
3872 let mut list = GpuCacheUpdateList {
3873 frame_id: FrameId::INVALID,
3874 clear: false,
3875 height: self.gpu_cache_texture.get_height(),
3876 blocks: Vec::new(),
3877 updates: Vec::new(),
3878 debug_commands: Vec::new(),
3879 };
3880
3881 for deferred_resolve in deferred_resolves {
3882 self.gpu_profile.place_marker("deferred resolve");
3883 let props = &deferred_resolve.image_properties;
3884 let ext_image = props
3885 .external_image
3886 .expect("BUG: Deferred resolves must be external images!");
3887 // Provide rendering information for NativeTexture external images.
3888 let image = handler.lock(ext_image.id, ext_image.channel_index, deferred_resolve.rendering);
3889 let texture_target = match ext_image.image_type {
3890 ExternalImageType::TextureHandle(target) => target,
3891 ExternalImageType::Buffer => {
3892 panic!("not a suitable image type in update_deferred_resolves()");
3893 }
3894 };
3895
3896 // In order to produce the handle, the external image handler may call into
3897 // the GL context and change some states.
3898 self.device.reset_state();
3899
3900 let texture = match image.source {
3901 ExternalImageSource::NativeTexture(texture_id) => {
3902 ExternalTexture::new(texture_id, texture_target)
3903 }
3904 ExternalImageSource::Invalid => {
3905 warn!("Invalid ext-image");
3906 debug!(
3907 "For ext_id:{:?}, channel:{}.",
3908 ext_image.id,
3909 ext_image.channel_index
3910 );
3911 // Just use 0 as the gl handle for this failed case.
3912 ExternalTexture::new(0, texture_target)
3913 }
3914 ExternalImageSource::RawData(_) => {
3915 panic!("Raw external data is not expected for deferred resolves!");
3916 }
3917 };
3918
3919 self.texture_resolver
3920 .external_images
3921 .insert((ext_image.id, ext_image.channel_index), texture);
3922
3923 list.updates.push(GpuCacheUpdate::Copy {
3924 block_index: list.blocks.len(),
3925 block_count: BLOCKS_PER_UV_RECT,
3926 address: deferred_resolve.address,
3927 });
3928 list.blocks.push(image.uv.into());
3929 list.blocks.push([0f32; 4].into());
3930 }
3931
3932 Some(list)
3933 }
3934
unlock_external_images(&mut self)3935 fn unlock_external_images(&mut self) {
3936 if !self.texture_resolver.external_images.is_empty() {
3937 let handler = self.external_image_handler
3938 .as_mut()
3939 .expect("Found external image, but no handler set!");
3940
3941 for (ext_data, _) in self.texture_resolver.external_images.drain() {
3942 handler.unlock(ext_data.0, ext_data.1);
3943 }
3944 }
3945 }
3946
3947 /// Allocates a texture to be used as the output for a rendering pass.
3948 ///
3949 /// We make an effort to reuse render targe textures across passes and
3950 /// across frames when the format and dimensions match. Because we use
3951 /// immutable storage, we can't resize textures.
3952 ///
3953 /// We could consider approaches to re-use part of a larger target, if
3954 /// available. However, we'd need to be careful about eviction. Currently,
3955 /// render targets are freed if they haven't been used in 30 frames. If we
3956 /// used partial targets, we'd need to track how _much_ of the target has
3957 /// been used in the last 30 frames, since we could otherwise end up
3958 /// keeping an enormous target alive indefinitely by constantly using it
3959 /// in situations where a much smaller target would suffice.
allocate_target_texture<T: RenderTarget>( &mut self, list: &mut RenderTargetList<T>, counters: &mut FrameProfileCounters, ) -> Option<ActiveTexture>3960 fn allocate_target_texture<T: RenderTarget>(
3961 &mut self,
3962 list: &mut RenderTargetList<T>,
3963 counters: &mut FrameProfileCounters,
3964 ) -> Option<ActiveTexture> {
3965 if list.targets.is_empty() {
3966 return None
3967 }
3968
3969 // Get a bounding rect of all the layers, and round it up to a multiple
3970 // of 256. This improves render target reuse when resizing the window,
3971 // since we don't need to create a new render target for each slightly-
3972 // larger frame.
3973 let mut bounding_rect = DeviceIntRect::zero();
3974 for t in list.targets.iter() {
3975 bounding_rect = t.used_rect().union(&bounding_rect);
3976 }
3977 debug_assert_eq!(bounding_rect.origin, DeviceIntPoint::zero());
3978 let dimensions = DeviceIntSize::new(
3979 (bounding_rect.size.width + 255) & !255,
3980 (bounding_rect.size.height + 255) & !255,
3981 );
3982
3983 counters.targets_used.inc();
3984
3985 // Try finding a match in the existing pool. If there's no match, we'll
3986 // create a new texture.
3987 let selector = TargetSelector {
3988 size: dimensions,
3989 num_layers: list.targets.len(),
3990 format: list.format,
3991 };
3992 let index = self.texture_resolver.render_target_pool
3993 .iter()
3994 .position(|texture| {
3995 selector == TargetSelector {
3996 size: texture.get_dimensions(),
3997 num_layers: texture.get_layer_count() as usize,
3998 format: texture.get_format(),
3999 }
4000 });
4001
4002 let rt_info = RenderTargetInfo { has_depth: list.needs_depth() };
4003 let texture = if let Some(idx) = index {
4004 let mut t = self.texture_resolver.render_target_pool.swap_remove(idx);
4005 self.device.reuse_render_target::<u8>(&mut t, rt_info);
4006 t
4007 } else {
4008 counters.targets_created.inc();
4009 self.device.create_texture(
4010 TextureTarget::Array,
4011 list.format,
4012 dimensions.width,
4013 dimensions.height,
4014 TextureFilter::Linear,
4015 Some(rt_info),
4016 list.targets.len() as _,
4017 )
4018 };
4019
4020 list.check_ready(&texture);
4021 Some(ActiveTexture {
4022 texture,
4023 saved_index: list.saved_index.clone(),
4024 })
4025 }
4026
bind_frame_data(&mut self, frame: &mut Frame)4027 fn bind_frame_data(&mut self, frame: &mut Frame) {
4028 let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
4029 self.device.set_device_pixel_ratio(frame.device_pixel_ratio);
4030
4031 self.prim_header_f_texture.update(
4032 &mut self.device,
4033 &mut frame.prim_headers.headers_float,
4034 );
4035 self.device.bind_texture(
4036 TextureSampler::PrimitiveHeadersF,
4037 &self.prim_header_f_texture.texture(),
4038 );
4039
4040 self.prim_header_i_texture.update(
4041 &mut self.device,
4042 &mut frame.prim_headers.headers_int,
4043 );
4044 self.device.bind_texture(
4045 TextureSampler::PrimitiveHeadersI,
4046 &self.prim_header_i_texture.texture(),
4047 );
4048
4049 self.transforms_texture.update(
4050 &mut self.device,
4051 &mut frame.transform_palette,
4052 );
4053 self.device.bind_texture(
4054 TextureSampler::TransformPalette,
4055 &self.transforms_texture.texture(),
4056 );
4057
4058 self.render_task_texture
4059 .update(&mut self.device, &mut frame.render_tasks.task_data);
4060 self.device.bind_texture(
4061 TextureSampler::RenderTasks,
4062 &self.render_task_texture.texture(),
4063 );
4064
4065 debug_assert!(self.texture_resolver.prev_pass_alpha.is_none());
4066 debug_assert!(self.texture_resolver.prev_pass_color.is_none());
4067 }
4068
draw_tile_frame( &mut self, frame: &mut Frame, framebuffer_size: Option<DeviceIntSize>, framebuffer_depth_is_ready: bool, frame_id: GpuFrameId, stats: &mut RendererStats, )4069 fn draw_tile_frame(
4070 &mut self,
4071 frame: &mut Frame,
4072 framebuffer_size: Option<DeviceIntSize>,
4073 framebuffer_depth_is_ready: bool,
4074 frame_id: GpuFrameId,
4075 stats: &mut RendererStats,
4076 ) {
4077 let _gm = self.gpu_profile.start_marker("tile frame draw");
4078
4079 if frame.passes.is_empty() {
4080 frame.has_been_rendered = true;
4081 return;
4082 }
4083
4084 self.device.disable_depth_write();
4085 self.set_blend(false, FramebufferKind::Other);
4086 self.device.disable_stencil();
4087
4088 self.bind_frame_data(frame);
4089 self.texture_resolver.begin_frame();
4090
4091 for (pass_index, pass) in frame.passes.iter_mut().enumerate() {
4092 let _gm = self.gpu_profile.start_marker(&format!("pass {}", pass_index));
4093
4094 self.texture_resolver.bind(
4095 &TextureSource::PrevPassAlpha,
4096 TextureSampler::PrevPassAlpha,
4097 &mut self.device,
4098 );
4099 self.texture_resolver.bind(
4100 &TextureSource::PrevPassColor,
4101 TextureSampler::PrevPassColor,
4102 &mut self.device,
4103 );
4104
4105 let (cur_alpha, cur_color) = match pass.kind {
4106 RenderPassKind::MainFramebuffer(ref target) => {
4107 if let Some(framebuffer_size) = framebuffer_size {
4108 stats.color_target_count += 1;
4109
4110 let clear_color = frame.background_color.map(|color| color.to_array());
4111 let projection = Transform3D::ortho(
4112 0.0,
4113 framebuffer_size.width as f32,
4114 framebuffer_size.height as f32,
4115 0.0,
4116 ORTHO_NEAR_PLANE,
4117 ORTHO_FAR_PLANE,
4118 );
4119
4120 self.draw_color_target(
4121 DrawTarget::Default(framebuffer_size),
4122 target,
4123 frame.inner_rect,
4124 framebuffer_depth_is_ready,
4125 clear_color,
4126 &frame.render_tasks,
4127 &projection,
4128 frame_id,
4129 stats,
4130 );
4131 }
4132
4133 (None, None)
4134 }
4135 RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => {
4136 let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters);
4137 let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters);
4138
4139 // If this frame has already been drawn, then any texture
4140 // cache targets have already been updated and can be
4141 // skipped this time.
4142 if !frame.has_been_rendered {
4143 for (&(texture_id, target_index), target) in texture_cache {
4144 self.draw_texture_cache_target(
4145 &texture_id,
4146 target_index,
4147 target,
4148 &frame.render_tasks,
4149 stats,
4150 );
4151 }
4152 }
4153
4154 for (target_index, target) in alpha.targets.iter().enumerate() {
4155 stats.alpha_target_count += 1;
4156 let draw_target = DrawTarget::Texture {
4157 texture: &alpha_tex.as_ref().unwrap().texture,
4158 layer: target_index,
4159 with_depth: false,
4160 };
4161
4162 let projection = Transform3D::ortho(
4163 0.0,
4164 draw_target.dimensions().width as f32,
4165 0.0,
4166 draw_target.dimensions().height as f32,
4167 ORTHO_NEAR_PLANE,
4168 ORTHO_FAR_PLANE,
4169 );
4170
4171 self.draw_alpha_target(
4172 draw_target,
4173 target,
4174 &projection,
4175 &frame.render_tasks,
4176 stats,
4177 );
4178 }
4179
4180 for (target_index, target) in color.targets.iter().enumerate() {
4181 stats.color_target_count += 1;
4182 let draw_target = DrawTarget::Texture {
4183 texture: &color_tex.as_ref().unwrap().texture,
4184 layer: target_index,
4185 with_depth: target.needs_depth(),
4186 };
4187
4188 let projection = Transform3D::ortho(
4189 0.0,
4190 draw_target.dimensions().width as f32,
4191 0.0,
4192 draw_target.dimensions().height as f32,
4193 ORTHO_NEAR_PLANE,
4194 ORTHO_FAR_PLANE,
4195 );
4196
4197 self.draw_color_target(
4198 draw_target,
4199 target,
4200 frame.inner_rect,
4201 false,
4202 Some([0.0, 0.0, 0.0, 0.0]),
4203 &frame.render_tasks,
4204 &projection,
4205 frame_id,
4206 stats,
4207 );
4208 }
4209
4210 (alpha_tex, color_tex)
4211 }
4212 };
4213
4214 self.texture_resolver.end_pass(
4215 &mut self.device,
4216 cur_alpha,
4217 cur_color,
4218 );
4219 }
4220
4221 self.texture_resolver.end_frame(&mut self.device, frame_id);
4222
4223 if let Some(framebuffer_size) = framebuffer_size {
4224 self.draw_frame_debug_items(&frame.debug_items);
4225 self.draw_render_target_debug(framebuffer_size);
4226 self.draw_texture_cache_debug(framebuffer_size);
4227 self.draw_gpu_cache_debug(framebuffer_size);
4228 self.draw_zoom_debug(framebuffer_size);
4229 }
4230 self.draw_epoch_debug();
4231
4232 // Garbage collect any frame outputs that weren't used this frame.
4233 let device = &mut self.device;
4234 self.output_targets
4235 .retain(|_, target| if target.last_access != frame_id {
4236 device.delete_fbo(target.fbo_id);
4237 false
4238 } else {
4239 true
4240 });
4241
4242 frame.has_been_rendered = true;
4243 }
4244
debug_renderer<'b>(&'b mut self) -> Option<&'b mut DebugRenderer>4245 pub fn debug_renderer<'b>(&'b mut self) -> Option<&'b mut DebugRenderer> {
4246 self.debug.get_mut(&mut self.device)
4247 }
4248
get_debug_flags(&self) -> DebugFlags4249 pub fn get_debug_flags(&self) -> DebugFlags {
4250 self.debug_flags
4251 }
4252
set_debug_flags(&mut self, flags: DebugFlags)4253 pub fn set_debug_flags(&mut self, flags: DebugFlags) {
4254 if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_TIME_QUERIES) {
4255 if enabled {
4256 self.gpu_profile.enable_timers();
4257 } else {
4258 self.gpu_profile.disable_timers();
4259 }
4260 }
4261 if let Some(enabled) = flag_changed(self.debug_flags, flags, DebugFlags::GPU_SAMPLE_QUERIES) {
4262 if enabled {
4263 self.gpu_profile.enable_samplers();
4264 } else {
4265 self.gpu_profile.disable_samplers();
4266 }
4267 }
4268
4269 self.debug_flags = flags;
4270 }
4271
save_cpu_profile(&self, filename: &str)4272 pub fn save_cpu_profile(&self, filename: &str) {
4273 write_profile(filename);
4274 }
4275
draw_frame_debug_items(&mut self, items: &[DebugItem])4276 fn draw_frame_debug_items(&mut self, items: &[DebugItem]) {
4277 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4278 Some(render) => render,
4279 None => return,
4280 };
4281
4282 for item in items {
4283 match item {
4284 DebugItem::Rect { rect, color } => {
4285 let inner_color = color.scale_alpha(0.5).into();
4286 let outer_color = (*color).into();
4287
4288 debug_renderer.add_quad(
4289 rect.origin.x,
4290 rect.origin.y,
4291 rect.origin.x + rect.size.width,
4292 rect.origin.y + rect.size.height,
4293 inner_color,
4294 inner_color,
4295 );
4296
4297 debug_renderer.add_rect(
4298 &rect.to_i32(),
4299 outer_color,
4300 );
4301 }
4302 DebugItem::Text { ref msg, position, color } => {
4303 debug_renderer.add_text(
4304 position.x,
4305 position.y,
4306 msg,
4307 (*color).into(),
4308 None,
4309 );
4310 }
4311 }
4312 }
4313 }
4314
draw_render_target_debug(&mut self, framebuffer_size: DeviceIntSize)4315 fn draw_render_target_debug(&mut self, framebuffer_size: DeviceIntSize) {
4316 if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
4317 return;
4318 }
4319
4320 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4321 Some(render) => render,
4322 None => return,
4323 };
4324
4325 let textures =
4326 self.texture_resolver.render_target_pool.iter().collect::<Vec<&Texture>>();
4327
4328 Self::do_debug_blit(
4329 &mut self.device,
4330 debug_renderer,
4331 textures,
4332 framebuffer_size,
4333 0,
4334 &|_| [0.0, 1.0, 0.0, 1.0], // Use green for all RTs.
4335 );
4336 }
4337
draw_zoom_debug( &mut self, framebuffer_size: DeviceIntSize, )4338 fn draw_zoom_debug(
4339 &mut self,
4340 framebuffer_size: DeviceIntSize,
4341 ) {
4342 if !self.debug_flags.contains(DebugFlags::ZOOM_DBG) {
4343 return;
4344 }
4345
4346 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4347 Some(render) => render,
4348 None => return,
4349 };
4350
4351 let source_size = DeviceIntSize::new(64, 64);
4352 let target_size = DeviceIntSize::new(1024, 1024);
4353
4354 let source_origin = DeviceIntPoint::new(
4355 (self.cursor_position.x - source_size.width / 2)
4356 .min(framebuffer_size.width - source_size.width)
4357 .max(0),
4358 (self.cursor_position.y - source_size.height / 2)
4359 .min(framebuffer_size.height - source_size.height)
4360 .max(0),
4361 );
4362
4363 let source_rect = DeviceIntRect::new(
4364 source_origin,
4365 source_size,
4366 );
4367
4368 let target_rect = DeviceIntRect::new(
4369 DeviceIntPoint::new(
4370 framebuffer_size.width - target_size.width - 64,
4371 framebuffer_size.height - target_size.height - 64,
4372 ),
4373 target_size,
4374 );
4375
4376 let texture_rect = DeviceIntRect::new(
4377 DeviceIntPoint::zero(),
4378 source_rect.size,
4379 );
4380
4381 debug_renderer.add_rect(
4382 &target_rect.inflate(1, 1),
4383 debug_colors::RED.into(),
4384 );
4385
4386 if self.zoom_debug_texture.is_none() {
4387 let texture = self.device.create_texture(
4388 TextureTarget::Default,
4389 ImageFormat::BGRA8,
4390 source_rect.size.width,
4391 source_rect.size.height,
4392 TextureFilter::Nearest,
4393 Some(RenderTargetInfo { has_depth: false }),
4394 1,
4395 );
4396
4397 self.zoom_debug_texture = Some(texture);
4398 }
4399
4400 // Copy frame buffer into the zoom texture
4401 self.device.bind_read_target(ReadTarget::Default);
4402 self.device.bind_draw_target(DrawTarget::Texture {
4403 texture: self.zoom_debug_texture.as_ref().unwrap(),
4404 layer: 0,
4405 with_depth: false,
4406 });
4407 self.device.blit_render_target(
4408 DeviceIntRect::new(
4409 DeviceIntPoint::new(
4410 source_rect.origin.x,
4411 framebuffer_size.height - source_rect.size.height - source_rect.origin.y,
4412 ),
4413 source_rect.size,
4414 ),
4415 texture_rect,
4416 TextureFilter::Nearest,
4417 );
4418
4419 // Draw the zoom texture back to the framebuffer
4420 self.device.bind_read_target(ReadTarget::Texture {
4421 texture: self.zoom_debug_texture.as_ref().unwrap(),
4422 layer: 0,
4423 });
4424 self.device.bind_draw_target(DrawTarget::Default(framebuffer_size));
4425 self.device.blit_render_target(
4426 texture_rect,
4427 DeviceIntRect::new(
4428 DeviceIntPoint::new(
4429 target_rect.origin.x,
4430 framebuffer_size.height - target_rect.size.height - target_rect.origin.y,
4431 ),
4432 target_rect.size,
4433 ),
4434 TextureFilter::Nearest,
4435 );
4436 }
4437
draw_texture_cache_debug(&mut self, framebuffer_size: DeviceIntSize)4438 fn draw_texture_cache_debug(&mut self, framebuffer_size: DeviceIntSize) {
4439 if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
4440 return;
4441 }
4442
4443 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4444 Some(render) => render,
4445 None => return,
4446 };
4447
4448 let textures =
4449 self.texture_resolver.texture_cache_map.values().collect::<Vec<&Texture>>();
4450
4451 fn select_color(texture: &Texture) -> [f32; 4] {
4452 if texture.flags().contains(TextureFlags::IS_SHARED_TEXTURE_CACHE) {
4453 [1.0, 0.5, 0.0, 1.0] // Orange for shared.
4454 } else {
4455 [1.0, 0.0, 1.0, 1.0] // Fuchsia for standalone.
4456 }
4457 }
4458
4459 Self::do_debug_blit(
4460 &mut self.device,
4461 debug_renderer,
4462 textures,
4463 framebuffer_size,
4464 if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) { 544 } else { 0 },
4465 &select_color,
4466 );
4467 }
4468
do_debug_blit( device: &mut Device, debug_renderer: &mut DebugRenderer, mut textures: Vec<&Texture>, framebuffer_size: DeviceIntSize, bottom: i32, select_color: &Fn(&Texture) -> [f32; 4], )4469 fn do_debug_blit(
4470 device: &mut Device,
4471 debug_renderer: &mut DebugRenderer,
4472 mut textures: Vec<&Texture>,
4473 framebuffer_size: DeviceIntSize,
4474 bottom: i32,
4475 select_color: &Fn(&Texture) -> [f32; 4],
4476 ) {
4477 let mut spacing = 16;
4478 let mut size = 512;
4479
4480 let fb_width = framebuffer_size.width as i32;
4481 let fb_height = framebuffer_size.height as i32;
4482 let num_layers: i32 = textures.iter()
4483 .map(|texture| texture.get_layer_count())
4484 .sum();
4485
4486 if num_layers * (size + spacing) > fb_width {
4487 let factor = fb_width as f32 / (num_layers * (size + spacing)) as f32;
4488 size = (size as f32 * factor) as i32;
4489 spacing = (spacing as f32 * factor) as i32;
4490 }
4491
4492 // Sort the display by layer size (in bytes), so that left-to-right is
4493 // largest-to-smallest.
4494 //
4495 // Note that the vec here is in increasing order, because the elements
4496 // get drawn right-to-left.
4497 textures.sort_by_key(|t| t.layer_size_in_bytes());
4498
4499 let mut i = 0;
4500 for texture in textures.iter() {
4501 let y = spacing + bottom;
4502 let dimensions = texture.get_dimensions();
4503 let src_rect = DeviceIntRect::new(
4504 DeviceIntPoint::zero(),
4505 DeviceIntSize::new(dimensions.width as i32, dimensions.height as i32),
4506 );
4507
4508 let layer_count = texture.get_layer_count() as usize;
4509 for layer in 0 .. layer_count {
4510 device.bind_read_target(ReadTarget::Texture { texture, layer});
4511
4512 let x = fb_width - (spacing + size) * (i as i32 + 1);
4513
4514 // If we have more targets than fit on one row in screen, just early exit.
4515 if x > fb_width {
4516 return;
4517 }
4518
4519 // Draw the info tag.
4520 let text_margin = 1;
4521 let text_height = 14; // Visually aproximated.
4522 let tag_height = text_height + text_margin * 2;
4523 let tag_rect = rect(x, y, size, tag_height);
4524 let tag_color = select_color(texture);
4525 device.clear_target(Some(tag_color), None, Some(tag_rect));
4526
4527 // Draw the dimensions onto the tag.
4528 let dim = texture.get_dimensions();
4529 let mut text_rect = tag_rect;
4530 text_rect.origin.y =
4531 fb_height - text_rect.origin.y - text_rect.size.height; // Top-relative.
4532 debug_renderer.add_text(
4533 (x + text_margin) as f32,
4534 (fb_height - y - text_margin) as f32, // Top-relative.
4535 &format!("{}x{}", dim.width, dim.height),
4536 ColorU::new(0, 0, 0, 255),
4537 Some(text_rect.to_f32())
4538 );
4539
4540 // Blit the contents of the layer. We need to invert Y because
4541 // we're blitting from a texture to the main framebuffer, which
4542 // use different conventions.
4543 let dest_rect = rect(x, y + tag_height, size, size);
4544 device.blit_render_target_invert_y(src_rect, dest_rect);
4545 i += 1;
4546 }
4547 }
4548 }
4549
draw_epoch_debug(&mut self)4550 fn draw_epoch_debug(&mut self) {
4551 if !self.debug_flags.contains(DebugFlags::EPOCHS) {
4552 return;
4553 }
4554
4555 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4556 Some(render) => render,
4557 None => return,
4558 };
4559
4560 let dy = debug_renderer.line_height();
4561 let x0: f32 = 30.0;
4562 let y0: f32 = 30.0;
4563 let mut y = y0;
4564 let mut text_width = 0.0;
4565 for (pipeline, epoch) in &self.pipeline_info.epochs {
4566 y += dy;
4567 let w = debug_renderer.add_text(
4568 x0, y,
4569 &format!("{:?}: {:?}", pipeline, epoch),
4570 ColorU::new(255, 255, 0, 255),
4571 None,
4572 ).size.width;
4573 text_width = f32::max(text_width, w);
4574 }
4575
4576 let margin = 10.0;
4577 debug_renderer.add_quad(
4578 &x0 - margin,
4579 y0 - margin,
4580 x0 + text_width + margin,
4581 y + margin,
4582 ColorU::new(25, 25, 25, 200),
4583 ColorU::new(51, 51, 51, 200),
4584 );
4585 }
4586
draw_gpu_cache_debug(&mut self, framebuffer_size: DeviceIntSize)4587 fn draw_gpu_cache_debug(&mut self, framebuffer_size: DeviceIntSize) {
4588 if !self.debug_flags.contains(DebugFlags::GPU_CACHE_DBG) {
4589 return;
4590 }
4591
4592 let debug_renderer = match self.debug.get_mut(&mut self.device) {
4593 Some(render) => render,
4594 None => return,
4595 };
4596
4597 let (x_off, y_off) = (30f32, 30f32);
4598 let height = self.gpu_cache_texture.texture
4599 .as_ref().map_or(0, |t| t.get_dimensions().height)
4600 .min(framebuffer_size.height - (y_off as i32) * 2) as usize;
4601 debug_renderer.add_quad(
4602 x_off,
4603 y_off,
4604 x_off + MAX_VERTEX_TEXTURE_WIDTH as f32,
4605 y_off + height as f32,
4606 ColorU::new(80, 80, 80, 80),
4607 ColorU::new(80, 80, 80, 80),
4608 );
4609
4610 let upper = self.gpu_cache_debug_chunks.len().min(height);
4611 for chunk in self.gpu_cache_debug_chunks[0..upper].iter().flatten() {
4612 let color = ColorU::new(250, 0, 0, 200);
4613 debug_renderer.add_quad(
4614 x_off + chunk.address.u as f32,
4615 y_off + chunk.address.v as f32,
4616 x_off + chunk.address.u as f32 + chunk.size as f32,
4617 y_off + chunk.address.v as f32 + 1.0,
4618 color,
4619 color,
4620 );
4621 }
4622 }
4623
4624 /// Pass-through to `Device::read_pixels_into`, used by Gecko's WR bindings.
read_pixels_into(&mut self, rect: DeviceIntRect, format: ReadPixelsFormat, output: &mut [u8])4625 pub fn read_pixels_into(&mut self, rect: DeviceIntRect, format: ReadPixelsFormat, output: &mut [u8]) {
4626 self.device.read_pixels_into(rect, format, output);
4627 }
4628
read_pixels_rgba8(&mut self, rect: DeviceIntRect) -> Vec<u8>4629 pub fn read_pixels_rgba8(&mut self, rect: DeviceIntRect) -> Vec<u8> {
4630 let mut pixels = vec![0; (rect.size.width * rect.size.height * 4) as usize];
4631 self.device.read_pixels_into(rect, ReadPixelsFormat::Rgba8, &mut pixels);
4632 pixels
4633 }
4634
read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>)4635 pub fn read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>) {
4636 let texture = self.gpu_cache_texture.texture.as_ref().unwrap();
4637 let size = texture.get_dimensions();
4638 let mut texels = vec![0; (size.width * size.height * 16) as usize];
4639 self.device.begin_frame();
4640 self.device.bind_read_target(ReadTarget::Texture { texture, layer: 0 });
4641 self.device.read_pixels_into(
4642 DeviceIntRect::new(DeviceIntPoint::zero(), size),
4643 ReadPixelsFormat::Standard(ImageFormat::RGBAF32),
4644 &mut texels,
4645 );
4646 self.device.reset_read_target();
4647 self.device.end_frame();
4648 (size, texels)
4649 }
4650
4651 // De-initialize the Renderer safely, assuming the GL is still alive and active.
deinit(mut self)4652 pub fn deinit(mut self) {
4653 //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
4654 self.device.begin_frame();
4655 self.gpu_cache_texture.deinit(&mut self.device);
4656 if let Some(dither_matrix_texture) = self.dither_matrix_texture {
4657 self.device.delete_texture(dither_matrix_texture);
4658 }
4659 if let Some(zoom_debug_texture) = self.zoom_debug_texture {
4660 self.device.delete_texture(zoom_debug_texture);
4661 }
4662 self.transforms_texture.deinit(&mut self.device);
4663 self.prim_header_f_texture.deinit(&mut self.device);
4664 self.prim_header_i_texture.deinit(&mut self.device);
4665 self.render_task_texture.deinit(&mut self.device);
4666 self.device.delete_pbo(self.texture_cache_upload_pbo);
4667 self.texture_resolver.deinit(&mut self.device);
4668 self.device.delete_vao(self.vaos.prim_vao);
4669 self.device.delete_vao(self.vaos.clip_vao);
4670 self.device.delete_vao(self.vaos.blur_vao);
4671 self.device.delete_vao(self.vaos.line_vao);
4672 self.device.delete_vao(self.vaos.border_vao);
4673 self.device.delete_vao(self.vaos.scale_vao);
4674
4675 self.debug.deinit(&mut self.device);
4676
4677 for (_, target) in self.output_targets {
4678 self.device.delete_fbo(target.fbo_id);
4679 }
4680 if let Ok(shaders) = Rc::try_unwrap(self.shaders) {
4681 shaders.into_inner().deinit(&mut self.device);
4682 }
4683 #[cfg(feature = "capture")]
4684 self.device.delete_fbo(self.read_fbo);
4685 #[cfg(feature = "replay")]
4686 for (_, ext) in self.owned_external_images {
4687 self.device.delete_external_texture(ext);
4688 }
4689 self.device.end_frame();
4690 }
4691
size_of<T>(&self, ptr: *const T) -> usize4692 fn size_of<T>(&self, ptr: *const T) -> usize {
4693 let op = self.size_of_ops.as_ref().unwrap().size_of_op;
4694 unsafe { op(ptr as *const c_void) }
4695 }
4696
4697 /// Collects a memory report.
report_memory(&self) -> MemoryReport4698 pub fn report_memory(&self) -> MemoryReport {
4699 let mut report = MemoryReport::default();
4700
4701 // GPU cache CPU memory.
4702 if let GpuCacheBus::PixelBuffer{ref rows, ..} = self.gpu_cache_texture.bus {
4703 for row in rows.iter() {
4704 report.gpu_cache_cpu_mirror += self.size_of(&*row.cpu_blocks as *const _);
4705 }
4706 }
4707
4708 // GPU cache GPU memory.
4709 report.gpu_cache_textures +=
4710 self.gpu_cache_texture.texture.as_ref().map_or(0, |t| t.size_in_bytes());
4711
4712 // Render task CPU memory.
4713 for (_id, doc) in &self.active_documents {
4714 report.render_tasks += self.size_of(doc.frame.render_tasks.tasks.as_ptr());
4715 report.render_tasks += self.size_of(doc.frame.render_tasks.task_data.as_ptr());
4716 }
4717
4718 // Vertex data GPU memory.
4719 report.vertex_data_textures += self.prim_header_f_texture.size_in_bytes();
4720 report.vertex_data_textures += self.prim_header_i_texture.size_in_bytes();
4721 report.vertex_data_textures += self.transforms_texture.size_in_bytes();
4722 report.vertex_data_textures += self.render_task_texture.size_in_bytes();
4723
4724 // Texture cache and render target GPU memory.
4725 report += self.texture_resolver.report_memory();
4726
4727 // Textures held internally within the device layer.
4728 report += self.device.report_memory();
4729
4730 report
4731 }
4732
4733 // Sets the blend mode. Blend is unconditionally set if the "show overdraw" debugging mode is
4734 // enabled.
set_blend(&self, mut blend: bool, framebuffer_kind: FramebufferKind)4735 fn set_blend(&self, mut blend: bool, framebuffer_kind: FramebufferKind) {
4736 if framebuffer_kind == FramebufferKind::Main &&
4737 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4738 blend = true
4739 }
4740 self.device.set_blend(blend)
4741 }
4742
set_blend_mode_multiply(&self, framebuffer_kind: FramebufferKind)4743 fn set_blend_mode_multiply(&self, framebuffer_kind: FramebufferKind) {
4744 if framebuffer_kind == FramebufferKind::Main &&
4745 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4746 self.device.set_blend_mode_show_overdraw();
4747 } else {
4748 self.device.set_blend_mode_multiply();
4749 }
4750 }
4751
set_blend_mode_premultiplied_alpha(&self, framebuffer_kind: FramebufferKind)4752 fn set_blend_mode_premultiplied_alpha(&self, framebuffer_kind: FramebufferKind) {
4753 if framebuffer_kind == FramebufferKind::Main &&
4754 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4755 self.device.set_blend_mode_show_overdraw();
4756 } else {
4757 self.device.set_blend_mode_premultiplied_alpha();
4758 }
4759 }
4760
set_blend_mode_subpixel_with_bg_color_pass1(&self, framebuffer_kind: FramebufferKind)4761 fn set_blend_mode_subpixel_with_bg_color_pass1(&self, framebuffer_kind: FramebufferKind) {
4762 if framebuffer_kind == FramebufferKind::Main &&
4763 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4764 self.device.set_blend_mode_show_overdraw();
4765 } else {
4766 self.device.set_blend_mode_subpixel_with_bg_color_pass1();
4767 }
4768 }
4769
set_blend_mode_subpixel_with_bg_color_pass2(&self, framebuffer_kind: FramebufferKind)4770 fn set_blend_mode_subpixel_with_bg_color_pass2(&self, framebuffer_kind: FramebufferKind) {
4771 if framebuffer_kind == FramebufferKind::Main &&
4772 self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
4773 self.device.set_blend_mode_show_overdraw();
4774 } else {
4775 self.device.set_blend_mode_subpixel_with_bg_color_pass2();
4776 }
4777 }
4778
4779 /// Clears all the layers of a texture with a given color.
clear_texture(&mut self, texture: &Texture, color: [f32; 4])4780 fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
4781 for i in 0..texture.get_layer_count() {
4782 self.device.bind_draw_target(DrawTarget::Texture {
4783 texture: &texture,
4784 layer: i as usize,
4785 with_depth: false,
4786 });
4787 self.device.clear_target(Some(color), None, None);
4788 }
4789 }
4790 }
4791
4792 pub enum ExternalImageSource<'a> {
4793 RawData(&'a [u8]), // raw buffers.
4794 NativeTexture(u32), // It's a gl::GLuint texture handle
4795 Invalid,
4796 }
4797
4798 /// The data that an external client should provide about
4799 /// an external image. The timestamp is used to test if
4800 /// the renderer should upload new texture data this
4801 /// frame. For instance, if providing video frames, the
4802 /// application could call wr.render() whenever a new
4803 /// video frame is ready. If the callback increments
4804 /// the returned timestamp for a given image, the renderer
4805 /// will know to re-upload the image data to the GPU.
4806 /// Note that the UV coords are supplied in texel-space!
4807 pub struct ExternalImage<'a> {
4808 pub uv: TexelRect,
4809 pub source: ExternalImageSource<'a>,
4810 }
4811
4812 /// The interfaces that an application can implement to support providing
4813 /// external image buffers.
4814 /// When the the application passes an external image to WR, it should kepp that
4815 /// external image life time. People could check the epoch id in RenderNotifier
4816 /// at the client side to make sure that the external image is not used by WR.
4817 /// Then, do the clean up for that external image.
4818 pub trait ExternalImageHandler {
4819 /// Lock the external image. Then, WR could start to read the image content.
4820 /// The WR client should not change the image content until the unlock()
4821 /// call. Provide ImageRendering for NativeTexture external images.
lock(&mut self, key: ExternalImageId, channel_index: u8, rendering: ImageRendering) -> ExternalImage4822 fn lock(&mut self, key: ExternalImageId, channel_index: u8, rendering: ImageRendering) -> ExternalImage;
4823 /// Unlock the external image. The WR should not read the image content
4824 /// after this call.
unlock(&mut self, key: ExternalImageId, channel_index: u8)4825 fn unlock(&mut self, key: ExternalImageId, channel_index: u8);
4826 }
4827
4828 /// Allows callers to receive a texture with the contents of a specific
4829 /// pipeline copied to it. Lock should return the native texture handle
4830 /// and the size of the texture. Unlock will only be called if the lock()
4831 /// call succeeds, when WR has issued the GL commands to copy the output
4832 /// to the texture handle.
4833 pub trait OutputImageHandler {
lock(&mut self, pipeline_id: PipelineId) -> Option<(u32, DeviceIntSize)>4834 fn lock(&mut self, pipeline_id: PipelineId) -> Option<(u32, DeviceIntSize)>;
unlock(&mut self, pipeline_id: PipelineId)4835 fn unlock(&mut self, pipeline_id: PipelineId);
4836 }
4837
4838 pub trait ThreadListener {
thread_started(&self, thread_name: &str)4839 fn thread_started(&self, thread_name: &str);
thread_stopped(&self, thread_name: &str)4840 fn thread_stopped(&self, thread_name: &str);
4841 }
4842
4843 /// Allows callers to hook in at certain points of the async scene build. These
4844 /// functions are all called from the scene builder thread.
4845 pub trait SceneBuilderHooks {
4846 /// This is called exactly once, when the scene builder thread is started
4847 /// and before it processes anything.
register(&self)4848 fn register(&self);
4849 /// This is called before each scene build starts.
pre_scene_build(&self)4850 fn pre_scene_build(&self);
4851 /// This is called before each scene swap occurs.
pre_scene_swap(&self, scenebuild_time: u64)4852 fn pre_scene_swap(&self, scenebuild_time: u64);
4853 /// This is called after each scene swap occurs. The PipelineInfo contains
4854 /// the updated epochs and pipelines removed in the new scene compared to
4855 /// the old scene.
post_scene_swap(&self, info: PipelineInfo, sceneswap_time: u64)4856 fn post_scene_swap(&self, info: PipelineInfo, sceneswap_time: u64);
4857 /// This is called after a resource update operation on the scene builder
4858 /// thread, in the case where resource updates were applied without a scene
4859 /// build.
post_resource_update(&self)4860 fn post_resource_update(&self);
4861 /// This is called after a scene build completes without any changes being
4862 /// made. We guarantee that each pre_scene_build call will be matched with
4863 /// exactly one of post_scene_swap, post_resource_update or
4864 /// post_empty_scene_build.
post_empty_scene_build(&self)4865 fn post_empty_scene_build(&self);
4866 /// This is a generic callback which provides an opportunity to run code
4867 /// on the scene builder thread. This is called as part of the main message
4868 /// loop of the scene builder thread, but outside of any specific message
4869 /// handler.
poke(&self)4870 fn poke(&self);
4871 /// This is called exactly once, when the scene builder thread is about to
4872 /// terminate.
deregister(&self)4873 fn deregister(&self);
4874 }
4875
4876 /// Allows callers to hook into the main render_backend loop and provide
4877 /// additional frame ops for generate_frame transactions. These functions
4878 /// are all called from the render backend thread.
4879 pub trait AsyncPropertySampler {
4880 /// This is called exactly once, when the render backend thread is started
4881 /// and before it processes anything.
register(&self)4882 fn register(&self);
4883 /// This is called for each transaction with the generate_frame flag set
4884 /// (i.e. that will trigger a render). The list of frame messages returned
4885 /// are processed as though they were part of the original transaction.
sample(&self) -> Vec<FrameMsg>4886 fn sample(&self) -> Vec<FrameMsg>;
4887 /// This is called exactly once, when the render backend thread is about to
4888 /// terminate.
deregister(&self)4889 fn deregister(&self);
4890 }
4891
4892 /// Flags that control how shaders are pre-cached, if at all.
4893 bitflags! {
4894 #[derive(Default)]
4895 pub struct ShaderPrecacheFlags: u32 {
4896 /// Needed for const initialization
4897 const EMPTY = 0;
4898
4899 /// Only start async compile
4900 const ASYNC_COMPILE = 1 << 2;
4901
4902 /// Do a full compile/link during startup
4903 const FULL_COMPILE = 1 << 3;
4904 }
4905 }
4906
4907 pub struct RendererOptions {
4908 pub device_pixel_ratio: f32,
4909 pub resource_override_path: Option<PathBuf>,
4910 pub enable_aa: bool,
4911 pub enable_dithering: bool,
4912 pub max_recorded_profiles: usize,
4913 pub precache_flags: ShaderPrecacheFlags,
4914 pub renderer_kind: RendererKind,
4915 pub enable_subpixel_aa: bool,
4916 pub clear_color: Option<ColorF>,
4917 pub enable_clear_scissor: bool,
4918 pub max_texture_size: Option<i32>,
4919 pub scatter_gpu_cache_updates: bool,
4920 pub upload_method: UploadMethod,
4921 pub workers: Option<Arc<ThreadPool>>,
4922 pub blob_image_handler: Option<Box<BlobImageHandler>>,
4923 pub recorder: Option<Box<ApiRecordingReceiver>>,
4924 pub thread_listener: Option<Box<ThreadListener + Send + Sync>>,
4925 pub size_of_op: Option<VoidPtrToSizeFn>,
4926 pub enclosing_size_of_op: Option<VoidPtrToSizeFn>,
4927 pub cached_programs: Option<Rc<ProgramCache>>,
4928 pub debug_flags: DebugFlags,
4929 pub renderer_id: Option<u64>,
4930 pub disable_dual_source_blending: bool,
4931 pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>,
4932 pub sampler: Option<Box<AsyncPropertySampler + Send>>,
4933 pub chase_primitive: ChasePrimitive,
4934 pub support_low_priority_transactions: bool,
4935 pub namespace_alloc_by_client: bool,
4936 pub enable_picture_caching: bool,
4937 pub testing: bool,
4938 }
4939
4940 impl Default for RendererOptions {
default() -> Self4941 fn default() -> Self {
4942 RendererOptions {
4943 device_pixel_ratio: 1.0,
4944 resource_override_path: None,
4945 enable_aa: true,
4946 enable_dithering: true,
4947 debug_flags: DebugFlags::empty(),
4948 max_recorded_profiles: 0,
4949 precache_flags: ShaderPrecacheFlags::empty(),
4950 renderer_kind: RendererKind::Native,
4951 enable_subpixel_aa: false,
4952 clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
4953 enable_clear_scissor: true,
4954 max_texture_size: None,
4955 // Scattered GPU cache updates haven't met a test that would show their superiority yet.
4956 scatter_gpu_cache_updates: false,
4957 // This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL,
4958 // but we are unable to make this decision here, so picking the reasonable medium.
4959 upload_method: UploadMethod::PixelBuffer(VertexUsageHint::Stream),
4960 workers: None,
4961 blob_image_handler: None,
4962 recorder: None,
4963 thread_listener: None,
4964 size_of_op: None,
4965 enclosing_size_of_op: None,
4966 renderer_id: None,
4967 cached_programs: None,
4968 disable_dual_source_blending: false,
4969 scene_builder_hooks: None,
4970 sampler: None,
4971 chase_primitive: ChasePrimitive::Nothing,
4972 support_low_priority_transactions: false,
4973 namespace_alloc_by_client: false,
4974 enable_picture_caching: false,
4975 testing: false,
4976 }
4977 }
4978 }
4979
4980 #[cfg(not(feature = "debugger"))]
4981 pub struct DebugServer;
4982
4983 #[cfg(not(feature = "debugger"))]
4984 impl DebugServer {
new(_: MsgSender<ApiMsg>) -> Self4985 pub fn new(_: MsgSender<ApiMsg>) -> Self {
4986 DebugServer
4987 }
4988
send(&mut self, _: String)4989 pub fn send(&mut self, _: String) {}
4990 }
4991
4992 /// Some basic statistics about the rendered scene, used in Gecko, as
4993 /// well as in wrench reftests to ensure that tests are batching and/or
4994 /// allocating on render targets as we expect them to.
4995 #[repr(C)]
4996 #[derive(Debug, Default)]
4997 pub struct RendererStats {
4998 pub total_draw_calls: usize,
4999 pub alpha_target_count: usize,
5000 pub color_target_count: usize,
5001 pub texture_upload_kb: usize,
5002 pub resource_upload_time: u64,
5003 pub gpu_cache_upload_time: u64,
5004 }
5005
5006 /// Return type from render(), which contains some repr(C) statistics as well as
5007 /// some non-repr(C) data.
5008 #[derive(Debug, Default)]
5009 pub struct RenderResults {
5010 pub stats: RendererStats,
5011 pub recorded_dirty_regions: Vec<RecordedDirtyRegion>,
5012 }
5013
5014 #[cfg(any(feature = "capture", feature = "replay"))]
5015 #[cfg_attr(feature = "capture", derive(Serialize))]
5016 #[cfg_attr(feature = "replay", derive(Deserialize))]
5017 struct PlainTexture {
5018 data: String,
5019 size: (DeviceIntSize, i32),
5020 format: ImageFormat,
5021 filter: TextureFilter,
5022 }
5023
5024
5025 #[cfg(any(feature = "capture", feature = "replay"))]
5026 #[cfg_attr(feature = "capture", derive(Serialize))]
5027 #[cfg_attr(feature = "replay", derive(Deserialize))]
5028 struct PlainRenderer {
5029 gpu_cache: PlainTexture,
5030 gpu_cache_frame_id: FrameId,
5031 textures: FastHashMap<CacheTextureId, PlainTexture>,
5032 external_images: Vec<ExternalCaptureImage>
5033 }
5034
5035 #[cfg(feature = "replay")]
5036 enum CapturedExternalImageData {
5037 NativeTexture(gl::GLuint),
5038 Buffer(Arc<Vec<u8>>),
5039 }
5040
5041 #[cfg(feature = "replay")]
5042 struct DummyExternalImageHandler {
5043 data: FastHashMap<(ExternalImageId, u8), (CapturedExternalImageData, TexelRect)>,
5044 }
5045
5046 #[cfg(feature = "replay")]
5047 impl ExternalImageHandler for DummyExternalImageHandler {
lock(&mut self, key: ExternalImageId, channel_index: u8, _rendering: ImageRendering) -> ExternalImage5048 fn lock(&mut self, key: ExternalImageId, channel_index: u8, _rendering: ImageRendering) -> ExternalImage {
5049 let (ref captured_data, ref uv) = self.data[&(key, channel_index)];
5050 ExternalImage {
5051 uv: *uv,
5052 source: match *captured_data {
5053 CapturedExternalImageData::NativeTexture(tid) => ExternalImageSource::NativeTexture(tid),
5054 CapturedExternalImageData::Buffer(ref arc) => ExternalImageSource::RawData(&*arc),
5055 }
5056 }
5057 }
unlock(&mut self, _key: ExternalImageId, _channel_index: u8)5058 fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
5059 }
5060
5061 #[cfg(feature = "replay")]
5062 impl OutputImageHandler for () {
lock(&mut self, _: PipelineId) -> Option<(u32, DeviceIntSize)>5063 fn lock(&mut self, _: PipelineId) -> Option<(u32, DeviceIntSize)> {
5064 None
5065 }
unlock(&mut self, _: PipelineId)5066 fn unlock(&mut self, _: PipelineId) {
5067 unreachable!()
5068 }
5069 }
5070
5071 #[derive(Default)]
5072 pub struct PipelineInfo {
5073 pub epochs: FastHashMap<PipelineId, Epoch>,
5074 pub removed_pipelines: Vec<PipelineId>,
5075 }
5076
5077 impl Renderer {
5078 #[cfg(feature = "capture")]
save_texture( texture: &Texture, name: &str, root: &PathBuf, device: &mut Device ) -> PlainTexture5079 fn save_texture(
5080 texture: &Texture, name: &str, root: &PathBuf, device: &mut Device
5081 ) -> PlainTexture {
5082 use std::fs;
5083 use std::io::Write;
5084
5085 let short_path = format!("textures/{}.raw", name);
5086
5087 let bytes_per_pixel = texture.get_format().bytes_per_pixel();
5088 let read_format = ReadPixelsFormat::Standard(texture.get_format());
5089 let rect = DeviceIntRect::new(
5090 DeviceIntPoint::zero(),
5091 texture.get_dimensions(),
5092 );
5093
5094 let mut file = fs::File::create(root.join(&short_path))
5095 .expect(&format!("Unable to create {}", short_path));
5096 let bytes_per_layer = (rect.size.width * rect.size.height * bytes_per_pixel) as usize;
5097 let mut data = vec![0; bytes_per_layer];
5098
5099 //TODO: instead of reading from an FBO with `read_pixels*`, we could
5100 // read from textures directly with `get_tex_image*`.
5101
5102 for layer_id in 0 .. texture.get_layer_count() {
5103 device.attach_read_texture(texture, layer_id);
5104 #[cfg(feature = "png")]
5105 {
5106 let mut png_data;
5107 let (data_ref, format) = match texture.get_format() {
5108 ImageFormat::RGBAF32 => {
5109 png_data = vec![0; (rect.size.width * rect.size.height * 4) as usize];
5110 device.read_pixels_into(rect, ReadPixelsFormat::Rgba8, &mut png_data);
5111 (&png_data, ReadPixelsFormat::Rgba8)
5112 }
5113 fm => (&data, ReadPixelsFormat::Standard(fm)),
5114 };
5115 CaptureConfig::save_png(
5116 root.join(format!("textures/{}-{}.png", name, layer_id)),
5117 rect.size, format,
5118 data_ref,
5119 );
5120 }
5121 device.read_pixels_into(rect, read_format, &mut data);
5122 file.write_all(&data)
5123 .unwrap();
5124 }
5125
5126 PlainTexture {
5127 data: short_path,
5128 size: (rect.size, texture.get_layer_count()),
5129 format: texture.get_format(),
5130 filter: texture.get_filter(),
5131 }
5132 }
5133
5134 #[cfg(feature = "replay")]
load_texture( target: TextureTarget, plain: &PlainTexture, rt_info: Option<RenderTargetInfo>, root: &PathBuf, device: &mut Device ) -> (Texture, Vec<u8>)5135 fn load_texture(
5136 target: TextureTarget,
5137 plain: &PlainTexture,
5138 rt_info: Option<RenderTargetInfo>,
5139 root: &PathBuf,
5140 device: &mut Device
5141 ) -> (Texture, Vec<u8>)
5142 {
5143 use std::fs::File;
5144 use std::io::Read;
5145
5146 let mut texels = Vec::new();
5147 File::open(root.join(&plain.data))
5148 .expect(&format!("Unable to open texture at {}", plain.data))
5149 .read_to_end(&mut texels)
5150 .unwrap();
5151
5152 let texture = device.create_texture(
5153 target,
5154 plain.format,
5155 plain.size.0.width,
5156 plain.size.0.height,
5157 plain.filter,
5158 rt_info,
5159 plain.size.1,
5160 );
5161 device.upload_texture_immediate(&texture, &texels);
5162
5163 (texture, texels)
5164 }
5165
5166 #[cfg(feature = "capture")]
save_capture( &mut self, config: CaptureConfig, deferred_images: Vec<ExternalCaptureImage>, )5167 fn save_capture(
5168 &mut self,
5169 config: CaptureConfig,
5170 deferred_images: Vec<ExternalCaptureImage>,
5171 ) {
5172 use std::fs;
5173 use std::io::Write;
5174 use api::{CaptureBits, ExternalImageData};
5175
5176 self.device.begin_frame();
5177 let _gm = self.gpu_profile.start_marker("read GPU data");
5178 self.device.bind_read_target_impl(self.read_fbo);
5179
5180 if !deferred_images.is_empty() {
5181 info!("saving external images");
5182 let mut arc_map = FastHashMap::<*const u8, String>::default();
5183 let mut tex_map = FastHashMap::<u32, String>::default();
5184 let handler = self.external_image_handler
5185 .as_mut()
5186 .expect("Unable to lock the external image handler!");
5187 for def in &deferred_images {
5188 info!("\t{}", def.short_path);
5189 let ExternalImageData { id, channel_index, image_type } = def.external;
5190 // The image rendering parameter is irrelevant because no filtering happens during capturing.
5191 let ext_image = handler.lock(id, channel_index, ImageRendering::Auto);
5192 let (data, short_path) = match ext_image.source {
5193 ExternalImageSource::RawData(data) => {
5194 let arc_id = arc_map.len() + 1;
5195 match arc_map.entry(data.as_ptr()) {
5196 Entry::Occupied(e) => {
5197 (None, e.get().clone())
5198 }
5199 Entry::Vacant(e) => {
5200 let short_path = format!("externals/d{}.raw", arc_id);
5201 (Some(data.to_vec()), e.insert(short_path).clone())
5202 }
5203 }
5204 }
5205 ExternalImageSource::NativeTexture(gl_id) => {
5206 let tex_id = tex_map.len() + 1;
5207 match tex_map.entry(gl_id) {
5208 Entry::Occupied(e) => {
5209 (None, e.get().clone())
5210 }
5211 Entry::Vacant(e) => {
5212 let target = match image_type {
5213 ExternalImageType::TextureHandle(target) => target,
5214 ExternalImageType::Buffer => unreachable!(),
5215 };
5216 info!("\t\tnative texture of target {:?}", target);
5217 let layer_index = 0; //TODO: what about layered textures?
5218 self.device.attach_read_texture_external(gl_id, target, layer_index);
5219 let data = self.device.read_pixels(&def.descriptor);
5220 let short_path = format!("externals/t{}.raw", tex_id);
5221 (Some(data), e.insert(short_path).clone())
5222 }
5223 }
5224 }
5225 ExternalImageSource::Invalid => {
5226 info!("\t\tinvalid source!");
5227 (None, String::new())
5228 }
5229 };
5230 if let Some(bytes) = data {
5231 fs::File::create(config.root.join(&short_path))
5232 .expect(&format!("Unable to create {}", short_path))
5233 .write_all(&bytes)
5234 .unwrap();
5235 #[cfg(feature = "png")]
5236 CaptureConfig::save_png(
5237 config.root.join(&short_path).with_extension("png"),
5238 def.descriptor.size,
5239 ReadPixelsFormat::Standard(def.descriptor.format),
5240 &bytes,
5241 );
5242 }
5243 let plain = PlainExternalImage {
5244 data: short_path,
5245 external: def.external,
5246 uv: ext_image.uv,
5247 };
5248 config.serialize(&plain, &def.short_path);
5249 }
5250 for def in &deferred_images {
5251 handler.unlock(def.external.id, def.external.channel_index);
5252 }
5253 }
5254
5255 if config.bits.contains(CaptureBits::FRAME) {
5256 let path_textures = config.root.join("textures");
5257 if !path_textures.is_dir() {
5258 fs::create_dir(&path_textures).unwrap();
5259 }
5260
5261 info!("saving GPU cache");
5262 self.update_gpu_cache(); // flush pending updates
5263 let mut plain_self = PlainRenderer {
5264 gpu_cache: Self::save_texture(
5265 &self.gpu_cache_texture.texture.as_ref().unwrap(),
5266 "gpu", &config.root, &mut self.device,
5267 ),
5268 gpu_cache_frame_id: self.gpu_cache_frame_id,
5269 textures: FastHashMap::default(),
5270 external_images: deferred_images,
5271 };
5272
5273 info!("saving cached textures");
5274 for (id, texture) in &self.texture_resolver.texture_cache_map {
5275 let file_name = format!("cache-{}", plain_self.textures.len() + 1);
5276 info!("\t{}", file_name);
5277 let plain = Self::save_texture(texture, &file_name, &config.root, &mut self.device);
5278 plain_self.textures.insert(*id, plain);
5279 }
5280
5281 config.serialize(&plain_self, "renderer");
5282 }
5283
5284 self.device.reset_read_target();
5285 self.device.end_frame();
5286 info!("done.");
5287 }
5288
5289 #[cfg(feature = "replay")]
load_capture( &mut self, root: PathBuf, plain_externals: Vec<PlainExternalImage> )5290 fn load_capture(
5291 &mut self, root: PathBuf, plain_externals: Vec<PlainExternalImage>
5292 ) {
5293 use std::fs::File;
5294 use std::io::Read;
5295 use std::slice;
5296
5297 info!("loading external buffer-backed images");
5298 assert!(self.texture_resolver.external_images.is_empty());
5299 let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
5300 let mut image_handler = DummyExternalImageHandler {
5301 data: FastHashMap::default(),
5302 };
5303 // Note: this is a `SCENE` level population of the external image handlers
5304 // It would put both external buffers and texture into the map.
5305 // But latter are going to be overwritten later in this function
5306 // if we are in the `FRAME` level.
5307 for plain_ext in plain_externals {
5308 let data = match raw_map.entry(plain_ext.data) {
5309 Entry::Occupied(e) => e.get().clone(),
5310 Entry::Vacant(e) => {
5311 let mut buffer = Vec::new();
5312 File::open(root.join(e.key()))
5313 .expect(&format!("Unable to open {}", e.key()))
5314 .read_to_end(&mut buffer)
5315 .unwrap();
5316 e.insert(Arc::new(buffer)).clone()
5317 }
5318 };
5319 let ext = plain_ext.external;
5320 let value = (CapturedExternalImageData::Buffer(data), plain_ext.uv);
5321 image_handler.data.insert((ext.id, ext.channel_index), value);
5322 }
5323
5324 if let Some(renderer) = CaptureConfig::deserialize::<PlainRenderer, _>(&root, "renderer") {
5325 info!("loading cached textures");
5326 self.device.begin_frame();
5327
5328 for (_id, texture) in self.texture_resolver.texture_cache_map.drain() {
5329 self.device.delete_texture(texture);
5330 }
5331 for (id, texture) in renderer.textures {
5332 info!("\t{}", texture.data);
5333 let t = Self::load_texture(
5334 TextureTarget::Array,
5335 &texture,
5336 Some(RenderTargetInfo { has_depth: false }),
5337 &root,
5338 &mut self.device
5339 );
5340 self.texture_resolver.texture_cache_map.insert(id, t.0);
5341 }
5342
5343 info!("loading gpu cache");
5344 if let Some(t) = self.gpu_cache_texture.texture.take() {
5345 self.device.delete_texture(t);
5346 }
5347 let (t, gpu_cache_data) = Self::load_texture(
5348 TextureTarget::Default,
5349 &renderer.gpu_cache,
5350 Some(RenderTargetInfo { has_depth: false }),
5351 &root,
5352 &mut self.device,
5353 );
5354 self.gpu_cache_texture.texture = Some(t);
5355 match self.gpu_cache_texture.bus {
5356 GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
5357 let dim = self.gpu_cache_texture.texture.as_ref().unwrap().get_dimensions();
5358 let blocks = unsafe {
5359 slice::from_raw_parts(
5360 gpu_cache_data.as_ptr() as *const GpuBlockData,
5361 gpu_cache_data.len() / mem::size_of::<GpuBlockData>(),
5362 )
5363 };
5364 // fill up the CPU cache from the contents we just loaded
5365 rows.clear();
5366 rows.extend((0 .. dim.height).map(|_| CacheRow::new()));
5367 let chunks = blocks.chunks(MAX_VERTEX_TEXTURE_WIDTH);
5368 debug_assert_eq!(chunks.len(), rows.len());
5369 for (row, chunk) in rows.iter_mut().zip(chunks) {
5370 row.cpu_blocks.copy_from_slice(chunk);
5371 }
5372 }
5373 GpuCacheBus::Scatter { .. } => {}
5374 }
5375 self.gpu_cache_frame_id = renderer.gpu_cache_frame_id;
5376
5377 info!("loading external texture-backed images");
5378 let mut native_map = FastHashMap::<String, gl::GLuint>::default();
5379 for ExternalCaptureImage { short_path, external, descriptor } in renderer.external_images {
5380 let target = match external.image_type {
5381 ExternalImageType::TextureHandle(target) => target,
5382 ExternalImageType::Buffer => continue,
5383 };
5384 let plain_ext = CaptureConfig::deserialize::<PlainExternalImage, _>(&root, &short_path)
5385 .expect(&format!("Unable to read {}.ron", short_path));
5386 let key = (external.id, external.channel_index);
5387
5388 let tid = match native_map.entry(plain_ext.data) {
5389 Entry::Occupied(e) => e.get().clone(),
5390 Entry::Vacant(e) => {
5391 //TODO: provide a way to query both the layer count and the filter from external images
5392 let (layer_count, filter) = (1, TextureFilter::Linear);
5393 let plain_tex = PlainTexture {
5394 data: e.key().clone(),
5395 size: (descriptor.size, layer_count),
5396 format: descriptor.format,
5397 filter,
5398 };
5399 let t = Self::load_texture(
5400 target,
5401 &plain_tex,
5402 None,
5403 &root,
5404 &mut self.device
5405 );
5406 let extex = t.0.into_external();
5407 self.owned_external_images.insert(key, extex.clone());
5408 e.insert(extex.internal_id()).clone()
5409 }
5410 };
5411
5412 let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv);
5413 image_handler.data.insert(key, value);
5414 }
5415
5416 self.device.end_frame();
5417 }
5418
5419 self.output_image_handler = Some(Box::new(()) as Box<_>);
5420 self.external_image_handler = Some(Box::new(image_handler) as Box<_>);
5421 info!("done.");
5422 }
5423 }
5424
5425 #[cfg(feature = "pathfinder")]
get_vao<'a>(vertex_array_kind: VertexArrayKind, vaos: &'a RendererVAOs, gpu_glyph_renderer: &'a GpuGlyphRenderer) -> &'a VAO5426 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
5427 vaos: &'a RendererVAOs,
5428 gpu_glyph_renderer: &'a GpuGlyphRenderer)
5429 -> &'a VAO {
5430 match vertex_array_kind {
5431 VertexArrayKind::Primitive => &vaos.prim_vao,
5432 VertexArrayKind::Clip => &vaos.clip_vao,
5433 VertexArrayKind::Blur => &vaos.blur_vao,
5434 VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao,
5435 VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao,
5436 VertexArrayKind::Border => &vaos.border_vao,
5437 VertexArrayKind::Scale => &vaos.scale_vao,
5438 VertexArrayKind::LineDecoration => &vaos.line_vao,
5439 }
5440 }
5441
5442 #[cfg(not(feature = "pathfinder"))]
get_vao<'a>(vertex_array_kind: VertexArrayKind, vaos: &'a RendererVAOs, _: &'a GpuGlyphRenderer) -> &'a VAO5443 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
5444 vaos: &'a RendererVAOs,
5445 _: &'a GpuGlyphRenderer)
5446 -> &'a VAO {
5447 match vertex_array_kind {
5448 VertexArrayKind::Primitive => &vaos.prim_vao,
5449 VertexArrayKind::Clip => &vaos.clip_vao,
5450 VertexArrayKind::Blur => &vaos.blur_vao,
5451 VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(),
5452 VertexArrayKind::Border => &vaos.border_vao,
5453 VertexArrayKind::Scale => &vaos.scale_vao,
5454 VertexArrayKind::LineDecoration => &vaos.line_vao,
5455 }
5456 }
5457
5458 #[derive(Clone, Copy, PartialEq)]
5459 enum FramebufferKind {
5460 Main,
5461 Other,
5462 }
5463
5464