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