author | Sotaro Ikeda <sikeda@mozilla.com> |
Sat, 08 Aug 2015 13:50:47 -0700 | |
changeset 256973 | 203271f48e46a124b92bc0fcba57d5f0c9c4888b |
parent 256972 | ae85c14a2bae38e65b9cfa04b7844574d9a31f86 |
child 256974 | d10584967bb9d020aeecaa212241003d4144e959 |
push id | 29197 |
push user | philringnalda@gmail.com |
push date | Sun, 09 Aug 2015 20:35:19 +0000 |
treeherder | mozilla-central@fd69d51a4068 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mwu, mattwoodrow |
bugs | 1186000 |
milestone | 42.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
|
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -991,16 +991,19 @@ pref("gfx.canvas.azure.accelerated", tru pref("gfx.canvas.skiagl.dynamic-cache", true); // Limit skia to canvases the size of the device screen or smaller pref("gfx.canvas.max-size-for-skia-gl", -1); // enable fence with readpixels for SurfaceStream pref("gfx.gralloc.fence-with-readpixels", true); +// enable screen mirroring to external display +pref("gfx.screen-mirroring.enabled", true); + // The url of the page used to display network error details. pref("b2g.neterror.url", "net_error.html"); // The origin used for the shared themes uri space. pref("b2g.theme.origin", "app://theme.gaiamobile.org"); pref("dom.mozApps.themable", true); pref("dom.mozApps.selected_theme", "default_theme.gaiamobile.org");
--- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -50,21 +50,27 @@ #include "nsISupportsImpl.h" // for Layer::AddRef, etc #include "nsIWidget.h" // for nsIWidget #include "nsPoint.h" // for nsIntPoint #include "nsRect.h" // for mozilla::gfx::IntRect #include "nsRegion.h" // for nsIntRegion, etc #ifdef MOZ_WIDGET_ANDROID #include <android/log.h> #include "AndroidBridge.h" +#endif +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) #include "opengl/CompositorOGL.h" #include "GLContextEGL.h" #include "GLContextProvider.h" #include "ScopedGLHelpers.h" #endif +#ifdef MOZ_WIDGET_GONK +#include "nsScreenManagerGonk.h" +#include "nsWindow.h" +#endif #include "GeckoProfiler.h" #include "TextRenderer.h" // for TextRenderer class gfxContext; namespace mozilla { namespace layers { @@ -297,17 +303,17 @@ LayerManagerComposite::EndTransaction(co // The results of our drawing always go directly into a pixel buffer, // so we don't need to pass any global transform here. mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); nsIntRegion opaque; ApplyOcclusionCulling(mRoot, opaque); Render(); -#ifdef MOZ_WIDGET_ANDROID +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) RenderToPresentationSurface(); #endif mGeometryChanged = false; } else { // Modified layer tree mGeometryChanged = true; } @@ -775,17 +781,17 @@ LayerManagerComposite::Render() composer2D->Render(mCompositor->GetWidget()); } mCompositor->GetWidget()->PostRender(this); RecordFrame(); } -#ifdef MOZ_WIDGET_ANDROID +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) class ScopedCompositorProjMatrix { public: ScopedCompositorProjMatrix(CompositorOGL* aCompositor, const Matrix4x4& aProjMatrix): mCompositor(aCompositor), mOriginalProjMatrix(mCompositor->GetProjMatrix()) { mCompositor->SetProjMatrix(aProjMatrix); } @@ -849,16 +855,17 @@ public: } private: GLContextEGL* const mContext; }; void LayerManagerComposite::RenderToPresentationSurface() { +#ifdef MOZ_WIDGET_ANDROID if (!AndroidBridge::Bridge()) { return; } void* window = AndroidBridge::Bridge()->GetPresentationWindow(); if (!window) { return; @@ -881,76 +888,124 @@ LayerManagerComposite::RenderToPresentat GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window); +#elif defined(MOZ_WIDGET_GONK) + CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); + nsScreenGonk* screen = static_cast<nsWindow*>(mCompositor->GetWidget())->GetScreen(); + if (!screen->IsPrimaryScreen()) { + // Only primary screen support mirroring + return; + } + + nsWindow* mirrorScreenWidget = screen->GetMirroringWidget(); + if (!mirrorScreenWidget) { + // No mirroring + return; + } + + nsScreenGonk* mirrorScreen = mirrorScreenWidget->GetScreen(); + if (!mirrorScreen->GetTopWindows().IsEmpty()) { + return; + } + + EGLSurface surface = mirrorScreen->GetEGLSurface(); + if (surface == LOCAL_EGL_NO_SURFACE) { + // Create GLContext + nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateForWindow(mirrorScreenWidget); + mirrorScreenWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT, + reinterpret_cast<uintptr_t>(gl.get())); + surface = mirrorScreen->GetEGLSurface(); + if (surface == LOCAL_EGL_NO_SURFACE) { + // Failed to create EGLSurface + return; + } + } + GLContext* gl = compositor->gl(); + GLContextEGL* egl = GLContextEGL::Cast(gl); + const IntSize windowSize = mirrorScreen->GetNaturalBounds().Size(); +#endif + if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } + ScreenRotation rotation = compositor->GetScreenRotation(); + const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); + const nsIntRect originalRect = nsIntRect(0, 0, originalSize.width, originalSize.height); - const int pageWidth = originalSize.width; - const int pageHeight = originalSize.height; + int pageWidth = originalSize.width; + int pageHeight = originalSize.height; + if (rotation == ROTATION_90 || rotation == ROTATION_270) { + pageWidth = originalSize.height; + pageHeight = originalSize.width; + } float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); - ScopedCompositorRenderOffset overrideRenderOffset(compositor, offset); ScopedContextSurfaceOverride overrideSurface(egl, surface); + Matrix viewMatrix = ComputeTransformForRotation(originalRect, + rotation); + viewMatrix.Invert(); // unrotate + viewMatrix.PostScale(scale, scale); + viewMatrix.PostTranslate(offset.x, offset.y); + Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix); + + mRoot->ComputeEffectiveTransforms(matrix); + nsIntRegion opaque; + ApplyOcclusionCulling(mRoot, opaque); + nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); Rect rect, actualBounds; mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); - // Override the projection matrix since the presentation frame buffer - // is probably not the same size as the device frame buffer. The override - // projection matrix also scales the content to fit into the presentation - // frame buffer. - Matrix viewMatrix; - viewMatrix.PreTranslate(-1.0, 1.0); - viewMatrix.PreScale((2.0f * scale) / (float)actualWidth, (2.0f * scale) / (float)actualHeight); - viewMatrix.PreScale(1.0f, -1.0f); - viewMatrix.PreTranslate((int)((float)offset.x / scale), offset.y); - - Matrix4x4 projMatrix = Matrix4x4::From2D(viewMatrix); - - ScopedCompositorProjMatrix overrideProjMatrix(compositor, projMatrix); - // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. - ScopedScissorRect screen(egl, 0, 0, actualWidth, actualHeight); + ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); - const IntRect clipRect = IntRect(0, 0, (int)(scale * pageWidth), actualHeight); + const IntRect clipRect = IntRect(0, 0, actualWidth, actualHeight); + RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); - mCompositor->SetDispAcquireFence(mRoot); + mCompositor->SetDispAcquireFence(mRoot); // Call after EndFrame() + +#ifdef MOZ_WIDGET_GONK + nsRefPtr<Composer2D> composer2D; + composer2D = mCompositor->GetWidget()->GetComposer2D(); + if (composer2D) { + composer2D->Render(mirrorScreenWidget); + } +#endif } #endif static void SubtractTransformedRegion(nsIntRegion& aRegion, const nsIntRegion& aRegionToSubtract, const Matrix4x4& aTransform) {
--- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -296,17 +296,17 @@ private: nsIntRegion& aScreenRegion, nsIntRegion& aLowPrecisionScreenRegion, const gfx::Matrix4x4& aTransform); /** * Render the current layer tree to the active target. */ void Render(); -#ifdef MOZ_WIDGET_ANDROID +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) void RenderToPresentationSurface(); #endif /** * Render debug overlays such as the FPS/FrameCounter above the frame. */ void RenderDebugOverlay(const gfx::Rect& aBounds);
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -258,16 +258,17 @@ private: DECL_GFX_PREF(Once, "gfx.vsync.compositor", VsyncAlignedCompositor, bool, false); // On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread // processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10. DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10); // Use vsync events generated by hardware DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled", HardwareVsyncEnabled, bool, false); DECL_GFX_PREF(Once, "gfx.vsync.refreshdriver", VsyncAlignedRefreshDriver, bool, false); DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true); + DECL_GFX_PREF(Once, "gfx.screen-mirroring.enabled", ScreenMirroringEnabled, bool, false); DECL_GFX_PREF(Live, "gl.msaa-level", MSAALevel, uint32_t, 2); DECL_GFX_PREF(Live, "gl.require-hardware", RequireHardwareGL, bool, false); DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024); DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500); DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false); DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true);
--- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -746,16 +746,19 @@ HwcComposer2D::Render(nsIWidget* aWidget return false; } if (mPrepared) { // No mHwc prepare, if already prepared in current draw cycle mList->hwLayers[mList->numHwLayers - 1].handle = dispSurface->lastHandle; mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); } else { + // Update screen rect to handle a case that TryRenderWithHwc() is not called. + mScreenRect = screen->GetNaturalBounds(); + mList->flags = HWC_GEOMETRY_CHANGED; mList->numHwLayers = 2; mList->hwLayers[0].hints = 0; mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; mList->hwLayers[0].flags = HWC_SKIP_LAYER; mList->hwLayers[0].backgroundColor = {0}; mList->hwLayers[0].acquireFenceFd = -1; mList->hwLayers[0].releaseFenceFd = -1; @@ -768,17 +771,18 @@ HwcComposer2D::Render(nsIWidget* aWidget } void HwcComposer2D::Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen) { if (mPrepared) { LOGE("Multiple hwc prepare calls!"); } - mHal->Prepare(mList, screen->GetDisplayType(), dispHandle, fence); + hwc_rect_t dispRect = {0, 0, mScreenRect.width, mScreenRect.height}; + mHal->Prepare(mList, screen->GetDisplayType(), dispRect, dispHandle, fence); mPrepared = true; } bool HwcComposer2D::Commit(nsScreenGonk* aScreen) { for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { mList->hwLayers[j].acquireFenceFd = -1;
--- a/widget/gonk/hwchal/HwcHAL.cpp +++ b/widget/gonk/hwchal/HwcHAL.cpp @@ -27,18 +27,16 @@ HwcHAL::HwcHAL() { // Some HALs don't want to open hwc twice. // If GetDisplay already load hwc module, we don't need to load again mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice(); if (!mHwc) { printf_stderr("HwcHAL Error: Cannot load hwcomposer"); return; } - - GetHwcAttributes(); } HwcHAL::~HwcHAL() { mHwc = nullptr; } bool @@ -74,16 +72,17 @@ int HwcHAL::ResetHwc() { return Set(nullptr, HWC_DISPLAY_PRIMARY); } int HwcHAL::Prepare(HwcList *aList, uint32_t aDisp, + hwc_rect_t aDispRect, buffer_handle_t aHandle, int aFenceFd) { MOZ_ASSERT(mHwc); if (!mHwc) { printf_stderr("HwcHAL Error: HwcDevice doesn't exist. A fence might be leaked."); return -1; } @@ -98,18 +97,18 @@ HwcHAL::Prepare(HwcList *aList, const auto idx = aList->numHwLayers - 1; aList->hwLayers[idx].hints = 0; aList->hwLayers[idx].flags = 0; aList->hwLayers[idx].transform = 0; aList->hwLayers[idx].handle = aHandle; aList->hwLayers[idx].blending = HWC_BLENDING_PREMULT; aList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET; - SetCrop(aList->hwLayers[idx], mHwcRect); - aList->hwLayers[idx].displayFrame = mHwcRect; + SetCrop(aList->hwLayers[idx], aDispRect); + aList->hwLayers[idx].displayFrame = aDispRect; aList->hwLayers[idx].visibleRegionScreen.numRects = 1; aList->hwLayers[idx].visibleRegionScreen.rects = &aList->hwLayers[idx].displayFrame; aList->hwLayers[idx].acquireFenceFd = aFenceFd; aList->hwLayers[idx].releaseFenceFd = -1; #if ANDROID_VERSION >= 18 aList->hwLayers[idx].planeAlpha = 0xFF; #endif return mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); @@ -190,30 +189,16 @@ HwcHAL::RegisterHwcEventCallback(const H // with JellyBean. #if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) return true; #else return false; #endif } -void -HwcHAL::GetHwcAttributes() -{ - int32_t values[2]; - const uint32_t attrs[] = { - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_NO_ATTRIBUTE - }; - - mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values); - mHwcRect = {0, 0, values[0], values[1]}; -} - uint32_t HwcHAL::GetAPIVersion() const { if (!mHwc) { // default value: HWC_MODULE_API_VERSION_0_1 return 1; } return mHwc->common.version;
--- a/widget/gonk/hwchal/HwcHAL.h +++ b/widget/gonk/hwchal/HwcHAL.h @@ -26,49 +26,45 @@ namespace mozilla { class HwcHAL final : public HwcHALBase { public: explicit HwcHAL(); virtual ~HwcHAL(); virtual bool HasHwc() const override { return static_cast<bool>(mHwc); } - virtual const hwc_rect_t GetHwcRect() const override { return mHwcRect; } - virtual void SetEGLInfo(hwc_display_t aDpy, hwc_surface_t aSur) override { } virtual bool Query(QueryType aType) override; virtual int Set(HwcList *aList, uint32_t aDisp) override; virtual int ResetHwc() override; virtual int Prepare(HwcList *aList, uint32_t aDisp, + hwc_rect_t aDispRect, buffer_handle_t aHandle, int aFenceFd) override; virtual bool SupportTransparency() const override; virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const override; virtual void SetCrop(HwcLayer &aLayer, const hwc_rect_t &aSrcCrop) const override; virtual bool EnableVsync(bool aEnable) override; virtual bool RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) override; private: - void GetHwcAttributes(); - uint32_t GetAPIVersion() const; private: HwcDevice *mHwc = nullptr; - hwc_rect_t mHwcRect = {0}; }; } // namespace mozilla #endif // mozilla_HwcHAL
--- a/widget/gonk/hwchal/HwcHALBase.h +++ b/widget/gonk/hwchal/HwcHALBase.h @@ -80,19 +80,16 @@ public: // Create HwcHAL module, Only HwcComposer2D calls this. // If other modules want to use HwcHAL, please use APIs in // HwcComposer2D static UniquePtr<HwcHALBase> CreateHwcHAL(); // Check if mHwc exists virtual bool HasHwc() const = 0; - // Get HwcRect - virtual const hwc_rect_t GetHwcRect() const = 0; - // Set EGL info (only ICS need this info) virtual void SetEGLInfo(hwc_display_t aEGLDisplay, hwc_surface_t aEGLSurface) = 0; // HwcDevice query properties virtual bool Query(QueryType aType) = 0; // HwcDevice set @@ -100,16 +97,17 @@ public: uint32_t aDisp) = 0; // Reset HwcDevice virtual int ResetHwc() = 0; // HwcDevice prepare virtual int Prepare(HwcList *aList, uint32_t aDisp, + hwc_rect_t aDispRect, buffer_handle_t aHandle, int aFenceFd) = 0; // Check transparency support virtual bool SupportTransparency() const = 0; // Get a geometry change flag virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const = 0;
--- a/widget/gonk/hwchal/HwcICS.cpp +++ b/widget/gonk/hwchal/HwcICS.cpp @@ -81,16 +81,17 @@ int HwcICS::ResetHwc() { return -1; } int HwcICS::Prepare(HwcList *aList, uint32_t aDisp, + hwc_rect_t aDispRect, buffer_handle_t aHandle, int aFenceFd) { return mHwc->prepare(mHwc, aList); } bool HwcICS::SupportTransparency() const
--- a/widget/gonk/hwchal/HwcICS.h +++ b/widget/gonk/hwchal/HwcICS.h @@ -26,30 +26,29 @@ namespace mozilla { class HwcICS final : public HwcHALBase { public: explicit HwcICS(); virtual ~HwcICS(); virtual bool HasHwc() const override { return static_cast<bool>(mHwc); } - virtual const hwc_rect_t GetHwcRect() const override { return {0}; } - virtual void SetEGLInfo(hwc_display_t aEGLDisplay, hwc_surface_t aEGLSurface) override; virtual bool Query(QueryType aType) override; virtual int Set(HwcList *aList, uint32_t aDisp) override; virtual int ResetHwc() override; virtual int Prepare(HwcList *aList, uint32_t aDisp, + hwc_rect_t aDispRect, buffer_handle_t aHandle, int aFenceFd) override; virtual bool SupportTransparency() const override; virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const override; virtual void SetCrop(HwcLayer &aLayer,
--- a/widget/gonk/nsScreenManagerGonk.cpp +++ b/widget/gonk/nsScreenManagerGonk.cpp @@ -116,16 +116,17 @@ nsScreenGonk::nsScreenGonk(uint32_t aId, : mId(aId) , mNativeWindow(aNativeData.mNativeWindow) , mDpi(aNativeData.mXdpi) , mScreenRotation(nsIScreen::ROTATION_0_DEG) , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG) #if ANDROID_VERSION >= 17 , mDisplaySurface(aNativeData.mDisplaySurface) #endif + , mIsMirroring(false) , mDisplayType(aDisplayType) , mEGLDisplay(EGL_NO_DISPLAY) , mEGLSurface(EGL_NO_SURFACE) , mGLContext(nullptr) { if (mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &mVirtualBounds.width) || mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &mVirtualBounds.height) || mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FORMAT, &mSurfaceFormat)) { @@ -138,18 +139,32 @@ nsScreenGonk::nsScreenGonk(uint32_t aId, char propValue[PROPERTY_VALUE_MAX]; property_get("ro.sf.hwrotation", propValue, "0"); mPhysicalScreenRotation = atoi(propValue) / 90; } mColorDepth = SurfaceFormatToColorDepth(mSurfaceFormat); } +static void +ReleaseGLContextSync(mozilla::gl::GLContext* aGLContext) { + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); + aGLContext->Release(); +} + nsScreenGonk::~nsScreenGonk() { + // Release GLContext on compositor thread + if (mGLContext) { + CompositorParent::CompositorLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(&ReleaseGLContextSync, + mGLContext.forget().take())); + mGLContext = nullptr; + } } bool nsScreenGonk::IsPrimaryScreen() { return mDisplayType == GonkDisplay::DISPLAY_PRIMARY; } @@ -354,17 +369,18 @@ nsScreenGonk::GetPrevDispAcquireFd() GonkDisplay::DisplayType nsScreenGonk::GetDisplayType() { return mDisplayType; } void -nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, +nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay, + hwc_surface_t aSurface, gl::GLContext* aGLContext) { MOZ_ASSERT(CompositorParent::IsInCompositorThread()); mEGLDisplay = aDisplay; mEGLSurface = aSurface; mGLContext = aGLContext; } @@ -373,18 +389,124 @@ nsScreenGonk::GetEGLDisplay() { MOZ_ASSERT(CompositorParent::IsInCompositorThread()); return mEGLDisplay; } hwc_surface_t nsScreenGonk::GetEGLSurface() { + return mEGLSurface; +} + +static void +UpdateMirroringWidgetSync(nsScreenGonk* aScreen, nsWindow* aWindow) { MOZ_ASSERT(CompositorParent::IsInCompositorThread()); - return mEGLSurface; + already_AddRefed<nsWindow> window(aWindow); + aScreen->UpdateMirroringWidget(window); +} + +bool +nsScreenGonk::EnableMirroring() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!IsPrimaryScreen()); + + nsRefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); + NS_ENSURE_TRUE(primaryScreen, false); + + bool ret = primaryScreen->SetMirroringScreen(this); + NS_ENSURE_TRUE(ret, false); + + // Create a widget for mirroring + nsWidgetInitData initData; + initData.mScreenId = mId; + nsRefPtr<nsWindow> window = new nsWindow(); + window->Create(nullptr, nullptr, mNaturalBounds, &initData); + MOZ_ASSERT(static_cast<nsWindow*>(window)->GetScreen() == this); + + // Update mMirroringWidget on compositor thread + CompositorParent::CompositorLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(&UpdateMirroringWidgetSync, + primaryScreen, + window.forget().take())); + + mIsMirroring = true; + return true; +} + +bool +nsScreenGonk::DisableMirroring() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!IsPrimaryScreen()); + + mIsMirroring = false; + nsRefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); + NS_ENSURE_TRUE(primaryScreen, false); + + bool ret = primaryScreen->ClearMirroringScreen(this); + NS_ENSURE_TRUE(ret, false); + + // Update mMirroringWidget on compositor thread + CompositorParent::CompositorLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(&UpdateMirroringWidgetSync, + primaryScreen, + nullptr)); + return true; +} + +bool +nsScreenGonk::SetMirroringScreen(nsScreenGonk* aScreen) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsPrimaryScreen()); + + if (mMirroringScreen) { + return false; + } + mMirroringScreen = mMirroringScreen; + return true; +} + +bool +nsScreenGonk::ClearMirroringScreen(nsScreenGonk* aScreen) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsPrimaryScreen()); + + if (mMirroringScreen != aScreen) { + return false; + } + mMirroringScreen = nullptr; + return true; +} + +void +nsScreenGonk::UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow) +{ + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); + MOZ_ASSERT(IsPrimaryScreen()); + + if (mMirroringWidget) { + nsCOMPtr<nsIWidget> widget = mMirroringWidget.forget(); + NS_ReleaseOnMainThread(widget); + } + mMirroringWidget = aWindow; +} + +nsWindow* +nsScreenGonk::GetMirroringWidget() +{ + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); + MOZ_ASSERT(IsPrimaryScreen()); + + return mMirroringWidget; } NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager) nsScreenManagerGonk::nsScreenManagerGonk() : mInitialized(false) { } @@ -606,50 +728,59 @@ NotifyDisplayChange(uint32_t aId, bool a { NS_DispatchToMainThread(new NotifyTask(aId, aConnected)); } } // end of unnamed namespace. nsresult nsScreenManagerGonk::AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aProducer) + android::IGraphicBufferProducer* aSink) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, NS_ERROR_FAILURE); uint32_t id = GetIdFromType(aDisplayType); NS_ENSURE_TRUE(!IsScreenConnected(id), NS_ERROR_FAILURE); GonkDisplay::NativeData nativeData = - GetGonkDisplay()->GetNativeData(aDisplayType, aProducer); + GetGonkDisplay()->GetNativeData(aDisplayType, aSink); nsScreenGonk* screen = new nsScreenGonk(id, aDisplayType, nativeData); mScreens.AppendElement(screen); NotifyDisplayChange(id, true); + // By default, non primary screen does mirroring. + if (aDisplayType != GonkDisplay::DISPLAY_PRIMARY && + gfxPrefs::ScreenMirroringEnabled()) { + screen->EnableMirroring(); + } + return NS_OK; } nsresult nsScreenManagerGonk::RemoveScreen(GonkDisplay::DisplayType aDisplayType) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, NS_ERROR_FAILURE); uint32_t screenId = GetIdFromType(aDisplayType); NS_ENSURE_TRUE(IsScreenConnected(screenId), NS_ERROR_FAILURE); for (size_t i = 0; i < mScreens.Length(); i++) { if (mScreens[i]->GetId() == screenId) { + if (mScreens[i]->IsMirroring()) { + mScreens[i]->DisableMirroring(); + } mScreens.RemoveElementAt(i); break; } } NotifyDisplayChange(screenId, false); return NS_OK;
--- a/widget/gonk/nsScreenManagerGonk.h +++ b/widget/gonk/nsScreenManagerGonk.h @@ -12,24 +12,26 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef nsScreenManagerGonk_h___ #define nsScreenManagerGonk_h___ -#include "mozilla/Hal.h" - #include "cutils/properties.h" #include "hardware/hwcomposer.h" + #include "libdisplay/GonkDisplay.h" +#include "mozilla/Hal.h" +#include "mozilla/Mutex.h" #include "nsBaseScreen.h" #include "nsCOMPtr.h" #include "nsIScreenManager.h" +#include "nsProxyRelease.h" #include <android/native_window.h> class nsRunnable; class nsWindow; namespace android { class DisplaySurface; @@ -82,42 +84,59 @@ public: void UnregisterWindow(nsWindow* aWindow); void BringToTop(nsWindow* aWindow); const nsTArray<nsWindow*>& GetTopWindows() const { return mTopWindows; } - // Set EGL info of primary display. Used for BLIT Composition. + // Non-primary screen only + bool EnableMirroring(); + bool DisableMirroring(); + bool IsMirroring() + { + return mIsMirroring; + } + + // Primary screen only + bool SetMirroringScreen(nsScreenGonk* aScreen); + bool ClearMirroringScreen(nsScreenGonk* aScreen); + + // Called only on compositor thread void SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, mozilla::gl::GLContext* aGLContext); hwc_display_t GetEGLDisplay(); hwc_surface_t GetEGLSurface(); + void UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow); // Primary screen only + nsWindow* GetMirroringWidget(); // Primary screen only protected: uint32_t mId; int32_t mColorDepth; android::sp<ANativeWindow> mNativeWindow; float mDpi; int32_t mSurfaceFormat; nsIntRect mNaturalBounds; // Screen bounds w/o rotation taken into account. nsIntRect mVirtualBounds; // Screen bounds w/ rotation taken into account. uint32_t mScreenRotation; uint32_t mPhysicalScreenRotation; nsTArray<nsWindow*> mTopWindows; #if ANDROID_VERSION >= 17 android::sp<android::DisplaySurface> mDisplaySurface; #endif + bool mIsMirroring; // Non-primary screen only + nsRefPtr<nsScreenGonk> mMirroringScreen; // Primary screen only // Accessed and updated only on compositor thread GonkDisplay::DisplayType mDisplayType; hwc_display_t mEGLDisplay; hwc_surface_t mEGLSurface; - mozilla::gl::GLContext* mGLContext; + nsRefPtr<mozilla::gl::GLContext> mGLContext; + nsRefPtr<nsWindow> mMirroringWidget; // Primary screen only }; class nsScreenManagerGonk final : public nsIScreenManager { public: typedef mozilla::GonkDisplay GonkDisplay; public: @@ -128,17 +147,17 @@ public: static already_AddRefed<nsScreenManagerGonk> GetInstance(); static already_AddRefed<nsScreenGonk> GetPrimaryScreen(); void Initialize(); void DisplayEnabled(bool aEnabled); nsresult AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aProducer = nullptr); + android::IGraphicBufferProducer* aSink = nullptr); nsresult RemoveScreen(GonkDisplay::DisplayType aDisplayType); protected: ~nsScreenManagerGonk(); void VsyncControl(bool aEnabled); uint32_t GetIdFromType(GonkDisplay::DisplayType aDisplayType); bool IsScreenConnected(uint32_t aId);