Bug 1449982 - Add the plumbing for scene builder thread interaction. r?nical draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 10 Apr 2018 12:29:55 -0400
changeset 779786 a14e72dc7259e27ecfb0b6d7ea98c831fe195888
parent 779785 fd3d72afcc7dfa2c333c65bca436650654c4add5
child 779787 f79351207dd428b3e680d43e7a82c948cd5cf960
push id105878
push userkgupta@mozilla.com
push dateTue, 10 Apr 2018 16:32:25 +0000
reviewersnical
bugs1449982
milestone61.0a1
Bug 1449982 - Add the plumbing for scene builder thread interaction. r?nical This is all the (bidirectional) glue that connects the SceneBuilderHooks to the APZUpdater. MozReview-Commit-ID: JIqUaClVa57
gfx/layers/apz/src/APZUpdater.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
gfx/webrender_bindings/webrender_ffi_generated.h
--- a/gfx/layers/apz/src/APZUpdater.cpp
+++ b/gfx/layers/apz/src/APZUpdater.cpp
@@ -263,8 +263,36 @@ APZUpdater::RunOnControllerThread(alread
   RunOnUpdaterThread(NewRunnableFunction(
       "APZUpdater::RunOnControllerThread",
       &APZThreadUtils::RunOnControllerThread,
       Move(aTask)));
 }
 
 } // namespace layers
 } // namespace mozilla
+
+// Rust callback implementations
+
+void
+apz_register_updater(mozilla::wr::WrWindowId aWindowId)
+{
+}
+
+void
+apz_pre_scene_swap(mozilla::wr::WrWindowId aWindowId)
+{
+}
+
+void
+apz_post_scene_swap(mozilla::wr::WrWindowId aWindowId,
+                    mozilla::wr::WrPipelineInfo* aInfo)
+{
+}
+
+void
+apz_run_updater(mozilla::wr::WrWindowId aWindowId)
+{
+}
+
+void
+apz_deregister_updater(mozilla::wr::WrWindowId aWindowId)
+{
+}
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -502,16 +502,22 @@ WebRenderAPI::Resume()
     // implies that all frame data have been processed when the renderer runs this event.
     RunOnRenderThread(Move(event));
 
     task.Wait();
     return result;
 }
 
 void
+WebRenderAPI::WakeSceneBuilder()
+{
+    wr_api_wake_scene_builder(mDocHandle);
+}
+
+void
 WebRenderAPI::WaitFlushed()
 {
     class WaitFlushedEvent : public RendererEvent
     {
         public:
             explicit WaitFlushedEvent(layers::SynchronousTask* aTask)
                 : mTask(aTask)
             {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -178,16 +178,18 @@ public:
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
 
   void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
 
   void Pause();
   bool Resume();
 
+  void WakeSceneBuilder();
+
   wr::WrIdNamespace GetNamespace();
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
   layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }
 
   void Capture();
 
 protected:
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -7,16 +7,17 @@ use std::sync::Arc;
 use std::os::raw::{c_void, c_char, c_float};
 use gleam::gl;
 
 use webrender::api::*;
 use webrender::{ReadPixelsFormat, Renderer, RendererOptions, ThreadListener};
 use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::DebugFlags;
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
+use webrender::{PipelineInfo, SceneBuilderHooks};
 use webrender::{ProgramCache, UploadMethod, VertexUsageHint};
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dImageRenderer;
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
 use log;
 
@@ -596,26 +597,29 @@ pub unsafe extern "C" fn wr_renderer_del
     // let renderer go out of scope and get dropped
 }
 
 pub struct WrPipelineInfo {
     epochs: Vec<(WrPipelineId, WrEpoch)>,
     removed_pipelines: Vec<PipelineId>,
 }
 
-#[no_mangle]
-pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> *mut WrPipelineInfo {
-    let info = renderer.flush_pipeline_info();
-    let pipeline_epochs = Box::new(
+impl WrPipelineInfo {
+    fn new(info: PipelineInfo) -> Self {
         WrPipelineInfo {
             epochs: info.epochs.into_iter().collect(),
             removed_pipelines: info.removed_pipelines,
         }
-    );
-    return Box::into_raw(pipeline_epochs);
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> *mut WrPipelineInfo {
+    let info = renderer.flush_pipeline_info();
+    Box::into_raw(Box::new(WrPipelineInfo::new(info)))
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_pipeline_info_next_epoch(
     info: &mut WrPipelineInfo,
     out_pipeline: &mut WrPipelineId,
     out_epoch: &mut WrEpoch
 ) -> bool {
@@ -640,16 +644,62 @@ pub unsafe extern "C" fn wr_pipeline_inf
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_pipeline_info_delete(info: *mut WrPipelineInfo) {
     Box::from_raw(info);
 }
 
+#[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the *mut WrPipelineInfo to an extern function
+extern "C" {
+    fn apz_register_updater(window_id: WrWindowId);
+    fn apz_pre_scene_swap(window_id: WrWindowId);
+    // This function takes ownership of the pipeline_info and is responsible for
+    // freeing it via wr_pipeline_info_delete.
+    fn apz_post_scene_swap(window_id: WrWindowId, pipeline_info: *mut WrPipelineInfo);
+    fn apz_run_updater(window_id: WrWindowId);
+    fn apz_deregister_updater(window_id: WrWindowId);
+}
+
+struct APZCallbacks {
+    window_id: WrWindowId,
+}
+
+impl APZCallbacks {
+    pub fn new(window_id: WrWindowId) -> Self {
+        APZCallbacks {
+            window_id,
+        }
+    }
+}
+
+impl SceneBuilderHooks for APZCallbacks {
+    fn register(&self) {
+        unsafe { apz_register_updater(self.window_id) }
+    }
+
+    fn pre_scene_swap(&self) {
+        unsafe { apz_pre_scene_swap(self.window_id) }
+    }
+
+    fn post_scene_swap(&self, info: PipelineInfo) {
+        let info = Box::into_raw(Box::new(WrPipelineInfo::new(info)));
+        unsafe { apz_post_scene_swap(self.window_id, info) }
+    }
+
+    fn poke(&self) {
+        unsafe { apz_run_updater(self.window_id) }
+    }
+
+    fn deregister(&self) {
+        unsafe { apz_deregister_updater(self.window_id) }
+    }
+}
+
 extern "C" {
     fn gecko_profiler_register_thread(name: *const ::std::os::raw::c_char);
     fn gecko_profiler_unregister_thread();
 }
 
 struct GeckoProfilerThreadListener {}
 
 impl GeckoProfilerThreadListener {
@@ -779,16 +829,17 @@ pub extern "C" fn wr_window_new(window_i
                 match CStr::from_ptr(override_charptr).to_str() {
                     Ok(override_str) => Some(PathBuf::from(override_str)),
                     _ => None
                 }
             }
         },
         renderer_id: Some(window_id.0),
         upload_method,
+        scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
         ..Default::default()
     };
 
     let notifier = Box::new(CppNotifier {
         window_id: window_id,
     });
     let (renderer, sender) = match Renderer::new(gl, notifier, opts) {
         Ok((renderer, sender)) => (renderer, sender),
@@ -1322,16 +1373,21 @@ pub extern "C" fn wr_resource_updates_de
     }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
     dh.api.get_namespace_id()
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn wr_api_wake_scene_builder(dh: &mut DocumentHandle) {
+    dh.api.wake_scene_builder();
+}
+
 // RenderThread WIP notes:
 // In order to separate the compositor thread (or ipc receiver) and the render
 // thread, some of the logic below needs to be rewritten. In particular
 // the WrWindowState and Notifier implementations aren't designed to work with
 // a separate render thread.
 // As part of that I am moving the bindings closer to WebRender's API boundary,
 // and moving more of the logic in C++ land.
 // This work is tracked by bug 1328602.
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -80,19 +80,28 @@ struct FontInstanceFlags {
     FONT_SMOOTHING    = 1 << 16,
 
     FORCE_AUTOHINT    = 1 << 16,
     NO_AUTOHINT       = 1 << 17,
     VERTICAL_LAYOUT   = 1 << 18
   };
 };
 
+struct WrWindowId;
+struct WrPipelineInfo;
+
 } // namespace wr
 } // namespace mozilla
 
+void apz_register_updater(mozilla::wr::WrWindowId aWindowId);
+void apz_pre_scene_swap(mozilla::wr::WrWindowId aWindowId);
+void apz_post_scene_swap(mozilla::wr::WrWindowId aWindowId, mozilla::wr::WrPipelineInfo* aInfo);
+void apz_run_updater(mozilla::wr::WrWindowId aWindowId);
+void apz_deregister_updater(mozilla::wr::WrWindowId aWindowId);
+
 } // extern "C"
 
 // Some useful defines to stub out webrender binding functions for when we
 // build gecko without webrender. We try to tell the compiler these functions
 // are unreachable in that case, but VC++ emits a warning if it finds any
 // unreachable functions invoked from destructors. That warning gets turned into
 // an error and causes the build to fail. So for wr_* functions called by
 // destructors in C++ classes, use WR_DESTRUCTOR_SAFE_FUNC instead, which omits
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -310,16 +310,30 @@ struct FontKey {
 };
 
 using WrFontKey = FontKey;
 
 using VecU8 = Vec<uint8_t>;
 
 using ArcVecU8 = Arc<VecU8>;
 
+struct WrWindowId {
+  uint64_t mHandle;
+
+  bool operator==(const WrWindowId& aOther) const {
+    return mHandle == aOther.mHandle;
+  }
+  bool operator<(const WrWindowId& aOther) const {
+    return mHandle < aOther.mHandle;
+  }
+  bool operator<=(const WrWindowId& aOther) const {
+    return mHandle <= aOther.mHandle;
+  }
+};
+
 template<typename T, typename U>
 struct TypedSize2D {
   T width;
   T height;
 
   bool operator==(const TypedSize2D& aOther) const {
     return width == aOther.width &&
            height == aOther.height;
@@ -740,30 +754,16 @@ struct MutByteSlice {
   uintptr_t len;
 
   bool operator==(const MutByteSlice& aOther) const {
     return buffer == aOther.buffer &&
            len == aOther.len;
   }
 };
 
-struct WrWindowId {
-  uint64_t mHandle;
-
-  bool operator==(const WrWindowId& aOther) const {
-    return mHandle == aOther.mHandle;
-  }
-  bool operator<(const WrWindowId& aOther) const {
-    return mHandle < aOther.mHandle;
-  }
-  bool operator<=(const WrWindowId& aOther) const {
-    return mHandle <= aOther.mHandle;
-  }
-};
-
 struct Epoch {
   uint32_t mHandle;
 
   bool operator==(const Epoch& aOther) const {
     return mHandle == aOther.mHandle;
   }
   bool operator<(const Epoch& aOther) const {
     return mHandle < aOther.mHandle;
@@ -942,16 +942,27 @@ extern void AddFontData(WrFontKey aKey,
                         const ArcVecU8 *aVec);
 
 extern void AddNativeFontHandle(WrFontKey aKey,
                                 void *aHandle,
                                 uint32_t aIndex);
 
 extern void DeleteFontData(WrFontKey aKey);
 
+extern void apz_deregister_updater(WrWindowId aWindowId);
+
+extern void apz_post_scene_swap(WrWindowId aWindowId,
+                                WrPipelineInfo *aPipelineInfo);
+
+extern void apz_pre_scene_swap(WrWindowId aWindowId);
+
+extern void apz_register_updater(WrWindowId aWindowId);
+
+extern void apz_run_updater(WrWindowId aWindowId);
+
 extern void gecko_printf_stderr_output(const char *aMsg);
 
 extern void gecko_profiler_register_thread(const char *aName);
 
 extern void gecko_profiler_unregister_thread();
 
 extern void gfx_critical_error(const char *aMsg);
 
@@ -1030,16 +1041,20 @@ void wr_api_send_transaction(DocumentHan
                              Transaction *aTransaction)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_shut_down(DocumentHandle *aDh)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
+void wr_api_wake_scene_builder(DocumentHandle *aDh)
+WR_FUNC;
+
+WR_INLINE
 void wr_clear_item_tag(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dec_ref_arc(const VecU8 *aArc)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE