Bug 1273949 - CompositorBridgeParent::CompositorLoop to CompositorThreadHolder::Loop...
[gecko.git] / widget / gonk / nsScreenManagerGonk.cpp
blob27ae6f1a0a796574743d0ae4b7ef6cf94aecc9a3
1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include "android/log.h"
17 #include "GLContext.h"
18 #include "gfxPrefs.h"
19 #include "gfxUtils.h"
20 #include "mozilla/MouseEvents.h"
21 #include "mozilla/TouchEvents.h"
22 #include "mozilla/Hal.h"
23 #include "libdisplay/BootAnimation.h"
24 #include "libdisplay/GonkDisplay.h"
25 #include "nsScreenManagerGonk.h"
26 #include "nsThreadUtils.h"
27 #include "HwcComposer2D.h"
28 #include "VsyncSource.h"
29 #include "nsWindow.h"
30 #include "mozilla/ClearOnShutdown.h"
31 #include "mozilla/layers/CompositorBridgeParent.h"
32 #include "mozilla/layers/CompositorThread.h"
33 #include "mozilla/Services.h"
34 #include "mozilla/ProcessPriorityManager.h"
35 #include "nsIdleService.h"
36 #include "nsIObserverService.h"
37 #include "nsAppShell.h"
38 #include "nsProxyRelease.h"
39 #include "nsTArray.h"
40 #include "pixelflinger/format.h"
41 #include "nsIDisplayInfo.h"
43 #if ANDROID_VERSION >= 17
44 #include "libdisplay/DisplaySurface.h"
45 #endif
47 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsScreenGonk" , ## args)
48 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "nsScreenGonk", ## args)
49 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "nsScreenGonk", ## args)
51 using namespace mozilla;
52 using namespace mozilla::hal;
53 using namespace mozilla::gfx;
54 using namespace mozilla::gl;
55 using namespace mozilla::layers;
56 using namespace mozilla::dom;
58 namespace {
60 class ScreenOnOffEvent : public mozilla::Runnable {
61 public:
62 ScreenOnOffEvent(bool on)
63 : mIsOn(on)
66 NS_IMETHOD Run() {
67 // Notify observers that the screen state has just changed.
68 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
69 if (observerService) {
70 observerService->NotifyObservers(
71 nullptr, "screen-state-changed",
72 mIsOn ? MOZ_UTF16("on") : MOZ_UTF16("off")
76 RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen();
77 const nsTArray<nsWindow*>& windows = screen->GetTopWindows();
79 for (uint32_t i = 0; i < windows.Length(); i++) {
80 nsWindow *win = windows[i];
82 if (nsIWidgetListener* listener = win->GetWidgetListener()) {
83 listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized);
87 return NS_OK;
90 private:
91 bool mIsOn;
94 static void
95 displayEnabledCallback(bool enabled)
97 RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
98 screenManager->DisplayEnabled(enabled);
101 } // namespace
103 static uint32_t
104 SurfaceFormatToColorDepth(int32_t aSurfaceFormat)
106 switch (aSurfaceFormat) {
107 case GGL_PIXEL_FORMAT_RGB_565:
108 return 16;
109 case GGL_PIXEL_FORMAT_RGBA_8888:
110 return 32;
112 return 24; // GGL_PIXEL_FORMAT_RGBX_8888
115 // nsScreenGonk.cpp
117 nsScreenGonk::nsScreenGonk(uint32_t aId,
118 GonkDisplay::DisplayType aDisplayType,
119 const GonkDisplay::NativeData& aNativeData,
120 NotifyDisplayChangedEvent aEventVisibility)
121 : mId(aId)
122 , mEventVisibility(aEventVisibility)
123 , mNativeWindow(aNativeData.mNativeWindow)
124 , mDpi(aNativeData.mXdpi)
125 , mScreenRotation(nsIScreen::ROTATION_0_DEG)
126 , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG)
127 #if ANDROID_VERSION >= 17
128 , mDisplaySurface(aNativeData.mDisplaySurface)
129 #endif
130 , mIsMirroring(false)
131 , mDisplayType(aDisplayType)
132 , mEGLDisplay(EGL_NO_DISPLAY)
133 , mEGLSurface(EGL_NO_SURFACE)
134 , mGLContext(nullptr)
135 , mFramebuffer(nullptr)
136 , mMappedBuffer(nullptr)
138 if (mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &mVirtualBounds.width) ||
139 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &mVirtualBounds.height) ||
140 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FORMAT, &mSurfaceFormat)) {
141 NS_RUNTIMEABORT("Failed to get native window size, aborting...");
144 mNaturalBounds = mVirtualBounds;
146 if (IsPrimaryScreen()) {
147 char propValue[PROPERTY_VALUE_MAX];
148 property_get("ro.sf.hwrotation", propValue, "0");
149 mPhysicalScreenRotation = atoi(propValue) / 90;
152 mColorDepth = SurfaceFormatToColorDepth(mSurfaceFormat);
155 static void
156 ReleaseGLContextSync(mozilla::gl::GLContext* aGLContext) {
157 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
158 aGLContext->Release();
161 nsScreenGonk::~nsScreenGonk()
163 // Release GLContext on compositor thread
164 if (mGLContext) {
165 CompositorThreadHolder::Loop()->PostTask(
166 NewRunnableFunction(&ReleaseGLContextSync,
167 mGLContext.forget().take()));
168 mGLContext = nullptr;
172 bool
173 nsScreenGonk::IsPrimaryScreen()
175 return mDisplayType == GonkDisplay::DISPLAY_PRIMARY;
178 NS_IMETHODIMP
179 nsScreenGonk::GetId(uint32_t *outId)
181 *outId = mId;
182 return NS_OK;
185 uint32_t
186 nsScreenGonk::GetId()
188 return mId;
191 NotifyDisplayChangedEvent
192 nsScreenGonk::GetEventVisibility()
194 return mEventVisibility;
197 NS_IMETHODIMP
198 nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop,
199 int32_t *outWidth, int32_t *outHeight)
201 *outLeft = mVirtualBounds.x;
202 *outTop = mVirtualBounds.y;
204 *outWidth = mVirtualBounds.width;
205 *outHeight = mVirtualBounds.height;
207 return NS_OK;
210 LayoutDeviceIntRect
211 nsScreenGonk::GetRect()
213 return mVirtualBounds;
216 NS_IMETHODIMP
217 nsScreenGonk::GetAvailRect(int32_t *outLeft, int32_t *outTop,
218 int32_t *outWidth, int32_t *outHeight)
220 return GetRect(outLeft, outTop, outWidth, outHeight);
223 NS_IMETHODIMP
224 nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth)
226 // XXX: this should actually return 32 when we're using 24-bit
227 // color, because we use RGBX.
228 *aPixelDepth = mColorDepth;
229 return NS_OK;
232 NS_IMETHODIMP
233 nsScreenGonk::GetColorDepth(int32_t *aColorDepth)
235 *aColorDepth = mColorDepth;
236 return NS_OK;
239 NS_IMETHODIMP
240 nsScreenGonk::GetRotation(uint32_t* aRotation)
242 *aRotation = mScreenRotation;
243 return NS_OK;
246 float
247 nsScreenGonk::GetDpi()
249 return mDpi;
252 int32_t
253 nsScreenGonk::GetSurfaceFormat()
255 return mSurfaceFormat;
258 ANativeWindow*
259 nsScreenGonk::GetNativeWindow()
261 return mNativeWindow.get();
264 NS_IMETHODIMP
265 nsScreenGonk::SetRotation(uint32_t aRotation)
267 if (!(aRotation <= ROTATION_270_DEG)) {
268 return NS_ERROR_ILLEGAL_VALUE;
271 if (mScreenRotation == aRotation) {
272 return NS_OK;
275 mScreenRotation = aRotation;
276 uint32_t rotation = EffectiveScreenRotation();
277 if (rotation == nsIScreen::ROTATION_90_DEG ||
278 rotation == nsIScreen::ROTATION_270_DEG) {
279 mVirtualBounds = LayoutDeviceIntRect(0, 0,
280 mNaturalBounds.height,
281 mNaturalBounds.width);
282 } else {
283 mVirtualBounds = mNaturalBounds;
286 nsAppShell::NotifyScreenRotation();
288 for (unsigned int i = 0; i < mTopWindows.Length(); i++) {
289 mTopWindows[i]->Resize(mVirtualBounds.width,
290 mVirtualBounds.height,
291 true);
294 return NS_OK;
297 LayoutDeviceIntRect
298 nsScreenGonk::GetNaturalBounds()
300 return mNaturalBounds;
303 uint32_t
304 nsScreenGonk::EffectiveScreenRotation()
306 return (mScreenRotation + mPhysicalScreenRotation) % (360 / 90);
309 // NB: This isn't gonk-specific, but gonk is the only widget backend
310 // that does this calculation itself, currently.
311 static ScreenOrientationInternal
312 ComputeOrientation(uint32_t aRotation, const LayoutDeviceIntSize& aScreenSize)
314 bool naturallyPortrait = (aScreenSize.height > aScreenSize.width);
315 switch (aRotation) {
316 case nsIScreen::ROTATION_0_DEG:
317 return (naturallyPortrait ? eScreenOrientation_PortraitPrimary :
318 eScreenOrientation_LandscapePrimary);
319 case nsIScreen::ROTATION_90_DEG:
320 // Arbitrarily choosing 90deg to be primary "unnatural"
321 // rotation.
322 return (naturallyPortrait ? eScreenOrientation_LandscapePrimary :
323 eScreenOrientation_PortraitPrimary);
324 case nsIScreen::ROTATION_180_DEG:
325 return (naturallyPortrait ? eScreenOrientation_PortraitSecondary :
326 eScreenOrientation_LandscapeSecondary);
327 case nsIScreen::ROTATION_270_DEG:
328 return (naturallyPortrait ? eScreenOrientation_LandscapeSecondary :
329 eScreenOrientation_PortraitSecondary);
330 default:
331 MOZ_CRASH("Gonk screen must always have a known rotation");
335 static uint16_t
336 RotationToAngle(uint32_t aRotation)
338 uint16_t angle = 90 * aRotation;
339 MOZ_ASSERT(angle == 0 || angle == 90 || angle == 180 || angle == 270);
340 return angle;
343 ScreenConfiguration
344 nsScreenGonk::GetConfiguration()
346 ScreenOrientationInternal orientation =
347 ComputeOrientation(mScreenRotation, mNaturalBounds.Size());
349 // NB: perpetuating colorDepth == pixelDepth illusion here, for
350 // consistency.
351 return ScreenConfiguration(mVirtualBounds.ToUnknownRect(), orientation,
352 RotationToAngle(mScreenRotation),
353 mColorDepth, mColorDepth);
356 void
357 nsScreenGonk::RegisterWindow(nsWindow* aWindow)
359 mTopWindows.AppendElement(aWindow);
362 void
363 nsScreenGonk::UnregisterWindow(nsWindow* aWindow)
365 mTopWindows.RemoveElement(aWindow);
368 void
369 nsScreenGonk::BringToTop(nsWindow* aWindow)
371 mTopWindows.RemoveElement(aWindow);
372 mTopWindows.InsertElementAt(0, aWindow);
375 static gralloc_module_t const*
376 gralloc_module()
378 hw_module_t const *module;
379 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) {
380 return nullptr;
382 return reinterpret_cast<gralloc_module_t const*>(module);
385 static SurfaceFormat
386 HalFormatToSurfaceFormat(int aHalFormat)
388 switch (aHalFormat) {
389 case HAL_PIXEL_FORMAT_RGBA_8888:
390 // Needs RB swap
391 return SurfaceFormat::B8G8R8A8;
392 case HAL_PIXEL_FORMAT_RGBX_8888:
393 // Needs RB swap
394 return SurfaceFormat::B8G8R8X8;
395 case HAL_PIXEL_FORMAT_BGRA_8888:
396 return SurfaceFormat::B8G8R8A8;
397 case HAL_PIXEL_FORMAT_RGB_565:
398 return SurfaceFormat::R5G6B5_UINT16;
399 default:
400 MOZ_CRASH("Unhandled HAL pixel format");
401 return SurfaceFormat::UNKNOWN; // not reached
405 static bool
406 NeedsRBSwap(int aHalFormat)
408 switch (aHalFormat) {
409 case HAL_PIXEL_FORMAT_RGBA_8888:
410 return true;
411 case HAL_PIXEL_FORMAT_RGBX_8888:
412 return true;
413 case HAL_PIXEL_FORMAT_BGRA_8888:
414 return false;
415 case HAL_PIXEL_FORMAT_RGB_565:
416 return false;
417 default:
418 MOZ_CRASH("Unhandled HAL pixel format");
419 return false; // not reached
423 already_AddRefed<DrawTarget>
424 nsScreenGonk::StartRemoteDrawing()
426 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
427 MOZ_ASSERT(!mFramebuffer);
428 MOZ_ASSERT(!mMappedBuffer);
430 mFramebuffer = DequeueBuffer();
431 int width = mFramebuffer->width, height = mFramebuffer->height;
432 if (gralloc_module()->lock(gralloc_module(), mFramebuffer->handle,
433 GRALLOC_USAGE_SW_READ_NEVER |
434 GRALLOC_USAGE_SW_WRITE_OFTEN |
435 GRALLOC_USAGE_HW_FB,
436 0, 0, width, height,
437 reinterpret_cast<void**>(&mMappedBuffer))) {
438 EndRemoteDrawing();
439 return nullptr;
441 SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat());
442 mFramebufferTarget = Factory::CreateDrawTargetForData(
443 BackendType::CAIRO,
444 mMappedBuffer,
445 IntSize(width, height),
446 mFramebuffer->stride * gfx::BytesPerPixel(format),
447 format);
448 if (!mFramebufferTarget) {
449 MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData");
451 if (!mBackBuffer ||
452 mBackBuffer->GetSize() != mFramebufferTarget->GetSize() ||
453 mBackBuffer->GetFormat() != mFramebufferTarget->GetFormat()) {
454 mBackBuffer = mFramebufferTarget->CreateSimilarDrawTarget(
455 mFramebufferTarget->GetSize(), mFramebufferTarget->GetFormat());
457 RefPtr<DrawTarget> buffer(mBackBuffer);
458 return buffer.forget();
461 void
462 nsScreenGonk::EndRemoteDrawing()
464 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
466 if (mFramebufferTarget && mFramebuffer) {
467 IntSize size = mFramebufferTarget->GetSize();
468 Rect rect(0, 0, size.width, size.height);
469 RefPtr<SourceSurface> source = mBackBuffer->Snapshot();
470 mFramebufferTarget->DrawSurface(source, rect, rect);
472 // Convert from BGR to RGB
473 // XXX this is a temporary solution. It consumes extra cpu cycles,
474 // it should not be used on product device.
475 if (NeedsRBSwap(GetSurfaceFormat())) {
476 LOGE("Very slow composition path, it should not be used on product!!!");
477 SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat());
478 gfxUtils::ConvertBGRAtoRGBA(
479 mMappedBuffer,
480 mFramebuffer->stride * mFramebuffer->height * gfx::BytesPerPixel(format));
483 if (mMappedBuffer) {
484 MOZ_ASSERT(mFramebuffer);
485 gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle);
486 mMappedBuffer = nullptr;
488 if (mFramebuffer) {
489 QueueBuffer(mFramebuffer);
491 mFramebuffer = nullptr;
492 mFramebufferTarget = nullptr;
495 ANativeWindowBuffer*
496 nsScreenGonk::DequeueBuffer()
498 ANativeWindowBuffer* buf = nullptr;
499 #if ANDROID_VERSION >= 17
500 int fenceFd = -1;
501 mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
502 android::sp<android::Fence> fence(new android::Fence(fenceFd));
503 #if ANDROID_VERSION == 17
504 fence->waitForever(1000, "nsScreenGonk_DequeueBuffer");
505 // 1000 is what Android uses. It is a warning timeout in ms.
506 // This timeout was removed in ANDROID_VERSION 18.
507 #else
508 fence->waitForever("nsScreenGonk_DequeueBuffer");
509 #endif
510 #else
511 mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
512 #endif
513 return buf;
516 bool
517 nsScreenGonk::QueueBuffer(ANativeWindowBuffer* buf)
519 #if ANDROID_VERSION >= 17
520 int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1);
521 return ret == 0;
522 #else
523 int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf);
524 return ret == 0;
525 #endif
528 nsresult
529 nsScreenGonk::MakeSnapshot(ANativeWindowBuffer* aBuffer)
531 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
532 MOZ_ASSERT(aBuffer);
534 layers::CompositorBridgeParent* compositorParent = mCompositorBridgeParent;
535 if (!compositorParent) {
536 return NS_ERROR_FAILURE;
539 int width = aBuffer->width, height = aBuffer->height;
540 uint8_t* mappedBuffer = nullptr;
541 if (gralloc_module()->lock(gralloc_module(), aBuffer->handle,
542 GRALLOC_USAGE_SW_READ_OFTEN |
543 GRALLOC_USAGE_SW_WRITE_OFTEN,
544 0, 0, width, height,
545 reinterpret_cast<void**>(&mappedBuffer))) {
546 return NS_ERROR_FAILURE;
549 SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat());
550 RefPtr<DrawTarget> mTarget =
551 Factory::CreateDrawTargetForData(
552 BackendType::CAIRO,
553 mappedBuffer,
554 IntSize(width, height),
555 aBuffer->stride * gfx::BytesPerPixel(format),
556 format);
557 if (!mTarget) {
558 return NS_ERROR_FAILURE;
561 gfx::IntRect rect = GetRect().ToUnknownRect();
562 compositorParent->ForceComposeToTarget(mTarget, &rect);
564 // Convert from BGR to RGB
565 // XXX this is a temporary solution. It consumes extra cpu cycles,
566 if (NeedsRBSwap(GetSurfaceFormat())) {
567 LOGE("Slow path of making Snapshot!!!");
568 SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat());
569 gfxUtils::ConvertBGRAtoRGBA(
570 mappedBuffer,
571 aBuffer->stride * aBuffer->height * gfx::BytesPerPixel(format));
572 mappedBuffer = nullptr;
574 gralloc_module()->unlock(gralloc_module(), aBuffer->handle);
575 return NS_OK;
578 void
579 nsScreenGonk::SetCompositorBridgeParent(layers::CompositorBridgeParent* aCompositorBridgeParent)
581 MOZ_ASSERT(NS_IsMainThread());
582 mCompositorBridgeParent = aCompositorBridgeParent;
585 #if ANDROID_VERSION >= 17
586 android::DisplaySurface*
587 nsScreenGonk::GetDisplaySurface()
589 return mDisplaySurface.get();
593 nsScreenGonk::GetPrevDispAcquireFd()
595 if (!mDisplaySurface.get()) {
596 return -1;
598 return mDisplaySurface->GetPrevDispAcquireFd();
600 #endif
602 GonkDisplay::DisplayType
603 nsScreenGonk::GetDisplayType()
605 return mDisplayType;
608 void
609 nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay,
610 hwc_surface_t aSurface,
611 gl::GLContext* aGLContext)
613 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
614 mEGLDisplay = aDisplay;
615 mEGLSurface = aSurface;
616 mGLContext = aGLContext;
619 hwc_display_t
620 nsScreenGonk::GetEGLDisplay()
622 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
623 return mEGLDisplay;
626 hwc_surface_t
627 nsScreenGonk::GetEGLSurface()
629 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
630 return mEGLSurface;
633 already_AddRefed<mozilla::gl::GLContext>
634 nsScreenGonk::GetGLContext()
636 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
637 RefPtr<mozilla::gl::GLContext>glContext = mGLContext;
638 return glContext.forget();
641 static void
642 UpdateMirroringWidgetSync(nsMainThreadPtrHandle<nsScreenGonk>&& aScreen, nsWindow* aWindow)
644 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
645 already_AddRefed<nsWindow> window(aWindow);
646 aScreen->UpdateMirroringWidget(window);
649 bool
650 nsScreenGonk::EnableMirroring()
652 MOZ_ASSERT(NS_IsMainThread());
653 MOZ_ASSERT(!IsPrimaryScreen());
655 RefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen();
656 NS_ENSURE_TRUE(primaryScreen, false);
658 bool ret = primaryScreen->SetMirroringScreen(this);
659 NS_ENSURE_TRUE(ret, false);
661 // Create a widget for mirroring
662 nsWidgetInitData initData;
663 initData.mScreenId = mId;
664 RefPtr<nsWindow> window = new nsWindow();
665 window->Create(nullptr, nullptr, mNaturalBounds, &initData);
666 MOZ_ASSERT(static_cast<nsWindow*>(window)->GetScreen() == this);
668 // Update mMirroringWidget on compositor thread
669 nsMainThreadPtrHandle<nsScreenGonk> primary =
670 nsMainThreadPtrHandle<nsScreenGonk>(new nsMainThreadPtrHolder<nsScreenGonk>(primaryScreen, false));
671 CompositorThreadHolder::Loop()->PostTask(
672 NewRunnableFunction(&UpdateMirroringWidgetSync,
673 primary,
674 window.forget().take()));
676 mIsMirroring = true;
677 return true;
680 bool
681 nsScreenGonk::DisableMirroring()
683 MOZ_ASSERT(NS_IsMainThread());
684 MOZ_ASSERT(!IsPrimaryScreen());
686 mIsMirroring = false;
687 RefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen();
688 NS_ENSURE_TRUE(primaryScreen, false);
690 bool ret = primaryScreen->ClearMirroringScreen(this);
691 NS_ENSURE_TRUE(ret, false);
693 // Update mMirroringWidget on compositor thread
694 nsMainThreadPtrHandle<nsScreenGonk> primary =
695 nsMainThreadPtrHandle<nsScreenGonk>(new nsMainThreadPtrHolder<nsScreenGonk>(primaryScreen, false));
696 CompositorThreadHolder::Loop()->PostTask(
697 NewRunnableFunction(&UpdateMirroringWidgetSync,
698 primary,
699 nullptr));
700 return true;
703 bool
704 nsScreenGonk::SetMirroringScreen(nsScreenGonk* aScreen)
706 MOZ_ASSERT(NS_IsMainThread());
707 MOZ_ASSERT(IsPrimaryScreen());
709 if (mMirroringScreen) {
710 return false;
712 mMirroringScreen = aScreen;
713 return true;
716 bool
717 nsScreenGonk::ClearMirroringScreen(nsScreenGonk* aScreen)
719 MOZ_ASSERT(NS_IsMainThread());
720 MOZ_ASSERT(IsPrimaryScreen());
722 if (mMirroringScreen != aScreen) {
723 return false;
725 mMirroringScreen = nullptr;
726 return true;
729 void
730 nsScreenGonk::UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow)
732 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
733 MOZ_ASSERT(IsPrimaryScreen());
735 if (mMirroringWidget) {
736 nsCOMPtr<nsIWidget> widget = mMirroringWidget.forget();
737 NS_ReleaseOnMainThread(widget.forget());
739 mMirroringWidget = aWindow;
742 nsWindow*
743 nsScreenGonk::GetMirroringWidget()
745 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
746 MOZ_ASSERT(IsPrimaryScreen());
748 return mMirroringWidget;
751 NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager)
753 nsScreenManagerGonk::nsScreenManagerGonk()
754 : mInitialized(false)
755 #if ANDROID_VERSION >= 19
756 , mDisplayEnabled(false)
757 #endif
761 nsScreenManagerGonk::~nsScreenManagerGonk()
765 static StaticRefPtr<nsScreenManagerGonk> sScreenManagerGonk;
767 /* static */ already_AddRefed<nsScreenManagerGonk>
768 nsScreenManagerGonk::GetInstance()
770 MOZ_ASSERT(NS_IsMainThread());
772 // Avoid creating nsScreenManagerGonk from content process.
773 if (!XRE_IsParentProcess()) {
774 MOZ_CRASH("Non-chrome processes should not get here.");
777 // Avoid creating multiple nsScreenManagerGonk instance inside main process.
778 if (!sScreenManagerGonk) {
779 sScreenManagerGonk = new nsScreenManagerGonk();
780 ClearOnShutdown(&sScreenManagerGonk);
783 RefPtr<nsScreenManagerGonk> screenMgr = sScreenManagerGonk.get();
784 return screenMgr.forget();
787 /* static */ already_AddRefed< nsScreenGonk>
788 nsScreenManagerGonk::GetPrimaryScreen()
790 MOZ_ASSERT(NS_IsMainThread());
792 RefPtr<nsScreenManagerGonk> manager = nsScreenManagerGonk::GetInstance();
793 nsCOMPtr<nsIScreen> screen;
794 manager->GetPrimaryScreen(getter_AddRefs(screen));
795 MOZ_ASSERT(screen);
796 return already_AddRefed<nsScreenGonk>(
797 static_cast<nsScreenGonk*>(screen.forget().take()));
800 void
801 nsScreenManagerGonk::Initialize()
803 if (mInitialized) {
804 return;
807 mScreenOnEvent = new ScreenOnOffEvent(true);
808 mScreenOffEvent = new ScreenOnOffEvent(false);
809 GetGonkDisplay()->OnEnabled(displayEnabledCallback);
811 AddScreen(GonkDisplay::DISPLAY_PRIMARY);
813 nsAppShell::NotifyScreenInitialized();
814 mInitialized = true;
817 void
818 nsScreenManagerGonk::DisplayEnabled(bool aEnabled)
820 MOZ_ASSERT(NS_IsMainThread());
822 #if ANDROID_VERSION >= 19
823 /* Bug 1244044
824 * This function could be called before |mCompositorVsyncScheduler| is set.
825 * To avoid this issue, keep the value stored in |mDisplayEnabled|.
827 mDisplayEnabled = aEnabled;
828 if (mCompositorVsyncScheduler) {
829 mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled);
831 #endif
833 VsyncControl(aEnabled);
834 NS_DispatchToMainThread(aEnabled ? mScreenOnEvent : mScreenOffEvent);
837 NS_IMETHODIMP
838 nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen)
840 NS_IF_ADDREF(*outScreen = mScreens[0].get());
841 return NS_OK;
844 NS_IMETHODIMP
845 nsScreenManagerGonk::ScreenForId(uint32_t aId,
846 nsIScreen **outScreen)
848 for (size_t i = 0; i < mScreens.Length(); i++) {
849 if (mScreens[i]->GetId() == aId) {
850 NS_IF_ADDREF(*outScreen = mScreens[i].get());
851 return NS_OK;
855 *outScreen = nullptr;
856 return NS_OK;
859 NS_IMETHODIMP
860 nsScreenManagerGonk::ScreenForRect(int32_t inLeft,
861 int32_t inTop,
862 int32_t inWidth,
863 int32_t inHeight,
864 nsIScreen **outScreen)
866 // Since all screens have independent coordinate system, we could
867 // only return the primary screen no matter what rect is given.
868 return GetPrimaryScreen(outScreen);
871 NS_IMETHODIMP
872 nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen)
874 for (size_t i = 0; i < mScreens.Length(); i++) {
875 if (aWidget == mScreens[i]->GetNativeWindow()) {
876 NS_IF_ADDREF(*outScreen = mScreens[i].get());
877 return NS_OK;
881 *outScreen = nullptr;
882 return NS_OK;
885 NS_IMETHODIMP
886 nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens)
888 *aNumberOfScreens = mScreens.Length();
889 return NS_OK;
892 NS_IMETHODIMP
893 nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale)
895 *aDefaultScale = 1.0f;
896 return NS_OK;
899 void
900 nsScreenManagerGonk::VsyncControl(bool aEnabled)
902 if (!NS_IsMainThread()) {
903 NS_DispatchToMainThread(
904 NS_NewRunnableMethodWithArgs<bool>(this,
905 &nsScreenManagerGonk::VsyncControl,
906 aEnabled));
907 return;
910 MOZ_ASSERT(NS_IsMainThread());
911 VsyncSource::Display &display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay();
912 if (aEnabled) {
913 display.EnableVsync();
914 } else {
915 display.DisableVsync();
919 uint32_t
920 nsScreenManagerGonk::GetIdFromType(GonkDisplay::DisplayType aDisplayType)
922 // This is the only place where we make the assumption that
923 // display type is equivalent to screen id.
925 // Bug 1138287 will address the conversion from type to id.
926 return aDisplayType;
929 bool
930 nsScreenManagerGonk::IsScreenConnected(uint32_t aId)
932 for (size_t i = 0; i < mScreens.Length(); ++i) {
933 if (mScreens[i]->GetId() == aId) {
934 return true;
938 return false;
941 namespace {
943 // A concrete class as a subject for 'display-changed' observer event.
944 class DisplayInfo : public nsIDisplayInfo {
945 public:
946 NS_DECL_ISUPPORTS
948 DisplayInfo(uint32_t aId, bool aConnected)
949 : mId(aId)
950 , mConnected(aConnected)
954 NS_IMETHODIMP GetId(int32_t *aId)
956 *aId = mId;
957 return NS_OK;
960 NS_IMETHODIMP GetConnected(bool *aConnected)
962 *aConnected = mConnected;
963 return NS_OK;
966 private:
967 virtual ~DisplayInfo() {}
969 uint32_t mId;
970 bool mConnected;
973 NS_IMPL_ISUPPORTS(DisplayInfo, nsIDisplayInfo, nsISupports)
975 class NotifyTask : public mozilla::Runnable {
976 public:
977 NotifyTask(uint32_t aId, bool aConnected)
978 : mDisplayInfo(new DisplayInfo(aId, aConnected))
982 NS_IMETHOD Run()
984 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
985 if (os) {
986 os->NotifyObservers(mDisplayInfo, "display-changed", nullptr);
989 return NS_OK;
991 private:
992 RefPtr<DisplayInfo> mDisplayInfo;
995 void
996 NotifyDisplayChange(uint32_t aId, bool aConnected)
998 NS_DispatchToMainThread(new NotifyTask(aId, aConnected));
1001 } // end of unnamed namespace.
1003 nsresult
1004 nsScreenManagerGonk::AddScreen(GonkDisplay::DisplayType aDisplayType,
1005 android::IGraphicBufferProducer* aSink,
1006 NotifyDisplayChangedEvent aEventVisibility)
1008 MOZ_ASSERT(NS_IsMainThread());
1010 NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES,
1011 NS_ERROR_FAILURE);
1013 uint32_t id = GetIdFromType(aDisplayType);
1014 NS_ENSURE_TRUE(!IsScreenConnected(id), NS_ERROR_FAILURE);
1016 GonkDisplay::NativeData nativeData =
1017 GetGonkDisplay()->GetNativeData(aDisplayType, aSink);
1018 nsScreenGonk* screen = new nsScreenGonk(id,
1019 aDisplayType,
1020 nativeData,
1021 aEventVisibility);
1022 mScreens.AppendElement(screen);
1024 if (aEventVisibility == NotifyDisplayChangedEvent::Observable) {
1025 NotifyDisplayChange(id, true);
1028 // By default, non primary screen does mirroring.
1029 if (aDisplayType != GonkDisplay::DISPLAY_PRIMARY &&
1030 gfxPrefs::ScreenMirroringEnabled()) {
1031 screen->EnableMirroring();
1034 return NS_OK;
1037 nsresult
1038 nsScreenManagerGonk::RemoveScreen(GonkDisplay::DisplayType aDisplayType)
1040 MOZ_ASSERT(NS_IsMainThread());
1042 NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES,
1043 NS_ERROR_FAILURE);
1045 NotifyDisplayChangedEvent eventVisibility = NotifyDisplayChangedEvent::Observable;
1046 uint32_t screenId = GetIdFromType(aDisplayType);
1047 NS_ENSURE_TRUE(IsScreenConnected(screenId), NS_ERROR_FAILURE);
1049 for (size_t i = 0; i < mScreens.Length(); i++) {
1050 if (mScreens[i]->GetId() == screenId) {
1051 if (mScreens[i]->IsMirroring()) {
1052 mScreens[i]->DisableMirroring();
1054 eventVisibility = mScreens[i]->GetEventVisibility();
1055 mScreens.RemoveElementAt(i);
1056 break;
1060 if (eventVisibility == NotifyDisplayChangedEvent::Observable) {
1061 NotifyDisplayChange(screenId, false);
1063 return NS_OK;
1066 #if ANDROID_VERSION >= 19
1067 void
1068 nsScreenManagerGonk::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver)
1070 MOZ_ASSERT(NS_IsMainThread());
1072 // We assume on b2g that there is only 1 CompositorBridgeParent
1073 MOZ_ASSERT(mCompositorVsyncScheduler == nullptr);
1074 MOZ_ASSERT(aObserver);
1075 mCompositorVsyncScheduler = aObserver;
1076 mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled);
1078 #endif