zng_view/
surface.rs

1use std::{collections::VecDeque, fmt};
2
3use tracing::span::EnteredSpan;
4use webrender::{
5    RenderApi, Renderer, Transaction,
6    api::{DocumentId, DynamicProperties, FontInstanceKey, FontKey, FontVariation, PipelineId},
7};
8use winit::event_loop::ActiveEventLoop;
9use zng_unit::{DipSize, DipToPx, Factor, Px, PxRect, Rgba};
10use zng_view_api::{
11    ViewProcessGen,
12    api_extension::{ApiExtensionId, ApiExtensionPayload},
13    font::{FontFaceId, FontId, FontOptions, FontVariationName},
14    image::{ImageId, ImageLoadedData, ImageMaskMode, ImageTextureId},
15    window::{FrameCapture, FrameId, FrameRequest, FrameUpdateRequest, HeadlessRequest, RenderMode, WindowId},
16};
17
18use crate::{
19    AppEventSender, FrameReadyMsg, WrNotifier,
20    display_list::{DisplayListCache, display_list_to_webrender},
21    extensions::{
22        self, BlobExtensionsImgHandler, DisplayListExtAdapter, FrameReadyArgs, RedrawArgs, RendererCommandArgs, RendererConfigArgs,
23        RendererDeinitedArgs, RendererExtension, RendererInitedArgs, WindowConfigArgs, WindowExtension,
24    },
25    gl::{GlContext, GlContextManager},
26    image_cache::{Image, ImageCache, ImageUseMap, WrImageCache},
27    px_wr::PxToWr as _,
28    util::{PxToWinit, frame_render_reasons, frame_update_render_reasons},
29};
30
31/// A headless "window".
32pub(crate) struct Surface {
33    id: WindowId,
34    pipeline_id: PipelineId,
35    document_id: DocumentId,
36    api: RenderApi,
37    size: DipSize,
38    scale_factor: Factor,
39
40    context: GlContext,
41    renderer: Option<Renderer>,
42    renderer_exts: Vec<(ApiExtensionId, Box<dyn RendererExtension>)>,
43    external_images: extensions::ExternalImages,
44    image_use: ImageUseMap,
45
46    display_list_cache: DisplayListCache,
47    clear_color: Option<Rgba>,
48
49    pending_frames: VecDeque<(FrameId, FrameCapture, Option<EnteredSpan>)>,
50    rendered_frame_id: FrameId,
51    resized: bool,
52}
53impl fmt::Debug for Surface {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        f.debug_struct("Surface")
56            .field("id", &self.id)
57            .field("pipeline_id", &self.pipeline_id)
58            .field("size", &self.size)
59            .field("scale_factor", &self.scale_factor)
60            .finish_non_exhaustive()
61    }
62}
63impl Surface {
64    pub fn open(
65        vp_gen: ViewProcessGen,
66        cfg: HeadlessRequest,
67        winit_loop: &ActiveEventLoop,
68        gl_manager: &mut GlContextManager,
69        mut window_exts: Vec<(ApiExtensionId, Box<dyn WindowExtension>)>,
70        mut renderer_exts: Vec<(ApiExtensionId, Box<dyn RendererExtension>)>,
71        event_sender: AppEventSender,
72    ) -> Self {
73        let id = cfg.id;
74
75        #[cfg(windows)]
76        let mut prefer_egl = false;
77        #[cfg(not(windows))]
78        let prefer_egl = false;
79
80        for (id, ext) in &mut window_exts {
81            ext.configure(&mut WindowConfigArgs {
82                config: cfg.extensions.iter().find(|(k, _)| k == id).map(|(_, p)| p),
83                window: None,
84            });
85
86            #[cfg(windows)]
87            if let Some(ext) = ext.as_any().downcast_ref::<crate::extensions::PreferAngleExt>() {
88                prefer_egl = ext.prefer_egl;
89            }
90        }
91
92        let mut context = gl_manager.create_headless(id, winit_loop, cfg.render_mode, &event_sender, prefer_egl);
93
94        let size = cfg.size.to_px(cfg.scale_factor);
95        context.resize(size.to_winit());
96
97        let mut opts = webrender::WebRenderOptions {
98            // text-aa config from Firefox.
99            enable_aa: true,
100            enable_subpixel_aa: cfg!(not(target_os = "android")),
101
102            renderer_id: Some(((vp_gen.get() as u64) << 32) | id.get() as u64),
103
104            // this clear color paints over the one set using `Renderer::set_clear_color`.
105            clear_color: webrender::api::ColorF::new(0.0, 0.0, 0.0, 0.0),
106
107            allow_advanced_blend_equation: context.is_software(),
108            clear_caches_with_quads: !context.is_software(),
109            enable_gpu_markers: !context.is_software(),
110
111            // extensions expect this to be set.
112            workers: Some(crate::util::wr_workers()),
113
114            //panic_on_gl_error: true,
115            ..Default::default()
116        };
117        let mut blobs = BlobExtensionsImgHandler(vec![]);
118        for (id, ext) in &mut renderer_exts {
119            ext.configure(&mut RendererConfigArgs {
120                config: cfg.extensions.iter().find(|(k, _)| k == id).map(|(_, v)| v),
121                options: &mut opts,
122                blobs: &mut blobs.0,
123                window: None,
124                context: &mut context,
125            });
126        }
127        if !opts.enable_multithreading {
128            for b in &mut blobs.0 {
129                b.enable_multithreading(false);
130            }
131        }
132        opts.blob_image_handler = Some(Box::new(blobs));
133
134        let device_size = cfg.size.to_px(cfg.scale_factor).to_wr_device();
135
136        let (mut renderer, sender) =
137            webrender::create_webrender_instance(context.gl().clone(), WrNotifier::create(id, event_sender), opts, None).unwrap();
138        renderer.set_external_image_handler(WrImageCache::new_boxed());
139
140        let mut external_images = extensions::ExternalImages::default();
141
142        let mut api = sender.create_api();
143        let document_id = api.add_document(device_size);
144        let pipeline_id = webrender::api::PipelineId(vp_gen.get(), id.get());
145
146        renderer_exts.retain_mut(|(_, ext)| {
147            ext.renderer_inited(&mut RendererInitedArgs {
148                renderer: &mut renderer,
149                external_images: &mut external_images,
150                api_sender: &sender,
151                api: &mut api,
152                document_id,
153                pipeline_id,
154                window: None,
155                context: &mut context,
156            });
157            !ext.is_init_only()
158        });
159
160        Self {
161            id,
162            pipeline_id,
163            document_id,
164            display_list_cache: DisplayListCache::new(pipeline_id, api.get_namespace_id()),
165            api,
166            size: cfg.size,
167            scale_factor: cfg.scale_factor,
168
169            context,
170            renderer: Some(renderer),
171            renderer_exts,
172            external_images,
173            image_use: ImageUseMap::default(),
174
175            clear_color: None,
176
177            pending_frames: VecDeque::new(),
178            rendered_frame_id: FrameId::INVALID,
179            resized: true,
180        }
181    }
182
183    pub fn render_mode(&self) -> RenderMode {
184        self.context.render_mode()
185    }
186
187    pub fn id(&self) -> WindowId {
188        self.id
189    }
190
191    pub fn frame_id(&self) -> FrameId {
192        self.rendered_frame_id
193    }
194
195    pub fn set_size(&mut self, size: DipSize, scale_factor: Factor) {
196        if self.size != size || (self.scale_factor - scale_factor).abs().0 > 0.001 {
197            self.size = size;
198            self.scale_factor = scale_factor;
199            self.context.make_current();
200            let px_size = size.to_px(self.scale_factor);
201            self.context.resize(px_size.to_winit());
202            self.resized = true;
203        }
204    }
205
206    pub fn use_image(&mut self, image: &Image) -> ImageTextureId {
207        self.image_use.new_use(image, self.document_id, &mut self.api)
208    }
209
210    pub fn update_image(&mut self, texture_id: ImageTextureId, image: &Image) {
211        self.image_use.update_use(texture_id, image, self.document_id, &mut self.api);
212    }
213
214    pub fn delete_image(&mut self, texture_id: ImageTextureId) {
215        self.image_use.delete(texture_id, self.document_id, &mut self.api);
216    }
217
218    pub fn add_font_face(&mut self, font: Vec<u8>, index: u32) -> FontFaceId {
219        #[cfg(target_os = "macos")]
220        let index = {
221            if index != 0 {
222                tracing::error!("webrender does not support font index on macOS, ignoring `{index}` will use `0`");
223            }
224            0
225        };
226
227        let key = self.api.generate_font_key();
228        let mut txn = webrender::Transaction::new();
229        txn.add_raw_font(key, font, index);
230        self.api.send_transaction(self.document_id, txn);
231        FontFaceId::from_raw(key.1)
232    }
233
234    pub fn delete_font_face(&mut self, font_face_id: FontFaceId) {
235        let mut txn = webrender::Transaction::new();
236        txn.delete_font(FontKey(self.api.get_namespace_id(), font_face_id.get()));
237        self.api.send_transaction(self.document_id, txn);
238    }
239
240    pub fn add_font(
241        &mut self,
242        font_face_id: FontFaceId,
243        glyph_size: Px,
244        options: FontOptions,
245        variations: Vec<(FontVariationName, f32)>,
246    ) -> FontId {
247        let key = self.api.generate_font_instance_key();
248        let mut txn = webrender::Transaction::new();
249        txn.add_font_instance(
250            key,
251            FontKey(self.api.get_namespace_id(), font_face_id.get()),
252            glyph_size.to_wr().get(),
253            options.to_wr(),
254            None,
255            variations
256                .into_iter()
257                .map(|(n, v)| FontVariation {
258                    tag: u32::from_be_bytes(n),
259                    value: v,
260                })
261                .collect(),
262        );
263        self.api.send_transaction(self.document_id, txn);
264        FontId::from_raw(key.1)
265    }
266
267    pub fn delete_font(&mut self, font_id: FontId) {
268        let mut txn = webrender::Transaction::new();
269        txn.delete_font_instance(FontInstanceKey(self.api.get_namespace_id(), font_id.get()));
270        self.api.send_transaction(self.document_id, txn);
271    }
272
273    fn push_resize(&mut self, txn: &mut Transaction) {
274        if self.resized {
275            self.resized = false;
276            let rect = PxRect::from_size(self.size.to_px(self.scale_factor)).to_wr_device();
277            txn.set_document_view(rect);
278        }
279    }
280
281    pub fn render(&mut self, frame: FrameRequest) {
282        let _span = tracing::trace_span!("render").entered();
283
284        let render_reasons = frame_render_reasons(&frame);
285
286        self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
287
288        let mut txn = Transaction::new();
289        txn.reset_dynamic_properties();
290        txn.append_dynamic_properties(DynamicProperties {
291            transforms: vec![],
292            floats: vec![],
293            colors: vec![],
294        });
295
296        let display_list = display_list_to_webrender(
297            frame.display_list,
298            &mut DisplayListExtAdapter {
299                frame_id: frame.id,
300                extensions: &mut self.renderer_exts,
301                transaction: &mut txn,
302                renderer: self.renderer.as_mut().unwrap(),
303                api: &mut self.api,
304                external_images: &mut self.external_images,
305            },
306            &mut self.display_list_cache,
307        );
308
309        self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
310        self.clear_color = Some(frame.clear_color);
311
312        txn.set_display_list(webrender::api::Epoch(frame.id.epoch()), (self.pipeline_id, display_list));
313
314        txn.set_root_pipeline(self.pipeline_id);
315
316        self.push_resize(&mut txn);
317
318        txn.generate_frame(frame.id.get(), render_reasons);
319
320        let frame_scope =
321            tracing::trace_span!("<frame>", ?frame.id, capture = ?frame.capture, from_update = false, thread = "<webrender>").entered();
322        self.pending_frames.push_back((frame.id, frame.capture, Some(frame_scope)));
323
324        self.api.send_transaction(self.document_id, txn);
325    }
326
327    pub fn render_update(&mut self, frame: FrameUpdateRequest) {
328        let _span = tracing::trace_span!("render_update").entered();
329
330        let render_reasons = frame_update_render_reasons(&frame);
331
332        if let Some(color) = frame.clear_color {
333            self.clear_color = Some(color);
334            self.renderer.as_mut().unwrap().set_clear_color(color.to_wr());
335        }
336
337        let resized = self.resized;
338
339        let mut txn = Transaction::new();
340        txn.set_root_pipeline(self.pipeline_id);
341        self.push_resize(&mut txn);
342        txn.generate_frame(self.frame_id().get(), render_reasons);
343
344        let frame_scope = match self.display_list_cache.update(
345            &mut DisplayListExtAdapter {
346                frame_id: self.frame_id(),
347                extensions: &mut self.renderer_exts,
348                transaction: &mut txn,
349                renderer: self.renderer.as_mut().unwrap(),
350                api: &mut self.api,
351                external_images: &mut self.external_images,
352            },
353            frame.transforms,
354            frame.floats,
355            frame.colors,
356            frame.extensions,
357            resized,
358        ) {
359            Ok(p) => {
360                if let Some(p) = p {
361                    txn.append_dynamic_properties(p);
362                }
363
364                tracing::trace_span!("<frame-update>", ?frame.id, capture = ?frame.capture, thread = "<webrender>")
365            }
366            Err(d) => {
367                txn.reset_dynamic_properties();
368                txn.append_dynamic_properties(DynamicProperties {
369                    transforms: vec![],
370                    floats: vec![],
371                    colors: vec![],
372                });
373
374                txn.set_display_list(webrender::api::Epoch(frame.id.epoch()), (self.pipeline_id, d));
375
376                tracing::trace_span!("<frame>", ?frame.id, capture = ?frame.capture, from_update = true, thread = "<webrender>")
377            }
378        };
379
380        self.pending_frames
381            .push_back((frame.id, frame.capture, Some(frame_scope.entered())));
382
383        self.api.send_transaction(self.document_id, txn);
384    }
385
386    pub fn on_frame_ready(&mut self, msg: FrameReadyMsg, images: &mut ImageCache) -> (FrameId, Option<ImageLoadedData>) {
387        let (frame_id, capture, _) = self
388            .pending_frames
389            .pop_front()
390            .unwrap_or((self.rendered_frame_id, FrameCapture::None, None));
391        self.rendered_frame_id = frame_id;
392
393        let mut captured_data = None;
394
395        let mut ext_args = FrameReadyArgs {
396            frame_id,
397            redraw: msg.composite_needed || capture != FrameCapture::None,
398        };
399        for (_, ext) in &mut self.renderer_exts {
400            ext.frame_ready(&mut ext_args);
401            ext_args.redraw |= msg.composite_needed || capture != FrameCapture::None;
402        }
403
404        if ext_args.redraw || msg.composite_needed || capture != FrameCapture::None {
405            self.context.make_current();
406            let renderer = self.renderer.as_mut().unwrap();
407
408            let size = self.size.to_px(self.scale_factor);
409
410            if msg.composite_needed {
411                renderer.update();
412                renderer.render(size.to_wr_device(), 0).unwrap();
413                let _ = renderer.flush_pipeline_info();
414            }
415
416            for (_, ext) in &mut self.renderer_exts {
417                ext.redraw(&mut RedrawArgs {
418                    scale_factor: self.scale_factor,
419                    size,
420                    context: &mut self.context,
421                });
422            }
423
424            let capture = match capture {
425                FrameCapture::None => None,
426                FrameCapture::Full => Some(None),
427                FrameCapture::Mask(m) => Some(Some(m)),
428            };
429            if let Some(mask) = capture {
430                captured_data = Some(images.frame_image_data(
431                    &**self.context.gl(),
432                    PxRect::from_size(self.size.to_px(self.scale_factor)),
433                    self.scale_factor,
434                    mask,
435                ));
436            }
437        }
438        (frame_id, captured_data)
439    }
440
441    pub fn frame_image(&mut self, images: &mut ImageCache, mask: Option<ImageMaskMode>) -> ImageId {
442        images.frame_image(
443            &**self.context.gl(),
444            PxRect::from_size(self.size.to_px(self.scale_factor)),
445            self.id,
446            self.rendered_frame_id,
447            self.scale_factor,
448            mask,
449        )
450    }
451
452    pub fn frame_image_rect(&mut self, images: &mut ImageCache, rect: PxRect, mask: Option<ImageMaskMode>) -> ImageId {
453        let rect = PxRect::from_size(self.size.to_px(self.scale_factor)).intersection(&rect).unwrap();
454        images.frame_image(&**self.context.gl(), rect, self.id, self.rendered_frame_id, self.scale_factor, mask)
455    }
456
457    /// Calls the render extension command.
458    pub fn render_extension(&mut self, extension_id: ApiExtensionId, request: ApiExtensionPayload) -> ApiExtensionPayload {
459        let mut redraw = false;
460
461        let mut r = None;
462
463        for (id, ext) in &mut self.renderer_exts {
464            if *id == extension_id {
465                r = Some(ext.command(&mut RendererCommandArgs {
466                    renderer: self.renderer.as_mut().unwrap(),
467                    api: &mut self.api,
468                    request,
469                    window: None,
470                    redraw: &mut redraw,
471                    context: &mut self.context,
472                }));
473                break;
474            }
475        }
476
477        if redraw {
478            let size = self.size.to_px(self.scale_factor);
479            for (_, ext) in &mut self.renderer_exts {
480                ext.redraw(&mut RedrawArgs {
481                    scale_factor: self.scale_factor,
482                    size,
483                    context: &mut self.context,
484                });
485            }
486        }
487
488        r.unwrap_or_else(|| ApiExtensionPayload::unknown_extension(extension_id))
489    }
490
491    pub(crate) fn on_low_memory(&mut self) {
492        self.api.notify_memory_pressure();
493
494        for (_, ext) in &mut self.renderer_exts {
495            ext.low_memory();
496        }
497    }
498}
499impl Drop for Surface {
500    fn drop(&mut self) {
501        self.context.make_current();
502        self.renderer.take().unwrap().deinit();
503        for (_, ext) in &mut self.renderer_exts {
504            ext.renderer_deinited(&mut RendererDeinitedArgs {
505                document_id: self.document_id,
506                pipeline_id: self.pipeline_id,
507                context: &mut self.context,
508                window: None,
509            })
510        }
511    }
512}