Source code

Revision control

Other Tools

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
use std::ffi::{CStr, CString};
6
#[cfg(not(target_os = "macos"))]
7
use std::ffi::OsString;
8
#[cfg(target_os = "windows")]
9
use std::os::windows::ffi::OsStringExt;
10
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
11
use std::os::unix::ffi::OsStringExt;
12
use std::io::Cursor;
13
use std::{mem, slice, ptr, env};
14
use std::marker::PhantomData;
15
use std::path::PathBuf;
16
use std::rc::Rc;
17
use std::cell::RefCell;
18
use std::sync::Arc;
19
use std::sync::atomic::{AtomicUsize, Ordering};
20
use std::ops::Range;
21
use std::os::raw::{c_void, c_char, c_float};
22
#[cfg(target_os = "android")]
23
use std::os::raw::{c_int};
24
use std::time::Duration;
25
use gleam::gl;
26
27
use webrender::{
28
api::*, api::units::*, ApiRecordingReceiver, AsyncPropertySampler, AsyncScreenshotHandle,
29
BinaryRecorder, Compositor, DebugFlags, Device,
30
NativeSurfaceId, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats,
31
SceneBuilderHooks, ShaderPrecacheFlags, Shaders, ThreadListener, UploadMethod, VertexUsageHint,
32
WrShaders, set_profiler_hooks, CompositorConfig, NativeSurfaceInfo, NativeTileId
33
};
34
use thread_profiler::register_thread_with_profiler;
35
use moz2d_renderer::Moz2dBlobImageHandler;
36
use program_cache::{WrProgramCache, remove_disk_cache};
37
use rayon;
38
use num_cpus;
39
use euclid::SideOffsets2D;
40
use nsstring::nsAString;
41
42
#[cfg(target_os = "macos")]
43
use core_foundation::string::CFString;
44
#[cfg(target_os = "macos")]
45
use core_graphics::font::CGFont;
46
47
extern "C" {
48
#[cfg(target_os = "android")]
49
fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
50
}
51
52
/// The unique id for WR resource identification.
53
static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
54
55
/// Special value handled in this wrapper layer to signify a redundant clip chain.
56
pub const ROOT_CLIP_CHAIN: u64 = !0;
57
58
fn next_namespace_id() -> IdNamespace {
59
IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
60
}
61
62
/// Whether a border should be antialiased.
63
#[repr(C)]
64
#[derive(Eq, PartialEq, Copy, Clone)]
65
pub enum AntialiasBorder {
66
No = 0,
67
Yes,
68
}
69
70
/// Used to indicate if an image is opaque, or has an alpha channel.
71
#[repr(u8)]
72
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
73
pub enum OpacityType {
74
Opaque = 0,
75
HasAlphaChannel = 1,
76
}
77
78
/// cbindgen:field-names=[mHandle]
79
/// cbindgen:derive-lt=true
80
/// cbindgen:derive-lte=true
81
/// cbindgen:derive-neq=true
82
type WrEpoch = Epoch;
83
/// cbindgen:field-names=[mHandle]
84
/// cbindgen:derive-lt=true
85
/// cbindgen:derive-lte=true
86
/// cbindgen:derive-neq=true
87
pub type WrIdNamespace = IdNamespace;
88
89
/// cbindgen:field-names=[mNamespace, mHandle]
90
type WrDocumentId = DocumentId;
91
/// cbindgen:field-names=[mNamespace, mHandle]
92
type WrPipelineId = PipelineId;
93
/// cbindgen:field-names=[mNamespace, mHandle]
94
/// cbindgen:derive-neq=true
95
type WrImageKey = ImageKey;
96
/// cbindgen:field-names=[mNamespace, mHandle]
97
pub type WrFontKey = FontKey;
98
/// cbindgen:field-names=[mNamespace, mHandle]
99
pub type WrFontInstanceKey = FontInstanceKey;
100
/// cbindgen:field-names=[mNamespace, mHandle]
101
type WrYuvColorSpace = YuvColorSpace;
102
/// cbindgen:field-names=[mNamespace, mHandle]
103
type WrColorDepth = ColorDepth;
104
/// cbindgen:field-names=[mNamespace, mHandle]
105
type WrColorRange = ColorRange;
106
107
#[repr(C)]
108
pub struct WrSpaceAndClip {
109
space: WrSpatialId,
110
clip: WrClipId,
111
}
112
113
impl WrSpaceAndClip {
114
fn from_webrender(sac: SpaceAndClipInfo) -> Self {
115
WrSpaceAndClip {
116
space: WrSpatialId { id: sac.spatial_id.0 },
117
clip: WrClipId::from_webrender(sac.clip_id),
118
}
119
}
120
121
fn to_webrender(&self, pipeline_id: WrPipelineId) -> SpaceAndClipInfo {
122
SpaceAndClipInfo {
123
spatial_id: self.space.to_webrender(pipeline_id),
124
clip_id: self.clip.to_webrender(pipeline_id),
125
}
126
}
127
}
128
129
#[inline]
130
fn clip_chain_id_to_webrender(id: u64, pipeline_id: WrPipelineId) -> ClipId {
131
if id == ROOT_CLIP_CHAIN {
132
ClipId::root(pipeline_id)
133
} else {
134
ClipId::ClipChain(ClipChainId(id, pipeline_id))
135
}
136
}
137
138
#[repr(C)]
139
pub struct WrSpaceAndClipChain {
140
space: WrSpatialId,
141
clip_chain: u64,
142
}
143
144
impl WrSpaceAndClipChain {
145
fn to_webrender(&self, pipeline_id: WrPipelineId) -> SpaceAndClipInfo {
146
//Warning: special case here to support dummy clip chain
147
SpaceAndClipInfo {
148
spatial_id: self.space.to_webrender(pipeline_id),
149
clip_id: clip_chain_id_to_webrender(self.clip_chain, pipeline_id),
150
}
151
}
152
}
153
154
#[repr(C)]
155
pub enum WrStackingContextClip {
156
None,
157
ClipId(WrClipId),
158
ClipChain(u64),
159
}
160
161
impl WrStackingContextClip {
162
fn to_webrender(&self, pipeline_id: WrPipelineId) -> Option<ClipId> {
163
match *self {
164
WrStackingContextClip::None => None,
165
WrStackingContextClip::ClipChain(id) => Some(clip_chain_id_to_webrender(id, pipeline_id)),
166
WrStackingContextClip::ClipId(id) => Some(id.to_webrender(pipeline_id)),
167
}
168
}
169
}
170
171
unsafe fn make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
172
if ptr.is_null() {
173
&[]
174
} else {
175
slice::from_raw_parts(ptr, len)
176
}
177
}
178
179
unsafe fn make_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
180
if ptr.is_null() {
181
&mut []
182
} else {
183
slice::from_raw_parts_mut(ptr, len)
184
}
185
}
186
187
pub struct DocumentHandle {
188
api: RenderApi,
189
document_id: DocumentId,
190
}
191
192
impl DocumentHandle {
193
pub fn new(api: RenderApi, size: DeviceIntSize, layer: i8) -> DocumentHandle {
194
let doc = api.add_document(size, layer);
195
DocumentHandle {
196
api: api,
197
document_id: doc
198
}
199
}
200
201
pub fn new_with_id(api: RenderApi, size: DeviceIntSize, layer: i8, id: u32) -> DocumentHandle {
202
let doc = api.add_document_with_id(size, layer, id);
203
DocumentHandle {
204
api: api,
205
document_id: doc
206
}
207
}
208
}
209
210
#[repr(C)]
211
pub struct WrVecU8 {
212
data: *mut u8,
213
length: usize,
214
capacity: usize,
215
}
216
217
impl WrVecU8 {
218
fn to_vec(self) -> Vec<u8> {
219
unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) }
220
}
221
222
// Equivalent to `to_vec` but clears self instead of consuming the value.
223
fn flush_into_vec(&mut self) -> Vec<u8> {
224
self.convert_into_vec::<u8>()
225
}
226
227
// Like flush_into_vec, but also does an unsafe conversion to the desired type.
228
fn convert_into_vec<T>(&mut self) -> Vec<T> {
229
let vec = unsafe {
230
Vec::from_raw_parts(
231
self.data as *mut T,
232
self.length / mem::size_of::<T>(),
233
self.capacity / mem::size_of::<T>(),
234
)
235
};
236
self.data = ptr::null_mut();
237
self.length = 0;
238
self.capacity = 0;
239
vec
240
}
241
242
fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
243
let w = WrVecU8 {
244
data: v.as_mut_ptr(),
245
length: v.len(),
246
capacity: v.capacity(),
247
};
248
mem::forget(v);
249
w
250
}
251
252
fn push_bytes(&mut self, bytes: &[u8]) {
253
let mut vec = self.flush_into_vec();
254
vec.extend_from_slice(bytes);
255
*self = Self::from_vec(vec);
256
}
257
}
258
259
#[repr(C)]
260
pub struct FfiVec<T> {
261
// We use a *const instead of a *mut because we don't want the C++ side
262
// to be mutating this. It is strictly read-only from C++
263
data: *const T,
264
length: usize,
265
capacity: usize,
266
}
267
268
impl<T> FfiVec<T> {
269
fn from_vec(v: Vec<T>) -> FfiVec<T> {
270
let ret = FfiVec {
271
data: v.as_ptr(),
272
length: v.len(),
273
capacity: v.capacity(),
274
};
275
mem::forget(v);
276
ret
277
}
278
}
279
280
impl<T> Drop for FfiVec<T> {
281
fn drop(&mut self) {
282
// turn the stuff back into a Vec and let it be freed normally
283
let _ = unsafe {
284
Vec::from_raw_parts(
285
self.data as *mut T,
286
self.length,
287
self.capacity
288
)
289
};
290
}
291
}
292
293
#[no_mangle]
294
pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) {
295
v.push_bytes(bytes.as_slice());
296
}
297
298
#[no_mangle]
299
pub extern "C" fn wr_vec_u8_free(v: WrVecU8) {
300
v.to_vec();
301
}
302
303
#[repr(C)]
304
pub struct ByteSlice<'a> {
305
buffer: *const u8,
306
len: usize,
307
_phantom: PhantomData<&'a ()>,
308
}
309
310
impl<'a> ByteSlice<'a> {
311
pub fn new(slice: &'a [u8]) -> ByteSlice<'a> {
312
ByteSlice {
313
buffer: slice.as_ptr(),
314
len: slice.len(),
315
_phantom: PhantomData,
316
}
317
}
318
319
pub fn as_slice(&self) -> &'a [u8] {
320
unsafe { make_slice(self.buffer, self.len) }
321
}
322
}
323
324
#[repr(C)]
325
pub struct MutByteSlice<'a> {
326
buffer: *mut u8,
327
len: usize,
328
_phantom: PhantomData<&'a ()>,
329
}
330
331
impl<'a> MutByteSlice<'a> {
332
pub fn new(slice: &'a mut [u8]) -> MutByteSlice<'a> {
333
let len = slice.len();
334
MutByteSlice {
335
buffer: slice.as_mut_ptr(),
336
len: len,
337
_phantom: PhantomData,
338
}
339
}
340
341
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
342
unsafe { make_slice_mut(self.buffer, self.len) }
343
}
344
}
345
346
#[repr(C)]
347
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
348
pub struct WrImageDescriptor {
349
pub format: ImageFormat,
350
pub width: i32,
351
pub height: i32,
352
pub stride: i32,
353
pub opacity: OpacityType,
354
// TODO(gw): Remove this flag (use prim flags instead).
355
pub prefer_compositor_surface: bool,
356
}
357
358
impl<'a> Into<ImageDescriptor> for &'a WrImageDescriptor {
359
fn into(self) -> ImageDescriptor {
360
let mut flags = ImageDescriptorFlags::empty();
361
362
if self.opacity == OpacityType::Opaque {
363
flags |= ImageDescriptorFlags::IS_OPAQUE;
364
}
365
366
ImageDescriptor {
367
size: DeviceIntSize::new(self.width, self.height),
368
stride: if self.stride != 0 {
369
Some(self.stride)
370
} else {
371
None
372
},
373
format: self.format,
374
offset: 0,
375
flags,
376
}
377
}
378
}
379
380
#[repr(u32)]
381
#[allow(dead_code)]
382
enum WrExternalImageType {
383
RawData,
384
NativeTexture,
385
Invalid,
386
}
387
388
#[repr(C)]
389
struct WrExternalImage {
390
image_type: WrExternalImageType,
391
392
// external texture handle
393
handle: u32,
394
// external texture coordinate
395
u0: f32,
396
v0: f32,
397
u1: f32,
398
v1: f32,
399
400
// external image buffer
401
buff: *const u8,
402
size: usize,
403
}
404
405
extern "C" {
406
fn wr_renderer_lock_external_image(
407
renderer: *mut c_void,
408
external_image_id: ExternalImageId,
409
channel_index: u8,
410
rendering: ImageRendering) -> WrExternalImage;
411
fn wr_renderer_unlock_external_image(
412
renderer: *mut c_void,
413
external_image_id: ExternalImageId,
414
channel_index: u8);
415
}
416
417
#[repr(C)]
418
#[derive(Copy, Clone, Debug)]
419
pub struct WrExternalImageHandler {
420
external_image_obj: *mut c_void,
421
}
422
423
impl ExternalImageHandler for WrExternalImageHandler {
424
fn lock(&mut self,
425
id: ExternalImageId,
426
channel_index: u8,
427
rendering: ImageRendering)
428
-> ExternalImage {
429
430
let image = unsafe { wr_renderer_lock_external_image(self.external_image_obj, id, channel_index, rendering) };
431
ExternalImage {
432
uv: TexelRect::new(image.u0, image.v0, image.u1, image.v1),
433
source: match image.image_type {
434
WrExternalImageType::NativeTexture => ExternalImageSource::NativeTexture(image.handle),
435
WrExternalImageType::RawData => ExternalImageSource::RawData(unsafe { make_slice(image.buff, image.size) }),
436
WrExternalImageType::Invalid => ExternalImageSource::Invalid,
437
},
438
}
439
}
440
441
fn unlock(&mut self,
442
id: ExternalImageId,
443
channel_index: u8) {
444
unsafe {
445
wr_renderer_unlock_external_image(self.external_image_obj, id, channel_index);
446
}
447
}
448
}
449
450
#[repr(C)]
451
#[derive(Clone, Copy)]
452
// Used for ComponentTransfer only
453
pub struct WrFilterData {
454
funcR_type: ComponentTransferFuncType,
455
R_values: *mut c_float,
456
R_values_count: usize,
457
funcG_type: ComponentTransferFuncType,
458
G_values: *mut c_float,
459
G_values_count: usize,
460
funcB_type: ComponentTransferFuncType,
461
B_values: *mut c_float,
462
B_values_count: usize,
463
funcA_type: ComponentTransferFuncType,
464
A_values: *mut c_float,
465
A_values_count: usize,
466
}
467
468
#[repr(u32)]
469
pub enum WrAnimationType {
470
Transform = 0,
471
Opacity = 1,
472
}
473
474
#[repr(C)]
475
pub struct WrAnimationProperty {
476
effect_type: WrAnimationType,
477
id: u64,
478
}
479
480
/// cbindgen:derive-eq=false
481
#[repr(C)]
482
#[derive(Debug)]
483
pub struct WrTransformProperty {
484
pub id: u64,
485
pub transform: LayoutTransform,
486
}
487
488
#[repr(C)]
489
#[derive(Copy, Clone, Debug)]
490
pub struct WrOpacityProperty {
491
pub id: u64,
492
pub opacity: f32,
493
}
494
495
/// cbindgen:field-names=[mHandle]
496
/// cbindgen:derive-lt=true
497
/// cbindgen:derive-lte=true
498
#[repr(C)]
499
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
500
pub struct WrWindowId(u64);
501
502
fn get_proc_address(glcontext_ptr: *mut c_void,
503
name: &str)
504
-> *const c_void {
505
506
extern "C" {
507
fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void,
508
procname: *const c_char)
509
-> *const c_void;
510
}
511
512
let symbol_name = CString::new(name).unwrap();
513
let symbol = unsafe { get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr()) };
514
515
if symbol.is_null() {
516
// XXX Bug 1322949 Make whitelist for extensions
517
warn!("Could not find symbol {:?} by glcontext", symbol_name);
518
}
519
520
symbol as *const _
521
}
522
523
#[repr(C)]
524
pub enum TelemetryProbe {
525
SceneBuildTime = 0,
526
SceneSwapTime = 1,
527
FrameBuildTime = 2,
528
}
529
530
extern "C" {
531
fn is_in_compositor_thread() -> bool;
532
fn is_in_render_thread() -> bool;
533
fn is_in_main_thread() -> bool;
534
fn is_glcontext_gles(glcontext_ptr: *mut c_void) -> bool;
535
fn is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool;
536
// Enables binary recording that can be used with `wrench replay`
537
// Outputs a wr-record-*.bin file for each window that is shown
538
// Note: wrench will panic if external images are used, they can
539
// be disabled in WebRenderBridgeParent::ProcessWebRenderCommands
540
// by commenting out the path that adds an external image ID
541
fn gfx_use_wrench() -> bool;
542
fn gfx_wr_resource_path_override() -> *const c_char;
543
// TODO: make gfx_critical_error() work.
544
// We still have problem to pass the error message from render/render_backend
545
// thread to main thread now.
546
#[allow(dead_code)]
547
fn gfx_critical_error(msg: *const c_char);
548
fn gfx_critical_note(msg: *const c_char);
549
fn record_telemetry_time(probe: TelemetryProbe, time_ns: u64);
550
}
551
552
struct CppNotifier {
553
window_id: WrWindowId,
554
}
555
556
unsafe impl Send for CppNotifier {}
557
558
extern "C" {
559
fn wr_notifier_wake_up(window_id: WrWindowId);
560
fn wr_notifier_new_frame_ready(window_id: WrWindowId);
561
fn wr_notifier_nop_frame_done(window_id: WrWindowId);
562
fn wr_notifier_external_event(window_id: WrWindowId,
563
raw_event: usize);
564
fn wr_schedule_render(window_id: WrWindowId,
565
document_id_array: *const WrDocumentId,
566
document_id_count: usize);
567
fn wr_finished_scene_build(window_id: WrWindowId,
568
document_id_array: *const WrDocumentId,
569
document_id_count: usize,
570
pipeline_info: WrPipelineInfo);
571
572
fn wr_transaction_notification_notified(handler: usize, when: Checkpoint);
573
}
574
575
impl RenderNotifier for CppNotifier {
576
fn clone(&self) -> Box<dyn RenderNotifier> {
577
Box::new(CppNotifier {
578
window_id: self.window_id,
579
})
580
}
581
582
fn wake_up(&self) {
583
unsafe {
584
wr_notifier_wake_up(self.window_id);
585
}
586
}
587
588
fn new_frame_ready(&self,
589
_: DocumentId,
590
_scrolled: bool,
591
composite_needed: bool,
592
render_time_ns: Option<u64>) {
593
unsafe {
594
if let Some(time) = render_time_ns {
595
record_telemetry_time(TelemetryProbe::FrameBuildTime, time);
596
}
597
if composite_needed {
598
wr_notifier_new_frame_ready(self.window_id);
599
} else {
600
wr_notifier_nop_frame_done(self.window_id);
601
}
602
}
603
}
604
605
fn external_event(&self,
606
event: ExternalEvent) {
607
unsafe {
608
wr_notifier_external_event(self.window_id, event.unwrap());
609
}
610
}
611
}
612
613
#[no_mangle]
614
pub extern "C" fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
615
external_image_handler: &mut WrExternalImageHandler) {
616
renderer.set_external_image_handler(Box::new(external_image_handler.clone()));
617
}
618
619
#[no_mangle]
620
pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) {
621
renderer.update();
622
}
623
624
#[repr(C)]
625
pub struct WrRenderResult {
626
result: bool,
627
dirty_rects: FfiVec<DeviceIntRect>,
628
}
629
630
#[no_mangle]
631
pub unsafe extern "C" fn wr_render_result_delete(_result: WrRenderResult) {
632
// _result will be dropped here, and the drop impl on FfiVec will free
633
// the underlying vec memory
634
}
635
636
#[no_mangle]
637
pub extern "C" fn wr_renderer_render(renderer: &mut Renderer,
638
width: i32,
639
height: i32,
640
had_slow_frame: bool,
641
out_stats: &mut RendererStats) -> WrRenderResult {
642
if had_slow_frame {
643
renderer.notify_slow_frame();
644
}
645
match renderer.render(DeviceIntSize::new(width, height)) {
646
Ok(results) => {
647
*out_stats = results.stats;
648
WrRenderResult {
649
result: true,
650
dirty_rects: FfiVec::from_vec(results.dirty_rects),
651
}
652
}
653
Err(errors) => {
654
for e in errors {
655
warn!(" Failed to render: {:?}", e);
656
let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
657
unsafe {
658
gfx_critical_note(msg.as_ptr());
659
}
660
}
661
WrRenderResult {
662
result: false,
663
dirty_rects: FfiVec::from_vec(vec![]),
664
}
665
},
666
}
667
}
668
669
#[no_mangle]
670
pub extern "C" fn wr_renderer_force_redraw(renderer: &mut Renderer) {
671
renderer.force_redraw();
672
}
673
674
#[no_mangle]
675
pub extern "C" fn wr_renderer_record_frame(
676
renderer: &mut Renderer,
677
image_format: ImageFormat,
678
out_handle: &mut RecordedFrameHandle,
679
out_width: &mut i32,
680
out_height: &mut i32,
681
) -> bool {
682
if let Some((handle, size)) = renderer.record_frame(image_format) {
683
*out_handle = handle;
684
*out_width = size.width;
685
*out_height = size.height;
686
687
true
688
} else {
689
false
690
}
691
}
692
693
#[no_mangle]
694
pub extern "C" fn wr_renderer_map_recorded_frame(
695
renderer: &mut Renderer,
696
handle: RecordedFrameHandle,
697
dst_buffer: *mut u8,
698
dst_buffer_len: usize,
699
dst_stride: usize,
700
) -> bool {
701
renderer.map_recorded_frame(
702
handle,
703
unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
704
dst_stride,
705
)
706
}
707
708
#[no_mangle]
709
pub extern "C" fn wr_renderer_release_composition_recorder_structures(
710
renderer: &mut Renderer,
711
) {
712
renderer.release_composition_recorder_structures();
713
}
714
715
#[no_mangle]
716
pub extern "C" fn wr_renderer_get_screenshot_async(
717
renderer: &mut Renderer,
718
window_x: i32,
719
window_y: i32,
720
window_width: i32,
721
window_height: i32,
722
buffer_width: i32,
723
buffer_height: i32,
724
image_format: ImageFormat,
725
screenshot_width: *mut i32,
726
screenshot_height: *mut i32,
727
) -> AsyncScreenshotHandle {
728
assert!(!screenshot_width.is_null());
729
assert!(!screenshot_height.is_null());
730
731
let (handle, size) = renderer.get_screenshot_async(
732
DeviceIntRect::new(
733
DeviceIntPoint::new(window_x, window_y),
734
DeviceIntSize::new(window_width, window_height),
735
),
736
DeviceIntSize::new(buffer_width, buffer_height),
737
image_format,
738
);
739
740
unsafe {
741
*screenshot_width = size.width;
742
*screenshot_height = size.height;
743
}
744
745
handle
746
}
747
748
#[no_mangle]
749
pub extern "C" fn wr_renderer_map_and_recycle_screenshot(
750
renderer: &mut Renderer,
751
handle: AsyncScreenshotHandle,
752
dst_buffer: *mut u8,
753
dst_buffer_len: usize,
754
dst_stride: usize,
755
) -> bool {
756
renderer.map_and_recycle_screenshot(
757
handle,
758
unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
759
dst_stride,
760
)
761
}
762
763
#[no_mangle]
764
pub extern "C" fn wr_renderer_release_profiler_structures(renderer: &mut Renderer) {
765
renderer.release_profiler_structures();
766
}
767
768
// Call wr_renderer_render() before calling this function.
769
#[no_mangle]
770
pub unsafe extern "C" fn wr_renderer_readback(renderer: &mut Renderer,
771
width: i32,
772
height: i32,
773
format: ImageFormat,
774
dst_buffer: *mut u8,
775
buffer_size: usize) {
776
assert!(is_in_render_thread());
777
778
let mut slice = make_slice_mut(dst_buffer, buffer_size);
779
renderer.read_pixels_into(FramebufferIntSize::new(width, height).into(),
780
format, &mut slice);
781
}
782
783
#[no_mangle]
784
pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
785
let renderer = Box::from_raw(renderer);
786
renderer.deinit();
787
// let renderer go out of scope and get dropped
788
}
789
790
#[no_mangle]
791
pub unsafe extern "C" fn wr_renderer_accumulate_memory_report(renderer: &mut Renderer,
792
report: &mut MemoryReport) {
793
*report += renderer.report_memory();
794
}
795
796
// cbindgen doesn't support tuples, so we have a little struct instead, with
797
// an Into implementation to convert from the tuple to the struct.
798
#[repr(C)]
799
pub struct WrPipelineEpoch {
800
pipeline_id: WrPipelineId,
801
document_id: WrDocumentId,
802
epoch: WrEpoch,
803
}
804
805
impl<'a> From<(&'a(WrPipelineId, WrDocumentId), &'a WrEpoch)> for WrPipelineEpoch {
806
fn from(tuple: (&(WrPipelineId, WrDocumentId), &WrEpoch)) -> WrPipelineEpoch {
807
WrPipelineEpoch {
808
pipeline_id: (tuple.0).0,
809
document_id: (tuple.0).1,
810
epoch: *tuple.1
811
}
812
}
813
}
814
815
#[repr(C)]
816
pub struct WrRemovedPipeline {
817
pipeline_id: WrPipelineId,
818
document_id: WrDocumentId,
819
}
820
821
impl<'a> From<&'a (WrPipelineId, WrDocumentId)> for WrRemovedPipeline {
822
fn from(tuple: &(WrPipelineId, WrDocumentId)) -> WrRemovedPipeline {
823
WrRemovedPipeline {
824
pipeline_id: tuple.0,
825
document_id: tuple.1,
826
}
827
}
828
}
829
830
#[repr(C)]
831
pub struct WrPipelineInfo {
832
// This contains an entry for each pipeline that was rendered, along with
833
// the epoch at which it was rendered. Rendered pipelines include the root
834
// pipeline and any other pipelines that were reachable via IFrame display
835
// items from the root pipeline.
836
epochs: FfiVec<WrPipelineEpoch>,
837
// This contains an entry for each pipeline that was removed during the
838
// last transaction. These pipelines would have been explicitly removed by
839
// calling remove_pipeline on the transaction object; the pipeline showing
840
// up in this array means that the data structures have been torn down on
841
// the webrender side, and so any remaining data structures on the caller
842
// side can now be torn down also.
843
removed_pipelines: FfiVec<WrRemovedPipeline>,
844
}
845
846
impl WrPipelineInfo {
847
fn new(info: &PipelineInfo) -> Self {
848
WrPipelineInfo {
849
epochs: FfiVec::from_vec(info.epochs.iter().map(WrPipelineEpoch::from).collect()),
850
removed_pipelines: FfiVec::from_vec(info.removed_pipelines.iter()
851
.map(WrRemovedPipeline::from).collect()),
852
}
853
}
854
}
855
856
#[no_mangle]
857
pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> WrPipelineInfo {
858
let info = renderer.flush_pipeline_info();
859
WrPipelineInfo::new(&info)
860
}
861
862
#[no_mangle]
863
pub unsafe extern "C" fn wr_pipeline_info_delete(_info: WrPipelineInfo) {
864
// _info will be dropped here, and the drop impl on FfiVec will free
865
// the underlying vec memory
866
}
867
868
extern "C" {
869
pub fn gecko_profiler_start_marker(name: *const c_char);
870
pub fn gecko_profiler_end_marker(name: *const c_char);
871
pub fn gecko_profiler_add_text_marker(
872
name: *const c_char, text_bytes: *const c_char, text_len: usize, microseconds: u64);
873
pub fn gecko_profiler_thread_is_being_profiled() -> bool;
874
}
875
876
/// Simple implementation of the WR ProfilerHooks trait to allow profile
877
/// markers to be seen in the Gecko profiler.
878
struct GeckoProfilerHooks;
879
880
impl ProfilerHooks for GeckoProfilerHooks {
881
fn begin_marker(&self, label: &CStr) {
882
unsafe {
883
gecko_profiler_start_marker(label.as_ptr());
884
}
885
}
886
887
fn end_marker(&self, label: &CStr) {
888
unsafe {
889
gecko_profiler_end_marker(label.as_ptr());
890
}
891
}
892
893
fn add_text_marker(&self, label: &CStr, text: &str, duration: Duration) {
894
unsafe {
895
// NB: This can be as_micros() once we require Rust 1.33.
896
let micros = duration.subsec_micros() as u64 + duration.as_secs() * 1000 * 1000;
897
let text_bytes = text.as_bytes();
898
gecko_profiler_add_text_marker(label.as_ptr(), text_bytes.as_ptr() as *const c_char, text_bytes.len(), micros);
899
}
900
}
901
902
fn thread_is_being_profiled(&self) -> bool {
903
unsafe { gecko_profiler_thread_is_being_profiled() }
904
}
905
}
906
907
static PROFILER_HOOKS: GeckoProfilerHooks = GeckoProfilerHooks {};
908
909
#[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &mut Transaction to an extern function
910
extern "C" {
911
// These callbacks are invoked from the scene builder thread (aka the APZ
912
// updater thread)
913
fn apz_register_updater(window_id: WrWindowId);
914
fn apz_pre_scene_swap(window_id: WrWindowId);
915
// This function takes ownership of the pipeline_info and is responsible for
916
// freeing it via wr_pipeline_info_delete.
917
fn apz_post_scene_swap(window_id: WrWindowId, pipeline_info: WrPipelineInfo);
918
fn apz_run_updater(window_id: WrWindowId);
919
fn apz_deregister_updater(window_id: WrWindowId);
920
921
// These callbacks are invoked from the render backend thread (aka the APZ
922
// sampler thread)
923
fn apz_register_sampler(window_id: WrWindowId);
924
fn apz_sample_transforms(window_id: WrWindowId, transaction: &mut Transaction,
925
document_id: WrDocumentId);
926
fn apz_deregister_sampler(window_id: WrWindowId);
927
}
928
929
struct APZCallbacks {
930
window_id: WrWindowId,
931
}
932
933
impl APZCallbacks {
934
pub fn new(window_id: WrWindowId) -> Self {
935
APZCallbacks {
936
window_id,
937
}
938
}
939
}
940
941
impl SceneBuilderHooks for APZCallbacks {
942
fn register(&self) {
943
unsafe { apz_register_updater(self.window_id) }
944
}
945
946
fn pre_scene_build(&self) {
947
unsafe { gecko_profiler_start_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
948
}
949
950
fn pre_scene_swap(&self, scenebuild_time: u64) {
951
unsafe {
952
record_telemetry_time(TelemetryProbe::SceneBuildTime, scenebuild_time);
953
apz_pre_scene_swap(self.window_id);
954
}
955
}
956
957
fn post_scene_swap(&self, document_ids: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64) {
958
unsafe {
959
let info = WrPipelineInfo::new(&info);
960
record_telemetry_time(TelemetryProbe::SceneSwapTime, sceneswap_time);
961
apz_post_scene_swap(self.window_id, info);
962
}
963
let info = WrPipelineInfo::new(&info);
964
965
// After a scene swap we should schedule a render for the next vsync,
966
// otherwise there's no guarantee that the new scene will get rendered
967
// anytime soon
968
unsafe { wr_finished_scene_build(self.window_id, document_ids.as_ptr(), document_ids.len(), info) }
969
unsafe { gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
970
}
971
972
fn post_resource_update(&self, document_ids: &Vec<DocumentId>) {
973
unsafe { wr_schedule_render(self.window_id, document_ids.as_ptr(), document_ids.len()) }
974
unsafe { gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
975
}
976
977
fn post_empty_scene_build(&self) {
978
unsafe { gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
979
}
980
981
fn poke(&self) {
982
unsafe { apz_run_updater(self.window_id) }
983
}
984
985
fn deregister(&self) {
986
unsafe { apz_deregister_updater(self.window_id) }
987
}
988
}
989
990
struct SamplerCallback {
991
window_id: WrWindowId,
992
}
993
994
impl SamplerCallback {
995
pub fn new(window_id: WrWindowId) -> Self {
996
SamplerCallback {
997
window_id,
998
}
999
}
1000
}
1001
1002
impl AsyncPropertySampler for SamplerCallback {
1003
fn register(&self) {
1004
unsafe { apz_register_sampler(self.window_id) }
1005
}
1006
1007
fn sample(&self, document_id: DocumentId) -> Vec<FrameMsg> {
1008
let mut transaction = Transaction::new();
1009
unsafe { apz_sample_transforms(self.window_id, &mut transaction, document_id) };
1010
// TODO: also omta_sample_transforms(...)
1011
transaction.get_frame_ops()
1012
}
1013
1014
fn deregister(&self) {
1015
unsafe { apz_deregister_sampler(self.window_id) }
1016
}
1017
}
1018
1019
extern "C" {
1020
fn gecko_profiler_register_thread(name: *const ::std::os::raw::c_char);
1021
fn gecko_profiler_unregister_thread();
1022
fn wr_register_thread_local_arena();
1023
}
1024
1025
struct GeckoProfilerThreadListener {}
1026
1027
impl GeckoProfilerThreadListener {
1028
pub fn new() -> GeckoProfilerThreadListener {
1029
GeckoProfilerThreadListener{}
1030
}
1031
}
1032
1033
impl ThreadListener for GeckoProfilerThreadListener {
1034
fn thread_started(&self, thread_name: &str) {
1035
let name = CString::new(thread_name).unwrap();
1036
unsafe {
1037
// gecko_profiler_register_thread copies the passed name here.
1038
gecko_profiler_register_thread(name.as_ptr());
1039
}
1040
}
1041
1042
fn thread_stopped(&self, _: &str) {
1043
unsafe {
1044
gecko_profiler_unregister_thread();
1045
}
1046
}
1047
}
1048
1049
pub struct WrThreadPool(Arc<rayon::ThreadPool>);
1050
1051
#[no_mangle]
1052
pub unsafe extern "C" fn wr_thread_pool_new(low_priority: bool) -> *mut WrThreadPool {
1053
// Clamp the number of workers between 1 and 8. We get diminishing returns
1054
// with high worker counts and extra overhead because of rayon and font
1055
// management.
1056
let num_threads = num_cpus::get().max(2).min(8);
1057
1058
let priority_tag = if low_priority { "LP" } else { "" };
1059
1060
let worker = rayon::ThreadPoolBuilder::new()
1061
.thread_name(move |idx|{ format!("WRWorker{}#{}", priority_tag, idx) })
1062
.num_threads(num_threads)
1063
.start_handler(move |idx| {
1064
wr_register_thread_local_arena();
1065
let name = format!("WRWorker{}#{}",priority_tag, idx);
1066
register_thread_with_profiler(name.clone());
1067
gecko_profiler_register_thread(CString::new(name).unwrap().as_ptr());
1068
})
1069
.exit_handler(|_idx| {
1070
gecko_profiler_unregister_thread();
1071
})
1072
.build();
1073
1074
let workers = Arc::new(worker.unwrap());
1075
1076
// This effectively leaks the thread pool. Not great but we only create one and it lives
1077
// for as long as the browser.
1078
// Do this to avoid intermittent race conditions with nsThreadManager shutdown.
1079
// A better fix would involve removing the dependency between implicit nsThreadManager
1080
// and webrender's threads, or be able to synchronously terminate rayon's thread pool.
1081
mem::forget(Arc::clone(&workers));
1082
1083
Box::into_raw(Box::new(WrThreadPool(workers)))
1084
}
1085
1086
#[no_mangle]
1087
pub unsafe extern "C" fn wr_thread_pool_delete(thread_pool: *mut WrThreadPool) {
1088
Box::from_raw(thread_pool);
1089
}
1090
1091
#[no_mangle]
1092
pub unsafe extern "C" fn wr_program_cache_new(prof_path: &nsAString, thread_pool: *mut WrThreadPool) -> *mut WrProgramCache {
1093
let workers = &(*thread_pool).0;
1094
let program_cache = WrProgramCache::new(prof_path, workers);
1095
Box::into_raw(Box::new(program_cache))
1096
}
1097
1098
#[no_mangle]
1099
pub unsafe extern "C" fn wr_program_cache_delete(program_cache: *mut WrProgramCache) {
1100
Box::from_raw(program_cache);
1101
}
1102
1103
#[no_mangle]
1104
pub unsafe extern "C" fn wr_try_load_startup_shaders_from_disk(program_cache: *mut WrProgramCache) {
1105
(*program_cache).try_load_startup_shaders_from_disk();
1106
}
1107
1108
#[no_mangle]
1109
pub unsafe extern "C" fn remove_program_binary_disk_cache(prof_path: &nsAString) -> bool {
1110
match remove_disk_cache(prof_path) {
1111
Ok(_) => true,
1112
Err(_) => {
1113
error!("Failed to remove program binary disk cache");
1114
false
1115
}
1116
}
1117
}
1118
1119
#[no_mangle]
1120
pub extern "C" fn wr_renderer_update_program_cache(renderer: &mut Renderer, program_cache: &mut WrProgramCache) {
1121
let program_cache = Rc::clone(&program_cache.rc_get());
1122
renderer.update_program_cache(program_cache);
1123
}
1124
1125
// This matches IsEnvSet in gfxEnv.h
1126
fn env_var_to_bool(key: &'static str) -> bool {
1127
env::var(key).ok().map_or(false, |v| !v.is_empty())
1128
}
1129
1130
// Call MakeCurrent before this.
1131
fn wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>)
1132
-> Device
1133
{
1134
assert!(unsafe { is_in_render_thread() });
1135
1136
let gl;
1137
if unsafe { is_glcontext_gles(gl_context) } {
1138
gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1139
} else {
1140
gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1141
}
1142
1143
let version = gl.get_string(gl::VERSION);
1144
1145
info!("WebRender - OpenGL version new {}", version);
1146
1147
let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
1148
UploadMethod::Immediate
1149
} else {
1150
UploadMethod::PixelBuffer(VertexUsageHint::Dynamic)
1151
};
1152
1153
let resource_override_path = unsafe {
1154
let override_charptr = gfx_wr_resource_path_override();
1155
if override_charptr.is_null() {
1156
None
1157
} else {
1158
match CStr::from_ptr(override_charptr).to_str() {
1159
Ok(override_str) => Some(PathBuf::from(override_str)),
1160
_ => None
1161
}
1162
}
1163
};
1164
1165
let cached_programs = match pc {
1166
Some(cached_programs) => Some(Rc::clone(cached_programs.rc_get())),
1167
None => None,
1168
};
1169
1170
Device::new(
1171
gl,
1172
resource_override_path,
1173
upload_method,
1174
cached_programs,
1175
false,
1176
true,
1177
true,
1178
None,
1179
false,
1180
false,
1181
)
1182
}
1183
1184
extern "C" {
1185
fn wr_compositor_create_surface(
1186
compositor: *mut c_void,
1187
id: NativeSurfaceId,
1188
tile_size: DeviceIntSize,
1189
is_opaque: bool,
1190
);
1191
fn wr_compositor_destroy_surface(
1192
compositor: *mut c_void,
1193
id: NativeSurfaceId,
1194
);
1195
fn wr_compositor_create_tile(
1196
compositor: *mut c_void,
1197
id: NativeSurfaceId,
1198
x: i32,
1199
y: i32,
1200
);
1201
fn wr_compositor_destroy_tile(
1202
compositor: *mut c_void,
1203
id: NativeSurfaceId,
1204
x: i32,
1205
y: i32,
1206
);
1207
fn wr_compositor_bind(
1208
compositor: *mut c_void,
1209
id: NativeTileId,
1210
offset: &mut DeviceIntPoint,
1211
fbo_id: &mut u32,
1212
dirty_rect: DeviceIntRect,
1213
);
1214
fn wr_compositor_unbind(compositor: *mut c_void);
1215
fn wr_compositor_begin_frame(compositor: *mut c_void);
1216
fn wr_compositor_add_surface(
1217
compositor: *mut c_void,
1218
id: NativeSurfaceId,
1219
position: DeviceIntPoint,
1220
clip_rect: DeviceIntRect,
1221
);
1222
fn wr_compositor_end_frame(compositor: *mut c_void);
1223
fn wr_compositor_enable_native_compositor(
1224
compositor: *mut c_void,
1225
enable: bool,
1226
);
1227
}
1228
1229
pub struct WrCompositor(*mut c_void);
1230
1231
impl Compositor for WrCompositor {
1232
fn create_surface(
1233
&mut self,
1234
id: NativeSurfaceId,
1235
tile_size: DeviceIntSize,
1236
is_opaque: bool,
1237
) {
1238
unsafe {
1239
wr_compositor_create_surface(
1240
self.0,
1241
id,
1242
tile_size,
1243
is_opaque,
1244
);
1245
}
1246
}
1247
1248
fn destroy_surface(
1249
&mut self,
1250
id: NativeSurfaceId,
1251
) {
1252
unsafe {
1253
wr_compositor_destroy_surface(
1254
self.0,
1255
id,
1256
);
1257
}
1258
}
1259
1260
fn create_tile(
1261
&mut self,
1262
id: NativeTileId,
1263
) {
1264
unsafe {
1265
wr_compositor_create_tile(
1266
self.0,
1267
id.surface_id,
1268
id.x,
1269
id.y,
1270
);
1271
}
1272
}
1273
1274
fn destroy_tile(
1275
&mut self,
1276
id: NativeTileId,
1277
) {
1278
unsafe {
1279
wr_compositor_destroy_tile(
1280
self.0,
1281
id.surface_id,
1282
id.x,
1283
id.y,
1284
);
1285
}
1286
}
1287
1288
fn bind(
1289
&mut self,
1290
id: NativeTileId,
1291
dirty_rect: DeviceIntRect,
1292
) -> NativeSurfaceInfo {
1293
let mut surface_info = NativeSurfaceInfo {
1294
origin: DeviceIntPoint::zero(),
1295
fbo_id: 0,
1296
};
1297
1298
unsafe {
1299
wr_compositor_bind(
1300
self.0,
1301
id,
1302
&mut surface_info.origin,
1303
&mut surface_info.fbo_id,
1304
dirty_rect,
1305
);
1306
}
1307
1308
surface_info
1309
}
1310
1311
fn unbind(
1312
&mut self,
1313
) {
1314
unsafe {
1315
wr_compositor_unbind(
1316
self.0,
1317
);
1318
}
1319
}
1320
1321
fn begin_frame(&mut self) {
1322
unsafe {
1323
wr_compositor_begin_frame(
1324
self.0,
1325
);
1326
}
1327
}
1328
1329
fn add_surface(
1330
&mut self,
1331
id: NativeSurfaceId,
1332
position: DeviceIntPoint,
1333
clip_rect: DeviceIntRect,
1334
) {
1335
unsafe {
1336
wr_compositor_add_surface(
1337
self.0,
1338
id,
1339
position,
1340
clip_rect,
1341
);
1342
}
1343
}
1344
1345
fn end_frame(&mut self) {
1346
unsafe {
1347
wr_compositor_end_frame(
1348
self.0,
1349
);
1350
}
1351
}
1352
1353
fn enable_native_compositor(&mut self, enable: bool) {
1354
unsafe {
1355
wr_compositor_enable_native_compositor(
1356
self.0,
1357
enable,
1358
);
1359
}
1360
}
1361
}
1362
1363
1364
// Call MakeCurrent before this.
1365
#[no_mangle]
1366
pub extern "C" fn wr_window_new(window_id: WrWindowId,
1367
window_width: i32,
1368
window_height: i32,
1369
support_low_priority_transactions: bool,
1370
support_low_priority_threadpool: bool,
1371
allow_texture_swizzling: bool,
1372
enable_picture_caching: bool,
1373
start_debug_server: bool,
1374
gl_context: *mut c_void,
1375
surface_origin_is_top_left: bool,
1376
program_cache: Option<&mut WrProgramCache>,
1377
shaders: Option<&mut WrShaders>,
1378
thread_pool: *mut WrThreadPool,
1379
thread_pool_low_priority: *mut WrThreadPool,
1380
size_of_op: VoidPtrToSizeFn,
1381
enclosing_size_of_op: VoidPtrToSizeFn,
1382
document_id: u32,
1383
compositor: *mut c_void,
1384
max_update_rects: usize,
1385
max_partial_present_rects: usize,
1386
out_handle: &mut *mut DocumentHandle,
1387
out_renderer: &mut *mut Renderer,
1388
out_max_texture_size: *mut i32,
1389
enable_gpu_markers: bool,
1390
panic_on_gl_error: bool)
1391
-> bool {
1392
assert!(unsafe { is_in_render_thread() });
1393
1394
let recorder: Option<Box<dyn ApiRecordingReceiver>> = if unsafe { gfx_use_wrench() } {
1395
let name = format!("wr-record-{}.bin", window_id.0);
1396
Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
1397
} else {
1398
None
1399
};
1400
1401
let gl;
1402
if unsafe { is_glcontext_gles(gl_context) } {
1403
gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1404
} else {
1405
gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1406
}
1407
1408
let version = gl.get_string(gl::VERSION);
1409
1410
info!("WebRender - OpenGL version new {}", version);
1411
1412
let workers = unsafe {
1413
Arc::clone(&(*thread_pool).0)
1414
};
1415
let workers_low_priority = unsafe {
1416
if support_low_priority_threadpool {
1417
Arc::clone(&(*thread_pool_low_priority).0)
1418
} else {
1419
Arc::clone(&(*thread_pool).0)
1420
}
1421
};
1422
1423
let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
1424
UploadMethod::Immediate
1425
} else {
1426
UploadMethod::PixelBuffer(VertexUsageHint::Dynamic)
1427
};
1428
1429
let precache_flags = if env_var_to_bool("MOZ_WR_PRECACHE_SHADERS") {
1430
ShaderPrecacheFlags::FULL_COMPILE
1431
} else {
1432
ShaderPrecacheFlags::empty()
1433
};
1434
1435
let cached_programs = match program_cache {
1436
Some(program_cache) => Some(Rc::clone(&program_cache.rc_get())),
1437
None => None,
1438
};
1439
1440
let color = if cfg!(target_os = "android") {
1441
// The color is for avoiding black flash before receiving display list.
1442
ColorF::new(1.0, 1.0, 1.0, 1.0)
1443
} else {
1444
ColorF::new(0.0, 0.0, 0.0, 0.0)
1445
};
1446
1447
let compositor_config = if compositor != ptr::null_mut() {
1448
CompositorConfig::Native {
1449
max_update_rects,
1450
compositor: Box::new(WrCompositor(compositor)),
1451
}
1452
} else {
1453
CompositorConfig::Draw {
1454
max_partial_present_rects,
1455
}
1456
};
1457
1458
let opts = RendererOptions {
1459
enable_aa: true,
1460
force_subpixel_aa: false,
1461
enable_subpixel_aa: cfg!(not(target_os = "android")),
1462
support_low_priority_transactions,
1463
allow_texture_swizzling,
1464
recorder: recorder,
1465
blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(workers.clone(), workers_low_priority.clone()))),
1466
workers: Some(workers.clone()),
1467
thread_listener: Some(Box::new(GeckoProfilerThreadListener::new())),
1468
size_of_op: Some(size_of_op),
1469
enclosing_size_of_op: Some(enclosing_size_of_op),
1470
cached_programs,
1471
resource_override_path: unsafe {
1472
let override_charptr = gfx_wr_resource_path_override();
1473
if override_charptr.is_null() {
1474
None
1475
} else {
1476
match CStr::from_ptr(override_charptr).to_str() {
1477
Ok(override_str) => Some(PathBuf::from(override_str)),
1478
_ => None
1479
}
1480
}
1481
},
1482
renderer_id: Some(window_id.0),
1483
upload_method,
1484
scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
1485
sampler: Some(Box::new(SamplerCallback::new(window_id))),
1486
max_texture_size: Some(8192), // Moz2D doesn't like textures bigger than this
1487
clear_color: Some(color),
1488
precache_flags,
1489
namespace_alloc_by_client: true,
1490
enable_picture_caching,
1491
allow_pixel_local_storage_support: false,
1492
start_debug_server,
1493
surface_origin_is_top_left,
1494
compositor_config,
1495
enable_gpu_markers,
1496
panic_on_gl_error,
1497
..Default::default()
1498
};
1499
1500
// Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
1501
set_profiler_hooks(Some(&PROFILER_HOOKS));
1502
1503
let window_size = DeviceIntSize::new(window_width, window_height);
1504
let notifier = Box::new(CppNotifier {
1505
window_id: window_id,
1506
});
1507
let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders, window_size) {
1508
Ok((renderer, sender)) => (renderer, sender),
1509
Err(e) => {
1510
warn!(" Failed to create a Renderer: {:?}", e);
1511
let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
1512
unsafe {
1513
gfx_critical_note(msg.as_ptr());
1514
}
1515
return false;
1516
},
1517
};
1518
1519
unsafe {
1520
*out_max_texture_size = renderer.get_max_texture_size();
1521
}
1522
let layer = 0;
1523
*out_handle = Box::into_raw(Box::new(
1524
DocumentHandle::new_with_id(sender.create_api_by_client(next_namespace_id()),
1525
window_size, layer, document_id)));
1526
*out_renderer = Box::into_raw(Box::new(renderer));
1527
1528
return true;
1529
}
1530
1531
#[no_mangle]
1532
pub extern "C" fn wr_api_create_document(
1533
root_dh: &mut DocumentHandle,
1534
out_handle: &mut *mut DocumentHandle,
1535
doc_size: DeviceIntSize,
1536
layer: i8,
1537
document_id: u32
1538
) {
1539
assert!(unsafe { is_in_compositor_thread() });
1540
1541
*out_handle = Box::into_raw(Box::new(DocumentHandle::new_with_id(
1542
root_dh.api.clone_sender().create_api_by_client(next_namespace_id()),
1543
doc_size,
1544
layer,
1545
document_id
1546
)));
1547
}
1548
1549
#[no_mangle]
1550
pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
1551
dh.api.delete_document(dh.document_id);
1552
}
1553
1554
#[no_mangle]
1555
pub extern "C" fn wr_api_clone(
1556
dh: &mut DocumentHandle,
1557
out_handle: &mut *mut DocumentHandle
1558
) {
1559
assert!(unsafe { is_in_compositor_thread() });
1560
1561
let handle = DocumentHandle {
1562
api: dh.api.clone_sender().create_api_by_client(next_namespace_id()),
1563
document_id: dh.document_id,
1564
};
1565
*out_handle = Box::into_raw(Box::new(handle));
1566
}
1567
1568
#[no_mangle]
1569
pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
1570
let _ = Box::from_raw(dh);
1571
}
1572
1573
#[no_mangle]
1574
pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
1575
dh.api.shut_down(true);
1576
}
1577
1578
#[no_mangle]
1579
pub unsafe extern "C" fn wr_api_notify_memory_pressure(dh: &mut DocumentHandle) {
1580
dh.api.notify_memory_pressure();
1581
}
1582
1583
#[no_mangle]
1584
pub extern "C" fn wr_api_set_debug_flags(dh: &mut DocumentHandle, flags: DebugFlags) {
1585
dh.api.set_debug_flags(flags);
1586
}
1587
1588
#[no_mangle]
1589
pub unsafe extern "C" fn wr_api_accumulate_memory_report(
1590
dh: &mut DocumentHandle,
1591
report: &mut MemoryReport
1592
) {
1593
*report += dh.api.report_memory();
1594
}
1595
1596
#[no_mangle]
1597
pub unsafe extern "C" fn wr_api_clear_all_caches(dh: &mut DocumentHandle) {
1598
dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
1599
}
1600
1601
#[no_mangle]
1602
pub unsafe extern "C" fn wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool) {
1603
dh.api.send_debug_cmd(DebugCommand::EnableNativeCompositor(enable));
1604
}
1605
1606
fn make_transaction(do_async: bool) -> Transaction {
1607
let mut transaction = Transaction::new();
1608
// Ensure that we either use async scene building or not based on the
1609
// gecko pref, regardless of what the default is. We can remove this once
1610
// the scene builder thread is enabled everywhere and working well.
1611
if do_async {
1612
transaction.use_scene_builder_thread();
1613
} else {
1614
transaction.skip_scene_builder();
1615
}
1616
transaction
1617
}
1618
1619
#[no_mangle]
1620
pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
1621
Box::into_raw(Box::new(make_transaction(do_async)))
1622
}
1623
1624
#[no_mangle]
1625
pub extern "C" fn wr_transaction_delete(txn: *mut Transaction) {
1626
unsafe { let _ = Box::from_raw(txn); }
1627
}
1628
1629
#[no_mangle]
1630
pub extern "C" fn wr_transaction_set_low_priority(txn: &mut Transaction, low_priority: bool) {
1631
txn.set_low_priority(low_priority);
1632
}
1633
1634
#[no_mangle]
1635
pub extern "C" fn wr_transaction_is_empty(txn: &Transaction) -> bool {
1636
txn.is_empty()
1637
}
1638
1639
#[no_mangle]
1640
pub extern "C" fn wr_transaction_resource_updates_is_empty(txn: &Transaction) -> bool {
1641
txn.resource_updates.is_empty()
1642
}
1643
1644
#[no_mangle]
1645
pub extern "C" fn wr_transaction_is_rendered_frame_invalidated(txn: &Transaction) -> bool {
1646
txn.invalidate_rendered_frame
1647
}
1648
1649
#[no_mangle]
1650
pub extern "C" fn wr_transaction_notify(txn: &mut Transaction, when: Checkpoint, event: usize) {
1651
struct GeckoNotification(usize);
1652
impl NotificationHandler for GeckoNotification {
1653
fn notify(&self, when: Checkpoint) {
1654
unsafe {
1655
wr_transaction_notification_notified(self.0, when);
1656
}
1657
}
1658
}
1659
1660
let handler = Box::new(GeckoNotification(event));
1661
txn.notify(NotificationRequest::new(when, handler));
1662
}
1663
1664
#[no_mangle]
1665
pub extern "C" fn wr_transaction_update_epoch(
1666
txn: &mut Transaction,
1667
pipeline_id: WrPipelineId,
1668
epoch: WrEpoch,
1669
) {
1670
txn.update_epoch(pipeline_id, epoch);
1671
}
1672
1673
#[no_mangle]
1674
pub extern "C" fn wr_transaction_set_root_pipeline(
1675
txn: &mut Transaction,
1676
pipeline_id: WrPipelineId,
1677
) {
1678
txn.set_root_pipeline(pipeline_id);
1679
}
1680
1681
#[no_mangle]
1682
pub extern "C" fn wr_transaction_remove_pipeline(
1683
txn: &mut Transaction,
1684
pipeline_id: WrPipelineId,
1685
) {
1686
txn.remove_pipeline(pipeline_id);
1687
}
1688
1689
#[no_mangle]
1690
pub extern "C" fn wr_transaction_set_display_list(
1691
txn: &mut Transaction,
1692
epoch: WrEpoch,
1693
background: ColorF,
1694
viewport_size: LayoutSize,
1695
pipeline_id: WrPipelineId,
1696
content_size: LayoutSize,
1697
dl_descriptor: BuiltDisplayListDescriptor,
1698
dl_data: &mut WrVecU8,
1699
) {
1700
let color = if background.a == 0.0 { None } else { Some(background) };
1701
1702
// See the documentation of set_display_list in api.rs. I don't think
1703
// it makes a difference in gecko at the moment(until APZ is figured out)
1704
// but I suppose it is a good default.
1705
let preserve_frame_state = true;
1706
1707
let dl_vec = dl_data.flush_into_vec();
1708
let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
1709
1710
txn.set_display_list(
1711
epoch,
1712
color,
1713
viewport_size,
1714
(pipeline_id, content_size, dl),
1715
preserve_frame_state,
1716
);
1717
}
1718
1719
#[no_mangle]
1720
pub extern "C" fn wr_transaction_set_document_view(
1721
txn: &mut Transaction,
1722
doc_rect: &DeviceIntRect,
1723
) {
1724
txn.set_document_view(
1725
*doc_rect,
1726
1.0,
1727
);
1728
}
1729
1730
#[no_mangle]
1731
pub extern "C" fn wr_transaction_generate_frame(
1732
txn: &mut Transaction) {
1733
txn.generate_frame();
1734
}
1735
1736
#[no_mangle]
1737
pub extern "C" fn wr_transaction_invalidate_rendered_frame(txn: &mut Transaction) {
1738
txn.invalidate_rendered_frame();
1739
}
1740
1741
#[no_mangle]
1742
pub extern "C" fn wr_transaction_update_dynamic_properties(
1743
txn: &mut Transaction,
1744
opacity_array: *const WrOpacityProperty,
1745
opacity_count: usize,
1746
transform_array: *const WrTransformProperty,
1747
transform_count: usize,
1748
) {
1749
let mut properties = DynamicProperties {
1750
transforms: Vec::new(),
1751
floats: Vec::new(),
1752
};
1753
1754
if transform_count > 0 {
1755
let transform_slice = unsafe { make_slice(transform_array, transform_count) };
1756
1757
properties.transforms.reserve(transform_slice.len());
1758
for element in transform_slice.iter() {
1759
let prop = PropertyValue {
1760
key: PropertyBindingKey::new(element.id),
1761
value: element.transform.into(),
1762
};
1763
1764
properties.transforms.push(prop);
1765
}
1766
}
1767
1768
if opacity_count > 0 {
1769
let opacity_slice = unsafe { make_slice(opacity_array, opacity_count) };
1770
1771
properties.floats.reserve(opacity_slice.len());
1772
for element in opacity_slice.iter() {
1773
let prop = PropertyValue {
1774
key: PropertyBindingKey::new(element.id),
1775
value: element.opacity,
1776
};
1777
properties.floats.push(prop);
1778
}
1779
}
1780
1781
txn.update_dynamic_properties(properties);
1782
}
1783
1784
#[no_mangle]
1785
pub extern "C" fn wr_transaction_append_transform_properties(
1786
txn: &mut Transaction,
1787
transform_array: *const WrTransformProperty,
1788
transform_count: usize,
1789
) {
1790
if transform_count == 0 {
1791
return;
1792
}
1793
1794
let mut properties = DynamicProperties {
1795
transforms: Vec::new(),
1796
floats: Vec::new(),
1797
};
1798
1799
let transform_slice = unsafe { make_slice(transform_array, transform_count) };
1800
properties.transforms.reserve(transform_slice.len());
1801
for element in transform_slice.iter() {
1802
let prop = PropertyValue {
1803
key: PropertyBindingKey::new(element.id),
1804
value: element.transform.into(),
1805
};
1806
1807
properties.transforms.push(prop);
1808
}
1809
1810
txn.append_dynamic_properties(properties);
1811
}
1812
1813
#[no_mangle]
1814
pub extern "C" fn wr_transaction_scroll_layer(
1815
txn: &mut Transaction,
1816
pipeline_id: WrPipelineId,
1817
scroll_id: u64,
1818
new_scroll_origin: LayoutPoint
1819
) {
1820
let scroll_id = ExternalScrollId(scroll_id, pipeline_id);
1821
txn.scroll_node_with_id(new_scroll_origin, scroll_id, ScrollClamping::NoClamping);
1822
}
1823
1824
#[no_mangle]
1825
pub extern "C" fn wr_transaction_pinch_zoom(
1826
txn: &mut Transaction,
1827
pinch_zoom: f32
1828
) {
1829
txn.set_pinch_zoom(ZoomFactor::new(pinch_zoom));
1830
}
1831
1832
#[no_mangle]
1833
pub extern "C" fn wr_transaction_set_is_transform_async_zooming(
1834
txn: &mut Transaction,
1835
animation_id: u64,
1836
is_zooming: bool
1837
) {
1838
txn.set_is_transform_async_zooming(is_zooming, PropertyBindingId::new(animation_id));
1839
}
1840
1841
#[no_mangle]
1842
pub extern "C" fn wr_transaction_set_quality_settings(
1843
txn: &mut Transaction,
1844
allow_sacrificing_subpixel_aa: bool
1845
) {
1846
txn.set_quality_settings(QualitySettings {
1847
allow_sacrificing_subpixel_aa
1848
});
1849
}
1850
1851
#[no_mangle]
1852
pub extern "C" fn wr_resource_updates_add_image(
1853
txn: &mut Transaction,
1854
image_key: WrImageKey,
1855
descriptor: &WrImageDescriptor,
1856
bytes: &mut WrVecU8,
1857
) {
1858
txn.add_image(
1859
image_key,
1860
descriptor.into(),
1861
ImageData::new(bytes.flush_into_vec()),
1862
None
1863
);
1864
}
1865
1866
#[no_mangle]
1867
pub extern "C" fn wr_resource_updates_add_blob_image(
1868
txn: &mut Transaction,
1869
image_key: BlobImageKey,
1870
descriptor: &WrImageDescriptor,
1871
bytes: &mut WrVecU8,
1872
visible_rect: DeviceIntRect,
1873
) {
1874
txn.add_blob_image(
1875
image_key,
1876
descriptor.into(),
1877
Arc::new(bytes.flush_into_vec()),
1878
visible_rect,
1879
if descriptor.format == ImageFormat::BGRA8 { Some(256) } else { None }
1880
);
1881
}
1882
1883
#[no_mangle]
1884
pub extern "C" fn wr_resource_updates_add_external_image(
1885
txn: &mut Transaction,
1886
image_key: WrImageKey,
1887
descriptor: &WrImageDescriptor,
1888
external_image_id: ExternalImageId,
1889