Bug 1082890 - Make BasicCompositor work for gonk widgets, again. r=mwu
authorChris Jones <cjones.bugs@gmail.com>
Thu, 16 Oct 2014 13:57:10 -0700
changeset 210919 80a92f907fbd0de7c56aae6f3882f5fa7f157497
parent 210918 515d83408ae7d37b6c264742796804ef0fd65d14
child 210920 b73bb9d2c9e1bda1804bea88894f60186ec42a96
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmwu
bugs1082890
milestone36.0a1
Bug 1082890 - Make BasicCompositor work for gonk widgets, again. r=mwu
widget/gonk/nsWindow.cpp
widget/gonk/nsWindow.h
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -39,31 +39,33 @@
 #include "nsWindow.h"
 #include "nsIWidgetListener.h"
 #include "cutils/properties.h"
 #include "ClientLayerManager.h"
 #include "BasicLayers.h"
 #include "libdisplay/GonkDisplay.h"
 #include "pixelflinger/format.h"
 #include "mozilla/BasicEvents.h"
+#include "mozilla/gfx/2D.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "ParentProcessController.h"
 #include "nsThreadUtils.h"
 #include "HwcComposer2D.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args)
 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args)
 
 #define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
+using namespace mozilla::gfx;
 using namespace mozilla::gl;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 nsIntRect gScreenBounds;
 static uint32_t sScreenRotation;
 static uint32_t sPhysicalScreenRotation;
 static nsIntRect sVirtualBounds;
@@ -121,16 +123,18 @@ displayEnabledCallback(bool enabled)
     HwcComposer2D::GetInstance()->EnableVsync(enabled);
     NS_DispatchToMainThread(enabled ? sScreenOnEvent : sScreenOffEvent);
 }
 
 } // anonymous namespace
 
 nsWindow::nsWindow()
 {
+    mFramebuffer = nullptr;
+
     if (sScreenInitialized)
         return;
 
     sScreenOnEvent = new ScreenOnOffEvent(true);
     ClearOnShutdown(&sScreenOnEvent);
     sScreenOffEvent = new ScreenOnOffEvent(false);
     ClearOnShutdown(&sScreenOffEvent);
     GetGonkDisplay()->OnEnabled(displayEnabledCallback);
@@ -467,16 +471,84 @@ nsWindow::MakeFullScreen(bool aFullScree
         // unpainted.
         Resize(sVirtualBounds.x, sVirtualBounds.y,
                sVirtualBounds.width, sVirtualBounds.height,
                /*repaint*/true);
     }
     return NS_OK;
 }
 
+static gralloc_module_t const*
+gralloc_module()
+{
+    hw_module_t const *module;
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) {
+        return nullptr;
+    }
+    return reinterpret_cast<gralloc_module_t const*>(module);
+}
+
+static SurfaceFormat
+HalFormatToSurfaceFormat(int aHalFormat, int* bytepp)
+{
+    switch (aHalFormat) {
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+        *bytepp = 4;
+        return SurfaceFormat::R8G8B8A8;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+        *bytepp = 4;
+        return SurfaceFormat::R8G8B8X8;
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+        *bytepp = 4;
+        return SurfaceFormat::B8G8R8A8;
+    case HAL_PIXEL_FORMAT_RGB_565:
+        *bytepp = 2;
+        return SurfaceFormat::R5G6B5;
+    default:
+        MOZ_CRASH("Unhandled HAL pixel format");
+        return SurfaceFormat::UNKNOWN; // not reached
+    }
+}
+
+TemporaryRef<DrawTarget>
+nsWindow::StartRemoteDrawing()
+{
+    GonkDisplay* display = GetGonkDisplay();
+    mFramebuffer = display->DequeueBuffer();
+    int width = mFramebuffer->width, height = mFramebuffer->height;
+    void *vaddr;
+    if (gralloc_module()->lock(gralloc_module(), mFramebuffer->handle,
+                               GRALLOC_USAGE_SW_READ_NEVER |
+                               GRALLOC_USAGE_SW_WRITE_OFTEN |
+                               GRALLOC_USAGE_HW_FB,
+                               0, 0, width, height, &vaddr)) {
+        EndRemoteDrawing();
+        return nullptr;
+    }
+    int bytepp;
+    SurfaceFormat format = HalFormatToSurfaceFormat(display->surfaceformat,
+                                                    &bytepp);
+    return mFramebufferTarget = Factory::CreateDrawTargetForData(
+        BackendType::CAIRO, (uint8_t*)vaddr,
+        IntSize(width, height), mFramebuffer->stride * bytepp, format);
+}
+
+void
+nsWindow::EndRemoteDrawing()
+{
+    if (mFramebufferTarget) {
+        gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle);
+    }
+    if (mFramebuffer) {
+        GetGonkDisplay()->QueueBuffer(mFramebuffer);
+    }
+    mFramebuffer = nullptr;
+    mFramebufferTarget = nullptr;
+}
+
 float
 nsWindow::GetDPI()
 {
     return GetGonkDisplay()->xdpi;
 }
 
 double
 nsWindow::GetDefaultScaleInternal()
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -14,28 +14,31 @@
  */
 
 #ifndef nsWindow_h
 #define nsWindow_h
 
 #include "nsBaseWidget.h"
 #include "nsRegion.h"
 #include "nsIIdleServiceInternal.h"
+#include "Units.h"
 
 extern nsIntRect gScreenBounds;
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 class LayersManager;
 }
 }
 
+class ANativeWindowBuffer;
+
 namespace android {
 class FramebufferNativeWindow;
 }
 
 namespace widget {
 struct InputContext;
 struct InputContextAction;
 }
@@ -89,16 +92,20 @@ public:
                                    bool aDoCapture)
     {
         return NS_ERROR_NOT_IMPLEMENTED;
     }
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
 
     NS_IMETHOD MakeFullScreen(bool aFullScreen) /*MOZ_OVERRIDE*/;
 
+    virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget>
+        StartRemoteDrawing() MOZ_OVERRIDE;
+    virtual void EndRemoteDrawing() MOZ_OVERRIDE;
+
     virtual float GetDPI();
     virtual double GetDefaultScaleInternal();
     virtual mozilla::layers::LayerManager*
         GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                         LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                         LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                         bool* aAllowRetaining = nullptr);
 
@@ -113,16 +120,21 @@ public:
 
     virtual Composer2D* GetComposer2D() MOZ_OVERRIDE;
 
 protected:
     nsWindow* mParent;
     bool mVisible;
     InputContext mInputContext;
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
+    // If we're using a BasicCompositor, these fields are temporarily
+    // set during frame composition.  They wrap the hardware
+    // framebuffer.
+    mozilla::RefPtr<mozilla::gfx::DrawTarget> mFramebufferTarget;
+    ANativeWindowBuffer* mFramebuffer;
 
     void BringToTop();
 
     // Call this function when the users activity is the direct cause of an
     // event (like a keypress or mouse click).
     void UserActivity();
 };