diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h --- a/widget/gtk/WindowSurfaceWayland.h +++ b/widget/gtk/WindowSurfaceWayland.h @@ -177,12 +177,9 @@ private: WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight); - WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight, - bool aFullScreenUpdate); + WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer); - already_AddRefed LockWaylandBuffer(int aWidth, int aHeight, - bool aClearBuffer, - bool aFullScreenUpdate); + already_AddRefed LockWaylandBuffer(bool aCanSwitchBuffer); void UnlockWaylandBuffer(); already_AddRefed LockImageSurface( @@ -198,7 +195,10 @@ // TODO: Do we need to hold a reference to nsWindow object? nsWindow* mWindow; - LayoutDeviceIntRect mLastScreenRect; + // Buffer screen rects helps us understand if we operate on + // the same window size as we're called on WindowSurfaceWayland::Lock(). + // mBufferScreenRect is window size when our wayland buffer was allocated. + LayoutDeviceIntRect mBufferScreenRect; nsWaylandDisplay* mWaylandDisplay; WindowBackBuffer* mWaylandBuffer; LayoutDeviceIntRegion mWaylandBufferDamage; @@ -211,7 +211,8 @@ AutoTArray mDelayedImageCommits; bool mDrawToWaylandBufferDirectly; bool mPendingCommit; - bool mWaylandBufferFullScreenDamage; + bool mWholeWindowBufferDamage; + bool mBufferNeedsClear; bool mIsMainThread; bool mNeedScaleFactorUpdate; diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp --- a/widget/gtk/WindowSurfaceWayland.cpp +++ b/widget/gtk/WindowSurfaceWayland.cpp @@ -499,7 +499,8 @@ mDelayedCommitHandle(nullptr), mDrawToWaylandBufferDirectly(true), mPendingCommit(false), - mWaylandBufferFullScreenDamage(false), + mWholeWindowBufferDamage(false), + mBufferNeedsClear(false), mIsMainThread(NS_IsMainThread()), mNeedScaleFactorUpdate(true) { for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr; @@ -565,18 +566,20 @@ } WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw( - int aWidth, int aHeight, bool aFullScreenUpdate) { + bool aCanSwitchBuffer) { LOGWAYLAND(("%s [%p] Requested buffer [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, aWidth, aHeight)); + (void*)this, mBufferScreenRect.width, mBufferScreenRect.height)); // There's no buffer created yet, create a new one. if (!mWaylandBuffer) { - MOZ_ASSERT(aFullScreenUpdate, "Created new buffer for partial drawing!"); + MOZ_ASSERT(aCanSwitchBuffer && mWholeWindowBufferDamage, + "Created new buffer for partial drawing!"); LOGWAYLAND(("%s [%p] Created new buffer [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, aWidth, aHeight)); + (void*)this, mBufferScreenRect.width, + mBufferScreenRect.height)); - mWaylandBuffer = CreateWaylandBuffer(aWidth, aHeight); - mWaylandBufferFullScreenDamage = true; + mWaylandBuffer = + CreateWaylandBuffer(mBufferScreenRect.width, mBufferScreenRect.height); mNeedScaleFactorUpdate = true; return mWaylandBuffer; } @@ -593,29 +596,31 @@ LOGWAYLAND( ("%s [%p] Use recent buffer.\n", __PRETTY_FUNCTION__, (void*)this)); - if (mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) { + if (mWaylandBuffer->IsMatchingSize(mBufferScreenRect.width, + mBufferScreenRect.height)) { LOGWAYLAND(("%s [%p] Size is ok, use the buffer [%d x %d]\n", - __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); + __PRETTY_FUNCTION__, (void*)this, mBufferScreenRect.width, + mBufferScreenRect.height)); return mWaylandBuffer; } - if (!aFullScreenUpdate) { + if (!aCanSwitchBuffer) { NS_WARNING("We can't resize Wayland buffer for non-fullscreen updates!"); return nullptr; } LOGWAYLAND(("%s [%p] Reuse buffer with resize [%d x %d]\n", - __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); + __PRETTY_FUNCTION__, (void*)this, mBufferScreenRect.width, + mBufferScreenRect.height)); - mWaylandBuffer->Resize(aWidth, aHeight); + mWaylandBuffer->Resize(mBufferScreenRect.width, mBufferScreenRect.height); // There's a chance that scale factor has been changed // when buffer size changed - mWaylandBufferFullScreenDamage = true; mNeedScaleFactorUpdate = true; return mWaylandBuffer; } - if (!aFullScreenUpdate) { + if (!aCanSwitchBuffer) { return nullptr; } @@ -625,8 +630,10 @@ availableBuffer++) { if (!mBackupBuffer[availableBuffer]) { LOGWAYLAND(("%s [%p] Created new buffer [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, aWidth, aHeight)); - mBackupBuffer[availableBuffer] = CreateWaylandBuffer(aWidth, aHeight); + (void*)this, mBufferScreenRect.width, + mBufferScreenRect.height)); + mBackupBuffer[availableBuffer] = CreateWaylandBuffer( + mBufferScreenRect.width, mBufferScreenRect.height); break; } @@ -650,23 +657,23 @@ __PRETTY_FUNCTION__, (void*)this, (void*)lastWaylandBuffer, (void*)mWaylandBuffer)); - mWaylandBufferFullScreenDamage = true; mNeedScaleFactorUpdate = true; - bool bufferNeedsResize = !mWaylandBuffer->IsMatchingSize(aWidth, aHeight); + bool bufferNeedsResize = !mWaylandBuffer->IsMatchingSize( + mBufferScreenRect.width, mBufferScreenRect.height); if (bufferNeedsResize) { LOGWAYLAND(("%s [%p] Resize buffer to [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, aWidth, aHeight)); - mWaylandBuffer->Resize(aWidth, aHeight); + (void*)this, mBufferScreenRect.width, + mBufferScreenRect.height)); + mWaylandBuffer->Resize(mBufferScreenRect.width, mBufferScreenRect.height); } return mWaylandBuffer; } already_AddRefed WindowSurfaceWayland::LockWaylandBuffer( - int aWidth, int aHeight, bool aClearBuffer, bool aFullScreenUpdate) { - WindowBackBuffer* buffer = - GetWaylandBufferToDraw(aWidth, aHeight, aFullScreenUpdate); + bool aCanSwitchBuffer) { + WindowBackBuffer* buffer = GetWaylandBufferToDraw(aCanSwitchBuffer); LOGWAYLAND(("%s [%p] Got buffer %p\n", __PRETTY_FUNCTION__, (void*)this, (void*)buffer)); @@ -675,8 +682,9 @@ return nullptr; } - if (aClearBuffer) { + if (mBufferNeedsClear && mWholeWindowBufferDamage) { buffer->Clear(); + mBufferNeedsClear = false; } return buffer->Lock(); @@ -744,7 +752,7 @@ const LayoutDeviceIntRegion& aRegion) { MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); - LayoutDeviceIntRect screenRect = mWindow->GetBounds(); + LayoutDeviceIntRect lockedScreenRect = mWindow->GetBounds(); gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); @@ -753,54 +761,77 @@ mWindow->IsWaylandPopup() && (eTransparencyTransparent == mWindow->GetTransparencyMode()); - mDrawToWaylandBufferDirectly = - isTransparentPopup ? IsPopupFullScreenUpdate(screenRect, aRegion) - : IsWindowFullScreenUpdate(screenRect, aRegion); + // We have request to lock whole buffer/window. + mWholeWindowBufferDamage = + isTransparentPopup ? IsPopupFullScreenUpdate(lockedScreenRect, aRegion) + : IsWindowFullScreenUpdate(lockedScreenRect, aRegion); - bool needsClear = mWindow->WaylandSurfaceNeedsClear() || - (isTransparentPopup && mDrawToWaylandBufferDirectly); + // Clear buffer when we (re)draw new transparent popup window, + // otherwise leave it as-is, mBufferNeedsClear can be set from previous + // (already pending) commits which are cached now. + if (mWholeWindowBufferDamage) { + mBufferNeedsClear = + mWindow->WaylandSurfaceNeedsClear() || isTransparentPopup; + } LOGWAYLAND(("%s [%p] lockSize [%d x %d] windowSize [%d x %d]\n", __PRETTY_FUNCTION__, (void*)this, lockSize.width, lockSize.height, - screenRect.width, screenRect.height)); + lockedScreenRect.width, lockedScreenRect.height)); LOGWAYLAND((" nsWindow = %p\n", mWindow)); LOGWAYLAND((" isPopup = %d\n", mWindow->IsWaylandPopup())); LOGWAYLAND((" isTransparentPopup = %d\n", isTransparentPopup)); LOGWAYLAND((" IsPopupFullScreenUpdate = %d\n", - IsPopupFullScreenUpdate(screenRect, aRegion))); + IsPopupFullScreenUpdate(lockedScreenRect, aRegion))); LOGWAYLAND((" IsWindowFullScreenUpdate = %d\n", - IsWindowFullScreenUpdate(screenRect, aRegion))); - LOGWAYLAND((" needsClear = %d\n", needsClear)); - LOGWAYLAND( - (" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); + IsWindowFullScreenUpdate(lockedScreenRect, aRegion))); + LOGWAYLAND((" mBufferNeedsClear = %d\n", mBufferNeedsClear)); + LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); + +#if DEBUG + if (!(mBufferScreenRect == lockedScreenRect)) { + LOGWAYLAND((" screen size changed\n")); + } +#endif - // Allow full screen allocation and clear - // when window size changed. - bool bufferRedraw = !(screenRect == mLastScreenRect); - if (bufferRedraw) { - mDrawToWaylandBufferDirectly = true; - needsClear = true; + if (!(mBufferScreenRect == lockedScreenRect)) { + // Screen (window) size changed and we still have some painting pending + // for the last window size. That can happen when window is resized. + // We can't commit them any more as they're for former window size, so + // scratch them. + mDelayedImageCommits.Clear(); + + if (!mWholeWindowBufferDamage) { + NS_WARNING("Partial screen update when window is resized!"); + // This should not happen. Screen size changed but we got only + // partal screen update instead of whole screen. Discard this painting + // as it produces artifacts. + return nullptr; + } + mBufferScreenRect = lockedScreenRect; } - if (mDrawToWaylandBufferDirectly) { + if (mWholeWindowBufferDamage) { + // We can lock/commit entire buffer direcly. + mDrawToWaylandBufferDirectly = true; + // If there's any pending image commit scratch them as we're going // to redraw the whole sceen anyway. mDelayedImageCommits.Clear(); - RefPtr dt = - LockWaylandBuffer(screenRect.width, screenRect.height, needsClear, - /* aFullScreenUpdate */ true); + RefPtr dt = LockWaylandBuffer( + /* aCanSwitchBuffer */ mWholeWindowBufferDamage); if (dt) { - if (bufferRedraw) { - mLastScreenRect = screenRect; - } return dt.forget(); } + } - // We don't have any front buffer available. Try indirect drawing - // to mImageSurface which is mirrored to front buffer at commit. - mDrawToWaylandBufferDirectly = false; - } + // We do indirect drawing due to: + // + // 1) We don't have any front buffer available. Try indirect drawing + // to mImageSurface which is mirrored to front buffer at commit. + // 2) Only part of the screen is locked. We can't lock entire screen for + // such drawing as it produces visible artifacts. + mDrawToWaylandBufferDirectly = false; LOGWAYLAND((" Indirect drawing.\n")); return LockImageSurface(lockSize); @@ -851,16 +882,14 @@ LayoutDeviceIntRegion& aWaylandBufferDamage) { MOZ_ASSERT(!mDrawToWaylandBufferDirectly); - LayoutDeviceIntRect screenRect = mWindow->GetBounds(); +#ifdef DEBUG gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); - gfx::Rect rect(bounds); - if (rect.IsEmpty()) { - return false; - } + MOZ_ASSERT(!rect.IsEmpty(), "Empty drawing?"); +#endif LOGWAYLAND(("%s [%p] screenSize [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, screenRect.width, screenRect.height)); + (void*)this, mBufferScreenRect.width, mBufferScreenRect.height)); RefPtr surf = gfx::Factory::CreateSourceSurfaceForCairoSurface( @@ -871,13 +900,8 @@ return false; } - // Allow full screen allocation and clear - // when window size changed. - bool bufferRedraw = !(screenRect == mLastScreenRect); - RefPtr dt = - LockWaylandBuffer(screenRect.width, screenRect.height, - /* needs clear*/ bufferRedraw, - /* aFullScreenUpdate */ bufferRedraw); + RefPtr dt = LockWaylandBuffer( + /* aCanSwitchBuffer */ mWholeWindowBufferDamage); if (dt) { LOGWAYLAND( (" Flushing %ld cached WindowImageSurfaces to Wayland buffer\n", @@ -885,14 +909,11 @@ // Draw any delayed image commits first DrawDelayedImageCommits(dt, aWaylandBufferDamage); + // Draw image from recent WindowSurfaceWayland::Lock(). WindowImageSurface::Draw(surf, dt, aRegion); // Submit all drawing to final Wayland buffer upload aWaylandBufferDamage.OrWith(aRegion); UnlockWaylandBuffer(); - - if (bufferRedraw) { - mLastScreenRect = screenRect; - } } else { mDelayedImageCommits.AppendElement(WindowImageSurface(surf, aRegion)); LOGWAYLAND((" Added WindowImageSurfaces, cached surfaces %ld\n", @@ -930,29 +951,25 @@ LOGWAYLAND(("%s [%p]\n", __PRETTY_FUNCTION__, (void*)this)); LOGWAYLAND( (" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); - LOGWAYLAND((" mWaylandBufferFullScreenDamage = %d\n", - mWaylandBufferFullScreenDamage)); + LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); LOGWAYLAND((" mDelayedCommitHandle = %p\n", mDelayedCommitHandle)); LOGWAYLAND((" mFrameCallback = %p\n", mFrameCallback)); LOGWAYLAND((" mLastCommittedSurface = %p\n", mLastCommittedSurface)); if (!mDrawToWaylandBufferDirectly) { + MOZ_ASSERT(mDelayedImageCommits.Length(), + "Indirect drawing without any image?"); + // There's some cached drawings - try to flush them now. - LayoutDeviceIntRect screenRect = mWindow->GetBounds(); - bool bufferRedraw = !(screenRect == mLastScreenRect); - RefPtr dt = - LockWaylandBuffer(screenRect.width, screenRect.height, - /* needsClear */ bufferRedraw, - /* full screen update */ bufferRedraw); + RefPtr dt = LockWaylandBuffer( + /* aCanSwitchBuffer */ mWholeWindowBufferDamage); + if (dt) { LOGWAYLAND(("%s [%p] flushed indirect drawing\n", __PRETTY_FUNCTION__, (void*)this)); DrawDelayedImageCommits(dt, mWaylandBufferDamage); UnlockWaylandBuffer(); mDrawToWaylandBufferDirectly = true; - if (bufferRedraw) { - mLastScreenRect = screenRect; - } } } @@ -1000,10 +1017,10 @@ mLastCommittedSurface = nullptr; } - if (mWaylandBufferFullScreenDamage) { - LayoutDeviceIntRect rect = mWindow->GetBounds(); - wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height); - mWaylandBufferFullScreenDamage = false; + if (mWholeWindowBufferDamage) { + wl_surface_damage(waylandSurface, 0, 0, mBufferScreenRect.width, + mBufferScreenRect.height); + mWholeWindowBufferDamage = false; mNeedScaleFactorUpdate = true; } else { gint scaleFactor = mWindow->GdkScaleFactor(); @@ -1043,24 +1060,24 @@ #ifdef DEBUG { - LayoutDeviceIntRect screenRect = mWindow->GetBounds(); gfx::IntRect bounds = aInvalidRegion.GetBounds().ToUnknownRect(); gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); LOGWAYLAND(("%s [%p] lockSize [%d x %d] screenSize [%d x %d]\n", __PRETTY_FUNCTION__, (void*)this, lockSize.width, - lockSize.height, screenRect.width, screenRect.height)); + lockSize.height, mBufferScreenRect.width, + mBufferScreenRect.height)); LOGWAYLAND((" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); - LOGWAYLAND((" mWaylandBufferFullScreenDamage = %d\n", - mWaylandBufferFullScreenDamage)); + LOGWAYLAND( + (" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); } #endif if (mDrawToWaylandBufferDirectly) { MOZ_ASSERT(mWaylandBuffer->IsLocked()); // If we're not at fullscreen damage add drawing area from aInvalidRegion - if (!mWaylandBufferFullScreenDamage) { + if (!mWholeWindowBufferDamage) { mWaylandBufferDamage.OrWith(aInvalidRegion); } UnlockWaylandBuffer();