Bug 1347641 - Implement the BlobImageRenderer binding glue. r=jrmuizel
authorNicolas Silva <nsilva@mozilla.com>
Mon, 27 Mar 2017 13:44:52 +0200
changeset 349957 3b0e181ef22d141b0fa4deadd548b9a4f6adb4e5
parent 349956 3c44df6bb970d10a4a6c33e752056381d17db801
child 349958 04bfc9efd61601638d9a91e777453a3a527dea59
push id88516
push userkwierso@gmail.com
push dateTue, 28 Mar 2017 00:18:55 +0000
treeherdermozilla-inbound@4346f1053ce3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1347641
milestone55.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 1347641 - Implement the BlobImageRenderer binding glue. r=jrmuizel
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/webrender_bindings/Moz2DImageRenderer.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/WebRenderTypes.h
gfx/webrender_bindings/moz.build
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -35,16 +35,18 @@ parent:
   // Creates a set of mappings between TextureReadLocks and an associated
   // ReadLockHandle that can be used in Update, and persist until the
   // next Update call.
   async InitReadLocks(ReadLockInit[] locks);
 
   sync Create(IntSize aSize);
   sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
                 SurfaceFormat aFormat, ByteBuffer aBytes);
+  async AddBlobImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
+                     SurfaceFormat aFormat, ByteBuffer aBytes);
   sync UpdateImage(ImageKey aImageKey, IntSize aSize,
                    SurfaceFormat aFormat, ByteBuffer aBytes);
   sync DeleteImage(ImageKey aImageKey);
   async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
   async DPBegin(IntSize aSize);
   async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
               ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
   sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -153,33 +153,51 @@ WebRenderBridgeParent::Destroy()
     return;
   }
   mDestroyed = true;
   ClearResources();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
-				    const gfx::IntSize& aSize,
+                                    const gfx::IntSize& aSize,
                                     const uint32_t& aStride,
                                     const gfx::SurfaceFormat& aFormat,
                                     const ByteBuffer& aBuffer)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(mApi);
   wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
   mApi->AddImage(aImageKey, descriptor,
                  aBuffer.AsSlice());
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvAddBlobImage(const wr::ImageKey& aImageKey,
+                        				        const gfx::IntSize& aSize,
+                                        const uint32_t& aStride,
+                                        const gfx::SurfaceFormat& aFormat,
+                                        const ByteBuffer& aBuffer)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
+  mApi->AddBlobImage(aImageKey, descriptor,
+                     aBuffer.AsSlice());
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
                                       const ByteBuffer& aBuffer,
                                       const uint32_t& aFontIndex)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(mApi);
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -63,16 +63,21 @@ public:
 
   mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
   mozilla::ipc::IPCResult RecvShutdown() override;
   mozilla::ipc::IPCResult RecvAddImage(const wr::ImageKey& aImageKey,
                                        const gfx::IntSize& aSize,
                                        const uint32_t& aStride,
                                        const gfx::SurfaceFormat& aFormat,
                                        const ByteBuffer& aBuffer) override;
+  mozilla::ipc::IPCResult RecvAddBlobImage(const wr::ImageKey& aImageKey,
+                                           const gfx::IntSize& aSize,
+                                           const uint32_t& aStride,
+                                           const gfx::SurfaceFormat& aFormat,
+                                           const ByteBuffer& aBuffer) override;
   mozilla::ipc::IPCResult RecvAddRawFont(const wr::FontKey& aFontKey,
                                          const ByteBuffer& aBuffer,
                                          const uint32_t& aFontIndex) override;
   mozilla::ipc::IPCResult RecvUpdateImage(const wr::ImageKey& aImageKey,
                                           const gfx::IntSize& aSize,
                                           const gfx::SurfaceFormat& aFormat,
                                           const ByteBuffer& aBuffer) override;
   mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/Moz2DImageRenderer.cpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#include "mozilla/Range.h"
+#include "mozilla/gfx/2D.h"
+#include "WebRenderTypes.h"
+
+namespace mozilla {
+namespace wr {
+
+static bool Moz2DRenderCallback(const Range<uint8_t> aBlob,
+                                gfx::IntSize aSize,
+                                gfx::SurfaceFormat aFormat,
+                                Range<uint8_t> output)
+{
+  return false; // TODO(nical)
+}
+
+} // namespace
+} // namespace
+
+extern "C" {
+
+bool wr_moz2d_render_cb(const WrByteSlice blob,
+                        uint32_t width, uint32_t height,
+                        mozilla::wr::ImageFormat aFormat,
+                        WrByteSlice output)
+{
+  return mozilla::wr::Moz2DRenderCallback(mozilla::wr::ByteSliceToRange(blob),
+                                          mozilla::gfx::IntSize(width, height),
+                                          mozilla::wr::WrImageFormatToSurfaceFormat(aFormat),
+                                          mozilla::wr::ByteSliceToRange(output));
+}
+
+} // extern
+
+
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -298,16 +298,26 @@ WebRenderAPI::AddImage(ImageKey key, con
 {
   wr_api_add_image(mWrApi,
                    key,
                    &aDescriptor,
                    RangeToByteSlice(aBytes));
 }
 
 void
+WebRenderAPI::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
+                           Range<uint8_t> aBytes)
+{
+  wr_api_add_blob_image(mWrApi,
+                        key,
+                        &aDescriptor,
+                        RangeToByteSlice(aBytes));
+}
+
+void
 WebRenderAPI::AddExternalImageHandle(ImageKey key,
                                      gfx::IntSize aSize,
                                      gfx::SurfaceFormat aFormat,
                                      uint64_t aHandle)
 {
   auto format = SurfaceFormatToWrImageFormat(aFormat).value();
   wr_api_add_external_image_handle(mWrApi,
                                    key,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -62,16 +62,20 @@ public:
                             WrPipelineId pipeline_id);
 
   void SetRootPipeline(wr::PipelineId aPipeline);
 
   void AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
+  void AddBlobImage(wr::ImageKey aKey,
+                    const ImageDescriptor& aDescriptor,
+                    Range<uint8_t> aBytes);
+
   void AddExternalImageHandle(ImageKey key,
                               gfx::IntSize aSize,
                               gfx::SurfaceFormat aFormat,
                               uint64_t aHandle);
 
   void AddExternalImageBuffer(ImageKey key,
                               const ImageDescriptor& aDescriptor,
                               uint64_t aHandle);
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -55,16 +55,30 @@ SurfaceFormatToWrImageFormat(gfx::Surfac
       return Some(WrImageFormat::A8);
     case gfx::SurfaceFormat::UNKNOWN:
       return Some(WrImageFormat::Invalid);
     default:
       return Nothing();
   }
 }
 
+inline gfx::SurfaceFormat
+WrImageFormatToSurfaceFormat(ImageFormat aFormat) {
+  switch (aFormat) {
+    case ImageFormat::RGBA8:
+      return gfx::SurfaceFormat::B8G8R8A8;
+    case ImageFormat::A8:
+      return gfx::SurfaceFormat::A8;
+    case ImageFormat::RGB8:
+      return gfx::SurfaceFormat::B8G8R8;
+    default:
+      return gfx::SurfaceFormat::UNKNOWN;
+  }
+}
+
 struct ImageDescriptor: public WrImageDescriptor {
   ImageDescriptor(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat)
   {
     format = SurfaceFormatToWrImageFormat(aFormat).value();
     width = aSize.width;
     height = aSize.height;
     stride = 0;
     is_opaque = gfx::IsOpaqueFormat(aFormat);
@@ -422,16 +436,20 @@ struct ByteBuffer
   uint8_t* mData;
   bool mOwned;
 };
 
 inline WrByteSlice RangeToByteSlice(mozilla::Range<uint8_t> aRange) {
   return WrByteSlice { aRange.begin().get(), aRange.length() };
 }
 
+inline mozilla::Range<uint8_t> ByteSliceToRange(WrByteSlice aWrSlice) {
+  return mozilla::Range<uint8_t>(aWrSlice.mBuffer, aWrSlice.mLength);
+}
+
 struct BuiltDisplayList {
   VecU8 dl;
   WrBuiltDisplayListDescriptor dl_desc;
   VecU8 aux;
   WrAuxiliaryListsDescriptor aux_desc;
 };
 
 } // namespace wr
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -12,16 +12,17 @@ EXPORTS.mozilla.webrender += [
     'RenderTextureHost.h',
     'RenderThread.h',
     'webrender_ffi.h',
     'WebRenderAPI.h',
     'WebRenderTypes.h',
 ]
 
 UNIFIED_SOURCES += [
+    'Moz2DImageRenderer.cpp',
     'RendererOGL.cpp',
     'RenderTextureHost.cpp',
     'RenderThread.cpp',
     'WebRenderAPI.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,22 +1,26 @@
 use std::ffi::CString;
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::os::raw::{c_void, c_char};
+use std::sync::Arc;
+use std::collections::HashMap;
 use gleam::gl;
 
 use webrender_traits::{AuxiliaryLists, AuxiliaryListsDescriptor, BorderDetails, BorderRadius};
 use webrender_traits::{BorderSide, BorderStyle, BorderWidths, BoxShadowClipMode, BuiltDisplayList};
 use webrender_traits::{BuiltDisplayListDescriptor, ClipRegion, ColorF, ComplexClipRegion};
 use webrender_traits::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, Epoch, ExtendMode};
 use webrender_traits::{ExternalEvent, ExternalImageId, FilterOp, FontKey, GlyphInstance};
 use webrender_traits::{GradientStop, IdNamespace, ImageBorder, ImageData, ImageDescriptor};
 use webrender_traits::{ImageFormat, ImageKey, ImageMask, ImageRendering, ItemRange, LayerPixel};
 use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode};
+use webrender_traits::{BlobImageData, BlobImageRenderer, BlobImageResult, BlobImageError};
+use webrender_traits::{BlobImageDescriptor, RasterizedBlobImage};
 use webrender_traits::{NinePatchDescriptor, NormalBorder, PipelineId, PropertyBinding, RenderApi};
 use webrender_traits::RepeatMode;
 use webrender::renderer::{Renderer, RendererOptions};
 use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use app_units::Au;
 use euclid::{TypedPoint2D, SideOffsets2D};
 
@@ -748,16 +752,17 @@ pub extern "C" fn wr_window_new(window_i
 
     println!("WebRender - OpenGL version new {}", version);
 
     let opts = RendererOptions {
         enable_aa: true,
         enable_subpixel_aa: true,
         enable_profiler: enable_profiler,
         recorder: recorder,
+        blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new())),
         ..Default::default()
     };
 
     let window_size = DeviceUintSize::new(window_width, window_height);
     let (renderer, sender) = match Renderer::new(gl, opts, window_size) {
         Ok((renderer, sender)) => (renderer, sender),
         Err(e) => {
             println!(" Failed to create a Renderer: {:?}", e);
@@ -788,16 +793,29 @@ pub extern "C" fn wr_api_add_image(api: 
     let copied_bytes = bytes.as_slice().to_owned();
     api.add_image(image_key,
                   descriptor.to_descriptor(),
                   ImageData::new(copied_bytes),
                   None);
 }
 
 #[no_mangle]
+pub extern "C" fn wr_api_add_blob_image(api: &mut RenderApi,
+                                        image_key: ImageKey,
+                                        descriptor: &WrImageDescriptor,
+                                        bytes: ByteSlice) {
+    assert!(unsafe { is_in_compositor_thread() });
+    let copied_bytes = bytes.as_slice().to_owned();
+    api.add_image(image_key,
+                  descriptor.to_descriptor(),
+                  ImageData::new_blob_image(copied_bytes),
+                  None);
+}
+
+#[no_mangle]
 pub extern "C" fn wr_api_add_external_image_handle(api: &mut RenderApi,
                                                    image_key: ImageKey,
                                                    width: u32,
                                                    height: u32,
                                                    format: ImageFormat,
                                                    external_image_id: u64) {
     assert!(unsafe { is_in_compositor_thread() });
     api.add_image(image_key,
@@ -1336,8 +1354,68 @@ pub unsafe extern "C" fn wr_dp_push_buil
     let dl_vec = dl_data.to_vec();
     let aux_vec = aux_data.to_vec();
 
     let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
     let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
 
     state.frame_builder.dl_builder.push_built_display_list(dl, aux);
 }
+
+struct Moz2dImageRenderer {
+    images: HashMap<ImageKey, BlobImageResult>
+}
+
+impl BlobImageRenderer for Moz2dImageRenderer {
+    fn request_blob_image(&mut self,
+                          key: ImageKey,
+                          data: Arc<BlobImageData>,
+                          descriptor: &BlobImageDescriptor) {
+        let result = self.render_blob_image(data, descriptor);
+        self.images.insert(key, result);
+    }
+
+    fn resolve_blob_image(&mut self, key: ImageKey) -> BlobImageResult {
+        return match self.images.remove(&key) {
+            Some(result) => result,
+            None => Err(BlobImageError::InvalidKey),
+        }
+    }
+}
+
+impl Moz2dImageRenderer {
+    fn new() -> Self {
+        Moz2dImageRenderer {
+            images: HashMap::new(),
+        }
+    }
+
+    fn render_blob_image(&mut self, data: Arc<BlobImageData>, descriptor: &BlobImageDescriptor) -> BlobImageResult {
+        let mut output = Vec::with_capacity(
+            (descriptor.width * descriptor.height * descriptor.format.bytes_per_pixel().unwrap()) as usize
+        );
+
+        unsafe {
+            if wr_moz2d_render_cb(ByteSlice::new(&data[..]),
+                                  descriptor.width,
+                                  descriptor.height,
+                                  descriptor.format,
+                                  MutByteSlice::new(output.as_mut_slice())) {
+                return Ok(RasterizedBlobImage {
+                    width: descriptor.width,
+                    height: descriptor.height,
+                    data: output,
+                });
+            }
+        }
+
+        Err(BlobImageError::Other("unimplemented!".to_string()))
+    }
+}
+
+extern "C" {
+    // TODO: figure out the API for tiled blob images.
+    fn wr_moz2d_render_cb(blob: ByteSlice,
+                          width: u32,
+                          height: u32,
+                          format: ImageFormat,
+                          output: MutByteSlice) -> bool;
+}
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -536,16 +536,20 @@ WR_INLINE void
 wr_api_delete(WrAPI* api)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE void
 wr_api_add_image(WrAPI* api, WrImageKey key, const WrImageDescriptor* descriptor, const WrByteSlice aSlice)
 WR_FUNC;
 
 WR_INLINE void
+wr_api_add_blob_image(WrAPI* api, WrImageKey key, const WrImageDescriptor* descriptor, const WrByteSlice aSlice)
+WR_FUNC;
+
+WR_INLINE void
 wr_api_add_external_image_handle(WrAPI* api, WrImageKey key, uint32_t width, uint32_t height,
                                  WrImageFormat format, uint64_t external_image_id)
 WR_FUNC;
 
 WR_INLINE void
 wr_api_add_external_image_buffer(WrAPI* api, WrImageKey key,
                                  const WrImageDescriptor* descriptor,
                                  uint64_t external_image_id)