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
31pub(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 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 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 workers: Some(crate::util::wr_workers()),
113
114 ..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 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}