Skip to content

Commit 3108fd7

Browse files
committed
Add VRCompositor commands for WebVR
1 parent c4a0c01 commit 3108fd7

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

webrender/src/render_backend.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace, Im
1919
use webrender_traits::{FlushNotifier, RenderNotifier, RenderDispatcher, WebGLCommand, WebGLContextId};
2020
use webrender_traits::{DeviceIntSize};
2121
use webrender_traits::channel::{PayloadHelperMethods, PayloadReceiver, PayloadSender, MsgReceiver};
22+
use webrender_traits::{VRCompositorCommand, VRCompositor, VRCompositorCreator, VRCompositorId};
2223
use record;
2324
use tiling::FrameBuilderConfig;
2425
use offscreen_gl_context::GLContextDispatcher;
@@ -50,6 +51,9 @@ pub struct RenderBackend {
5051
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
5152

5253
next_webgl_id: usize,
54+
55+
vr_compositor_creator: Arc<Mutex<Option<Box<VRCompositorCreator>>>>,
56+
vr_compositors: HashMap<VRCompositorId, Box<VRCompositor>>
5357
}
5458

5559
impl RenderBackend {
@@ -66,7 +70,8 @@ impl RenderBackend {
6670
config: FrameBuilderConfig,
6771
debug: bool,
6872
enable_recording:bool,
69-
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>) -> RenderBackend {
73+
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
74+
vr_compositor_creator: Arc<Mutex<Option<Box<VRCompositorCreator>>>>) -> RenderBackend {
7075

7176
let resource_cache = ResourceCache::new(texture_cache,
7277
device_pixel_ratio,
@@ -90,6 +95,8 @@ impl RenderBackend {
9095
enable_recording:enable_recording,
9196
main_thread_dispatcher: main_thread_dispatcher,
9297
next_webgl_id: 0,
98+
vr_compositor_creator: vr_compositor_creator,
99+
vr_compositors: HashMap::new(),
93100
}
94101
}
95102

@@ -337,6 +344,10 @@ impl RenderBackend {
337344
ctx.make_current();
338345
ctx.apply_command(command);
339346
self.current_bound_webgl_context_id = Some(context_id);
347+
},
348+
349+
ApiMsg::VRCompositorCommand(context_id, command) => {
350+
self.handle_vr_compositor_command(context_id, command);
340351
}
341352
ApiMsg::GenerateFrame => {
342353
let frame = profile_counters.total_time.profile(|| {
@@ -470,6 +481,38 @@ impl RenderBackend {
470481
let mut notifier = self.notifier.lock();
471482
notifier.as_mut().unwrap().as_mut().unwrap().new_scroll_frame_ready(composite_needed);
472483
}
484+
485+
fn handle_vr_compositor_command(&mut self, ctx_id: WebGLContextId, cmd: VRCompositorCommand) {
486+
match cmd {
487+
VRCompositorCommand::Create(compositor_id) => {
488+
let mut creator = self.vr_compositor_creator.lock();
489+
let compositor = creator.as_mut().unwrap().as_mut().unwrap().create_compositor(compositor_id);
490+
if let Some(compositor) = compositor {
491+
self.vr_compositors.insert(compositor_id, compositor);
492+
}
493+
}
494+
VRCompositorCommand::SyncPoses(compositor_id, near, far, sender) => {
495+
if let Some(ref compositor) = self.vr_compositors.get(&compositor_id) {
496+
let pose = compositor.sync_poses(near, far);
497+
let _result = sender.send(Ok(pose));
498+
} else {
499+
let _result = sender.send(Err(()));
500+
}
501+
}
502+
VRCompositorCommand::SubmitFrame(compositor_id, left_bounds, right_bounds) => {
503+
if let Some(ref compositor) = self.vr_compositors.get(&compositor_id) {
504+
let texture = self.resource_cache.get_webgl_texture(&ctx_id);
505+
if let SourceTexture::WebGL(texture_id) = texture.texture_id {
506+
compositor.submit_frame(texture_id, left_bounds, right_bounds);
507+
}
508+
}
509+
}
510+
VRCompositorCommand::Release(compositor_id) => {
511+
self.vr_compositors.remove(&compositor_id);
512+
}
513+
}
514+
515+
}
473516
}
474517

475518
struct WebRenderGLDispatcher {

webrender/src/renderer.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use webrender_traits::{ColorF, Epoch, FlushNotifier, PipelineId, RenderNotifier,
4040
use webrender_traits::{ExternalImageId, ImageFormat, RenderApiSender, RendererKind};
4141
use webrender_traits::{DeviceSize, DevicePoint, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
4242
use webrender_traits::channel;
43+
use webrender_traits::VRCompositorCreator;
4344

4445
pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
4546

@@ -414,6 +415,10 @@ pub struct Renderer {
414415

415416
/// Map of external image IDs to native textures.
416417
external_images: HashMap<ExternalImageId, TextureId, BuildHasherDefault<FnvHasher>>,
418+
419+
// Optional trait object that allows to create a VRCompositor instance to handle WebVR commands.
420+
// Some WebVR commands such as Vsync and SubmitFrame must be called in the WebGL render thread.
421+
vr_compositor_creator: Arc<Mutex<Option<Box<VRCompositorCreator>>>>
417422
}
418423

419424
impl Renderer {
@@ -668,6 +673,9 @@ impl Renderer {
668673
let backend_main_thread_dispatcher = main_thread_dispatcher.clone();
669674
let backend_flush_notifier = flush_notifier.clone();
670675

676+
let vr_compositor = Arc::new(Mutex::new(None));
677+
let backend_vr_compositor = vr_compositor.clone();
678+
671679
// We need a reference to the webrender context from the render backend in order to share
672680
// texture ids
673681
let context_handle = match options.renderer_kind {
@@ -696,7 +704,8 @@ impl Renderer {
696704
config,
697705
debug,
698706
enable_recording,
699-
backend_main_thread_dispatcher);
707+
backend_main_thread_dispatcher,
708+
backend_vr_compositor);
700709
backend.run();
701710
});
702711

@@ -756,6 +765,7 @@ impl Renderer {
756765
cache_texture_id_map: Vec::new(),
757766
external_image_handler: None,
758767
external_images: HashMap::with_hasher(Default::default()),
768+
vr_compositor_creator: vr_compositor
759769
};
760770

761771
let sender = RenderApiSender::new(api_tx, payload_tx);
@@ -789,6 +799,16 @@ impl Renderer {
789799
*dispatcher_arc = Some(dispatcher);
790800
}
791801

802+
/// Sets the VRCompositorCreator.
803+
///
804+
/// Some WebVR commands such as Vsync and SubmitFrame must be called in the WebGL render thread.
805+
/// VRCompositorCreator is used to create VRCompositor objects that are able to handle WebVR
806+
/// commands that must be called in the render thread.
807+
pub fn set_vr_compositor_creator(&self, creator: Box<VRCompositorCreator>) {
808+
let mut creator_arc = self.vr_compositor_creator.lock().unwrap();
809+
*creator_arc = Some(creator);
810+
}
811+
792812
/// Returns the Epoch of the current frame in a pipeline.
793813
pub fn current_epoch(&self, pipeline_id: PipelineId) -> Option<Epoch> {
794814
self.pipeline_epoch_map.get(&pipeline_id).map(|epoch| *epoch)

webrender_traits/src/api.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use {ApiMsg, ColorF, DisplayListBuilder, Epoch};
1111
use {FontKey, IdNamespace, ImageFormat, ImageKey, NativeFontHandle, PipelineId};
1212
use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState, ServoScrollRootId};
1313
use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand};
14+
use VRCompositorCommand;
1415

1516
impl RenderApiSender {
1617
pub fn new(api_sender: MsgSender<ApiMsg>,
@@ -245,6 +246,11 @@ impl RenderApi {
245246
self.api_sender.send(msg).unwrap();
246247
}
247248

249+
pub fn send_vr_compositor_command(&self, context_id: WebGLContextId, command: VRCompositorCommand) {
250+
let msg = ApiMsg::VRCompositorCommand(context_id, command);
251+
self.api_sender.send(msg).unwrap();
252+
}
253+
248254
#[inline]
249255
fn next_unique_id(&self) -> (u32, u32) {
250256
let IdNamespace(namespace) = self.id_namespace;

webrender_traits/src/types.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ pub enum ApiMsg {
5757
ResizeWebGLContext(WebGLContextId, Size2D<i32>),
5858
WebGLCommand(WebGLContextId, WebGLCommand),
5959
GenerateFrame,
60+
// WebVR commands that must be called in the WebGL render thread.
61+
VRCompositorCommand(WebGLContextId, VRCompositorCommand)
6062
}
6163

6264
#[derive(Copy, Clone, Deserialize, Serialize, Debug)]
@@ -644,7 +646,16 @@ pub enum WebGLCommand {
644646
DrawingBufferHeight(MsgSender<i32>),
645647
Finish(MsgSender<()>),
646648
Flush,
647-
GenerateMipmap(u32),
649+
GenerateMipmap(u32)
650+
}
651+
652+
// WebVR commands that must be called in the WebGL render thread.
653+
#[derive(Clone, Deserialize, Serialize)]
654+
pub enum VRCompositorCommand {
655+
Create(VRCompositorId),
656+
SyncPoses(VRCompositorId, f64, f64, MsgSender<Result<Vec<u8>,()>>),
657+
SubmitFrame(VRCompositorId, [f32; 4], [f32; 4]),
658+
Release(VRCompositorId)
648659
}
649660

650661
#[cfg(feature = "nightly")]
@@ -784,3 +795,18 @@ pub enum WebGLShaderParameter {
784795
Bool(bool),
785796
Invalid,
786797
}
798+
799+
pub type VRCompositorId = u64;
800+
801+
// Trait object that runs WebVR commands that must be called in the WebGL render thread.
802+
pub trait VRCompositor {
803+
// Synchronization point to keep in step with the HMD.
804+
fn sync_poses(&self, f64, f64) -> Vec<u8>;
805+
// Submits the frame to the display using the shared WebGLContext texture.
806+
fn submit_frame(&self, u32, [f32; 4], [f32; 4]);
807+
}
808+
809+
// Trait that allows to create VRCompositor instance using decoupled dependencies.
810+
pub trait VRCompositorCreator: Send {
811+
fn create_compositor(&mut self, VRCompositorId) -> Option<Box<VRCompositor>>;
812+
}

0 commit comments

Comments
 (0)