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