Bug 1082890 - Make BasicCompositor work for gonk widgets, again. r=mwu
--- 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();
};