Bug 1591752 - FFI for WebRender OS compositor integration: Create WrCompositor struct which implements the webrender::Compositor trait and calls through to virtual methods on RenderCompositor. r=sotaro
authorMarkus Stange <mstange@themasta.com>
Sun, 27 Oct 2019 01:18:27 +0000
changeset 499375 69f9b16a76be90025457aa38645c3252420e8e1f
parent 499374 c556c522813239e87b566bb4d1e572efb52bdcaf
child 499376 956451c71574bec00e8dbf8a0b507e9fd28711e5
push id114161
push userncsoregi@mozilla.com
push dateTue, 29 Oct 2019 21:34:24 +0000
treeherdermozilla-inbound@25bf8e097e60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1591752
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1591752 - FFI for WebRender OS compositor integration: Create WrCompositor struct which implements the webrender::Compositor trait and calls through to virtual methods on RenderCompositor. r=sotaro This patch was largely written by Sotaro. This patch also adds an off-by-default pref gfx.webrender.compositor that currently does nothing. Differential Revision: https://phabricator.services.mozilla.com/D50721
gfx/webrender_bindings/RenderCompositor.cpp
gfx/webrender_bindings/RenderCompositor.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderTypes.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/webrender/src/composite.rs
modules/libpref/init/StaticPrefList.yaml
--- a/gfx/webrender_bindings/RenderCompositor.cpp
+++ b/gfx/webrender_bindings/RenderCompositor.cpp
@@ -18,16 +18,55 @@
 
 #if defined(MOZ_WAYLAND) || defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/webrender/RenderCompositorEGL.h"
 #endif
 
 namespace mozilla {
 namespace wr {
 
+void wr_compositor_add_surface(void* aCompositor, wr::NativeSurfaceId aId,
+                               wr::DeviceIntPoint aPosition,
+                               wr::DeviceIntRect aClipRect) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->AddSurface(aId, aPosition, aClipRect);
+}
+
+void wr_compositor_begin_frame(void* aCompositor) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->CompositorBeginFrame();
+}
+
+void wr_compositor_bind(void* aCompositor, wr::NativeSurfaceId aId,
+                        wr::DeviceIntPoint* aOffset) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->Bind(aId, aOffset);
+}
+
+void wr_compositor_create_surface(void* aCompositor, wr::NativeSurfaceId aId,
+                                  wr::DeviceIntSize aSize) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->CreateSurface(aId, aSize);
+}
+
+void wr_compositor_destroy_surface(void* aCompositor, NativeSurfaceId aId) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->DestroySurface(aId);
+}
+
+void wr_compositor_end_frame(void* aCompositor) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->CompositorEndFrame();
+}
+
+void wr_compositor_unbind(void* aCompositor) {
+  RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
+  compositor->Unbind();
+}
+
 /* static */
 UniquePtr<RenderCompositor> RenderCompositor::Create(
     RefPtr<widget::CompositorWidget>&& aWidget) {
 #ifdef XP_WIN
   if (gfx::gfxVars::UseWebRenderANGLE()) {
     return RenderCompositorANGLE::Create(std::move(aWidget));
   }
 #endif
--- a/gfx/webrender_bindings/RenderCompositor.h
+++ b/gfx/webrender_bindings/RenderCompositor.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_RENDERCOMPOSITOR_H
 #define MOZILLA_GFX_RENDERCOMPOSITOR_H
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 #include "Units.h"
 
 namespace mozilla {
 
 namespace gl {
 class GLContext;
 }
 
@@ -57,16 +58,31 @@ class RenderCompositor {
   virtual LayoutDeviceIntSize GetBufferSize() = 0;
 
   widget::CompositorWidget* GetWidget() const { return mWidget; }
 
   layers::SyncObjectHost* GetSyncObject() const { return mSyncObject.get(); }
 
   virtual bool IsContextLost();
 
+  virtual bool ShouldUseNativeCompositor() { return false; }
+
+  // Interface for wr::Compositor
+  virtual void CompositorBeginFrame() {}
+  virtual void CompositorEndFrame() {}
+  virtual void Bind(wr::NativeSurfaceId aId, wr::DeviceIntPoint* aOffset) {}
+  virtual void Unbind() {}
+  virtual void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aSize) {
+  }
+  virtual void DestroySurface(NativeSurfaceId aId) {}
+  virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
+                          wr::DeviceIntRect aClipRect) {}
+
+  void wr_compositor_unbind(void* aCompositor) {}
+
  protected:
   RefPtr<widget::CompositorWidget> mWidget;
   RefPtr<layers::SyncObjectHost> mSyncObject;
 };
 
 }  // namespace wr
 }  // namespace mozilla
 
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -70,36 +70,38 @@ class NewRenderer : public RendererEvent
     *mUseDComp = compositor->UseDComp();
     *mUseTripleBuffering = compositor->UseTripleBuffering();
 
     bool allow_texture_swizzling = gfx::gfxVars::UseGLSwizzle();
     bool isMainWindow = true;  // TODO!
     bool supportLowPriorityTransactions = isMainWindow;
     bool supportPictureCaching = isMainWindow;
     wr::Renderer* wrRenderer = nullptr;
-    if (!wr_window_new(aWindowId, mSize.width, mSize.height,
-                       supportLowPriorityTransactions, allow_texture_swizzling,
-                       StaticPrefs::gfx_webrender_picture_caching() &&
-                           supportPictureCaching,
+    if (!wr_window_new(
+            aWindowId, mSize.width, mSize.height,
+            supportLowPriorityTransactions, allow_texture_swizzling,
+            StaticPrefs::gfx_webrender_picture_caching() &&
+                supportPictureCaching,
 #ifdef NIGHTLY_BUILD
-                       StaticPrefs::gfx_webrender_start_debug_server(),
+            StaticPrefs::gfx_webrender_start_debug_server(),
 #else
-                       false,
+            false,
 #endif
-                       compositor->gl(),
-                       aRenderThread.GetProgramCache()
-                           ? aRenderThread.GetProgramCache()->Raw()
-                           : nullptr,
-                       aRenderThread.GetShaders()
-                           ? aRenderThread.GetShaders()->RawShaders()
-                           : nullptr,
-                       aRenderThread.ThreadPool().Raw(), &WebRenderMallocSizeOf,
-                       &WebRenderMallocEnclosingSizeOf,
-                       (uint32_t)wr::RenderRoot::Default, mDocHandle,
-                       &wrRenderer, mMaxTextureSize)) {
+            compositor->gl(),
+            aRenderThread.GetProgramCache()
+                ? aRenderThread.GetProgramCache()->Raw()
+                : nullptr,
+            aRenderThread.GetShaders()
+                ? aRenderThread.GetShaders()->RawShaders()
+                : nullptr,
+            aRenderThread.ThreadPool().Raw(), &WebRenderMallocSizeOf,
+            &WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default,
+            compositor->ShouldUseNativeCompositor() ? compositor.get()
+                                                    : nullptr,
+            mDocHandle, &wrRenderer, mMaxTextureSize)) {
       // wr_window_new puts a message into gfxCriticalNote if it returns false
       return;
     }
     MOZ_ASSERT(wrRenderer);
 
     RefPtr<RenderThread> thread = &aRenderThread;
     auto renderer =
         MakeUnique<RendererOGL>(std::move(thread), std::move(compositor),
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -220,16 +220,20 @@ struct ImageDescriptor : public wr::WrIm
     format = wr::SurfaceFormatToImageFormat(aFormat).value();
     width = aSize.width;
     height = aSize.height;
     stride = aByteStride;
     opacity = aOpacity;
   }
 };
 
+inline uint64_t AsUint64(const NativeSurfaceId& aId) {
+  return static_cast<uint64_t>(aId._0);
+}
+
 // Whenever possible, use wr::WindowId instead of manipulating uint64_t.
 inline uint64_t AsUint64(const WindowId& aId) {
   return static_cast<uint64_t>(aId.mHandle);
 }
 
 // Whenever possible, use wr::ImageKey instead of manipulating uint64_t.
 inline uint64_t AsUint64(const ImageKey& aId) {
   return (static_cast<uint64_t>(aId.mNamespace.mHandle) << 32) +
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -17,18 +17,18 @@ use std::ops::Range;
 use std::os::raw::{c_void, c_char, c_float};
 #[cfg(target_os = "android")]
 use std::os::raw::{c_int};
 use std::time::Duration;
 use gleam::gl;
 
 use webrender::{
     api::*, api::units::*, ApiRecordingReceiver, AsyncPropertySampler, AsyncScreenshotHandle,
-    BinaryRecorder, DebugFlags, Device, ExternalImage, ExternalImageHandler, ExternalImageSource,
-    PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats,
+    BinaryRecorder, Compositor, DebugFlags, Device, ExternalImage, ExternalImageHandler, ExternalImageSource,
+    NativeSurfaceId, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats,
     SceneBuilderHooks, ShaderPrecacheFlags, Shaders, ThreadListener, UploadMethod, VertexUsageHint,
     WrShaders, set_profiler_hooks,
 };
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dBlobImageHandler;
 use program_cache::{WrProgramCache, remove_disk_cache};
 use rayon;
 use num_cpus;
@@ -1130,32 +1130,147 @@ fn wr_device_new(gl_context: *mut c_void
     let cached_programs = match pc {
       Some(cached_programs) => Some(Rc::clone(cached_programs.rc_get())),
       None => None,
     };
 
     Device::new(gl, resource_override_path, upload_method, cached_programs, false, true, true, None)
 }
 
+extern "C" {
+    fn wr_compositor_create_surface(
+        compositor: *mut c_void,
+        id: NativeSurfaceId,
+        size: DeviceIntSize,
+    );
+    fn wr_compositor_destroy_surface(
+        compositor: *mut c_void,
+        id: NativeSurfaceId,
+    );
+    fn wr_compositor_bind(
+        compositor: *mut c_void,
+        id: NativeSurfaceId,
+        offset: &mut DeviceIntPoint,
+    );
+    fn wr_compositor_unbind(compositor: *mut c_void);
+    fn wr_compositor_begin_frame(compositor: *mut c_void);
+    fn wr_compositor_add_surface(
+        compositor: *mut c_void,
+        id: NativeSurfaceId,
+        position: DeviceIntPoint,
+        clip_rect: DeviceIntRect,
+    );
+    fn wr_compositor_end_frame(compositor: *mut c_void);
+}
+
+pub struct WrCompositor(*mut c_void);
+
+impl Compositor for WrCompositor {
+    fn create_surface(
+        &mut self,
+        id: NativeSurfaceId,
+        size: DeviceIntSize,
+    ) {
+        unsafe {
+            wr_compositor_create_surface(
+                self.0,
+                id,
+                size,
+            );
+        }
+    }
+
+    fn destroy_surface(
+        &mut self,
+        id: NativeSurfaceId,
+    ) {
+        unsafe {
+            wr_compositor_destroy_surface(
+                self.0,
+                id,
+            );
+        }
+    }
+
+    fn bind(
+        &mut self,
+        id: NativeSurfaceId,
+    ) -> DeviceIntPoint {
+        let mut offset = DeviceIntPoint::zero();
+        unsafe {
+            wr_compositor_bind(
+                self.0,
+                id,
+                &mut offset,
+            );
+        }
+        offset
+    }
+
+    fn unbind(
+        &mut self,
+    ) {
+        unsafe {
+            wr_compositor_unbind(
+                self.0,
+            );
+        }
+    }
+
+    fn begin_frame(&mut self) {
+        unsafe {
+            wr_compositor_begin_frame(
+                self.0,
+            );
+        }
+    }
+
+    fn add_surface(
+        &mut self,
+        id: NativeSurfaceId,
+        position: DeviceIntPoint,
+        clip_rect: DeviceIntRect,
+    ) {
+        unsafe {
+            wr_compositor_add_surface(
+                self.0,
+                id,
+                position,
+                clip_rect,
+            );
+        }
+    }
+
+    fn end_frame(&mut self) {
+        unsafe {
+            wr_compositor_end_frame(
+                self.0,
+            );
+        }
+    }
+}
+
+
 // Call MakeCurrent before this.
 #[no_mangle]
 pub extern "C" fn wr_window_new(window_id: WrWindowId,
                                 window_width: i32,
                                 window_height: i32,
                                 support_low_priority_transactions: bool,
                                 allow_texture_swizzling: bool,
                                 enable_picture_caching: bool,
                                 start_debug_server: bool,
                                 gl_context: *mut c_void,
                                 program_cache: Option<&mut WrProgramCache>,
                                 shaders: Option<&mut WrShaders>,
                                 thread_pool: *mut WrThreadPool,
                                 size_of_op: VoidPtrToSizeFn,
                                 enclosing_size_of_op: VoidPtrToSizeFn,
                                 document_id: u32,
+                                compositor: *mut c_void,
                                 out_handle: &mut *mut DocumentHandle,
                                 out_renderer: &mut *mut Renderer,
                                 out_max_texture_size: *mut i32)
                                 -> bool {
     assert!(unsafe { is_in_render_thread() });
 
     let recorder: Option<Box<dyn ApiRecordingReceiver>> = if unsafe { gfx_use_wrench() } {
         let name = format!("wr-record-{}.bin", window_id.0);
@@ -1198,16 +1313,22 @@ pub extern "C" fn wr_window_new(window_i
 
     let color = if cfg!(target_os = "android") {
         // The color is for avoiding black flash before receiving display list.
         ColorF::new(1.0, 1.0, 1.0, 1.0)
     } else {
         ColorF::new(0.0, 0.0, 0.0, 0.0)
     };
 
+    let native_compositor : Option<Box<dyn Compositor>> = if compositor != ptr::null_mut() {
+        Some(Box::new(WrCompositor(compositor)))
+    } else {
+        None
+    };
+
     let opts = RendererOptions {
         enable_aa: true,
         enable_subpixel_aa: cfg!(not(target_os = "android")),
         support_low_priority_transactions,
         allow_texture_swizzling,
         recorder: recorder,
         blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(workers.clone()))),
         workers: Some(workers.clone()),
@@ -1232,16 +1353,17 @@ pub extern "C" fn wr_window_new(window_i
         sampler: Some(Box::new(SamplerCallback::new(window_id))),
         max_texture_size: Some(8192), // Moz2D doesn't like textures bigger than this
         clear_color: Some(color),
         precache_flags,
         namespace_alloc_by_client: true,
         enable_picture_caching,
         allow_pixel_local_storage_support: false,
         start_debug_server,
+        native_compositor,
         ..Default::default()
     };
 
     // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
     set_profiler_hooks(Some(&PROFILER_HOOKS));
 
     let window_size = DeviceIntSize::new(window_width, window_height);
     let notifier = Box::new(CppNotifier {
--- a/gfx/wr/webrender/src/composite.rs
+++ b/gfx/wr/webrender/src/composite.rs
@@ -145,16 +145,17 @@ impl CompositeState {
                 id,
                 details: NativeSurfaceOperationDetails::DestroySurface,
             }
         );
     }
 }
 
 /// An arbitrary identifier for a native (OS compositor) surface
+#[repr(C)]
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct NativeSurfaceId(pub u64);
 
 /// Defines an interface to a native (OS level) compositor. If supplied
 /// by the client application, then picture cache slices will be
 /// composited by the OS compositor, rather than drawn via WR batches.
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -3557,16 +3557,21 @@
   value: true
   mirror: always
 
 - name: gfx.webrender.split-render-roots
   type: bool
   value: false
   mirror: once
 
+- name: gfx.webrender.compositor
+  type: bool
+  value: false
+  mirror: once
+
 #ifdef NIGHTLY_BUILD
   # Keep this pref hidden on non-nightly builds to avoid people accidentally
   # turning it on.
 -   name: gfx.webrender.start-debug-server
     type: RelaxedAtomicBool
     value: false
     mirror: always
 #endif