forked from mirrors/gecko-dev
		
	 6d0dfe44e3
			
		
	
	
		6d0dfe44e3
		
	
	
	
	
		
			
			It caused us substantial confusion investigating this bug under the belief that StartRemoteDrawingInRegion may have been modifying the dirty region. None of our existing widget code anymore uses the API in this way, so it makes sense to just force this dirty region to be const so that we no longer support the assumption and alleviate confusion in the future about how our widget code actually behaves. Depends on D106246 Differential Revision: https://phabricator.services.mozilla.com/D106247
		
			
				
	
	
		
			223 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| #include "CompositorWidgetParent.h"
 | |
| 
 | |
| #include "mozilla/Unused.h"
 | |
| #include "mozilla/StaticPrefs_layers.h"
 | |
| #include "mozilla/gfx/DeviceManagerDx.h"
 | |
| #include "mozilla/gfx/Point.h"
 | |
| #include "mozilla/layers/Compositor.h"
 | |
| #include "mozilla/layers/CompositorBridgeParent.h"
 | |
| #include "mozilla/layers/CompositorThread.h"
 | |
| #include "mozilla/webrender/RenderThread.h"
 | |
| #include "mozilla/widget/PlatformWidgetTypes.h"
 | |
| #include "nsWindow.h"
 | |
| #include "VsyncDispatcher.h"
 | |
| #include "WinCompositorWindowThread.h"
 | |
| #include "VRShMem.h"
 | |
| #include "RemoteBackbuffer.h"
 | |
| 
 | |
| #include <ddraw.h>
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace widget {
 | |
| 
 | |
| using namespace mozilla::gfx;
 | |
| using namespace mozilla;
 | |
| 
 | |
| CompositorWidgetParent::CompositorWidgetParent(
 | |
|     const CompositorWidgetInitData& aInitData,
 | |
|     const layers::CompositorOptions& aOptions)
 | |
|     : WinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(),
 | |
|                           aOptions),
 | |
|       mWnd(reinterpret_cast<HWND>(
 | |
|           aInitData.get_WinCompositorWidgetInitData().hWnd())),
 | |
|       mTransparencyMode(
 | |
|           aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
 | |
|       mRemoteBackbufferClient() {
 | |
|   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
 | |
|   MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
 | |
| }
 | |
| 
 | |
| CompositorWidgetParent::~CompositorWidgetParent() {}
 | |
| 
 | |
| bool CompositorWidgetParent::Initialize(
 | |
|     const RemoteBackbufferHandles& aRemoteHandles) {
 | |
|   mRemoteBackbufferClient = std::make_unique<remote_backbuffer::Client>();
 | |
|   if (!mRemoteBackbufferClient->Initialize(aRemoteHandles)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CompositorWidgetParent::PreRender(WidgetRenderingContext* aContext) {
 | |
|   // This can block waiting for WM_SETTEXT to finish
 | |
|   // Using PreRender is unnecessarily pessimistic because
 | |
|   // we technically only need to block during the present call
 | |
|   // not all of compositor rendering
 | |
|   mPresentLock.Enter();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void CompositorWidgetParent::PostRender(WidgetRenderingContext* aContext) {
 | |
|   mPresentLock.Leave();
 | |
| }
 | |
| 
 | |
| LayoutDeviceIntSize CompositorWidgetParent::GetClientSize() {
 | |
|   RECT r;
 | |
|   if (!::GetClientRect(mWnd, &r)) {
 | |
|     return LayoutDeviceIntSize();
 | |
|   }
 | |
|   return LayoutDeviceIntSize(r.right - r.left, r.bottom - r.top);
 | |
| }
 | |
| 
 | |
| already_AddRefed<gfx::DrawTarget>
 | |
| CompositorWidgetParent::StartRemoteDrawingInRegion(
 | |
|     const LayoutDeviceIntRegion& aInvalidRegion,
 | |
|     layers::BufferMode* aBufferMode) {
 | |
|   MOZ_ASSERT(mRemoteBackbufferClient);
 | |
|   MOZ_ASSERT(aBufferMode);
 | |
| 
 | |
|   // Because we use remote backbuffering, there is no need to use a local
 | |
|   // backbuffer too.
 | |
|   (*aBufferMode) = layers::BufferMode::BUFFER_NONE;
 | |
| 
 | |
|   return mRemoteBackbufferClient->BorrowDrawTarget();
 | |
| }
 | |
| 
 | |
| void CompositorWidgetParent::EndRemoteDrawingInRegion(
 | |
|     gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
 | |
|   Unused << mRemoteBackbufferClient->PresentDrawTarget(
 | |
|       aInvalidRegion.ToUnknownRegion());
 | |
| }
 | |
| 
 | |
| bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
 | |
| 
 | |
| already_AddRefed<gfx::DrawTarget>
 | |
| CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
 | |
|                                                 const gfx::IntRect& aRect,
 | |
|                                                 bool* aOutIsCleared) {
 | |
|   MOZ_CRASH(
 | |
|       "Unexpected call to GetBackBufferDrawTarget() with remote "
 | |
|       "backbuffering in use");
 | |
| }
 | |
| 
 | |
| already_AddRefed<gfx::SourceSurface>
 | |
| CompositorWidgetParent::EndBackBufferDrawing() {
 | |
|   MOZ_CRASH(
 | |
|       "Unexpected call to EndBackBufferDrawing() with remote "
 | |
|       "backbuffering in use");
 | |
| }
 | |
| 
 | |
| bool CompositorWidgetParent::InitCompositor(layers::Compositor* aCompositor) {
 | |
|   if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
 | |
|     DeviceManagerDx::Get()->InitializeDirectDraw();
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CompositorWidgetParent::HasGlass() const {
 | |
|   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
 | |
|              wr::RenderThread::IsInRenderThread());
 | |
| 
 | |
|   nsTransparencyMode transparencyMode = mTransparencyMode;
 | |
|   return transparencyMode == eTransparencyGlass ||
 | |
|          transparencyMode == eTransparencyBorderlessGlass;
 | |
| }
 | |
| 
 | |
| bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
 | |
| 
 | |
| mozilla::ipc::IPCResult CompositorWidgetParent::RecvInitialize(
 | |
|     const RemoteBackbufferHandles& aRemoteHandles) {
 | |
|   Unused << Initialize(aRemoteHandles);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnterPresentLock() {
 | |
|   mPresentLock.Enter();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult CompositorWidgetParent::RecvLeavePresentLock() {
 | |
|   mPresentLock.Leave();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult CompositorWidgetParent::RecvUpdateTransparency(
 | |
|     const nsTransparencyMode& aMode) {
 | |
|   mTransparencyMode = aMode;
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult CompositorWidgetParent::RecvClearTransparentWindow() {
 | |
|   gfx::CriticalSectionAutoEnter lock(&mPresentLock);
 | |
| 
 | |
|   RefPtr<DrawTarget> drawTarget = mRemoteBackbufferClient->BorrowDrawTarget();
 | |
|   if (!drawTarget) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   IntSize size = drawTarget->GetSize();
 | |
|   if (size.IsEmpty()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
 | |
| 
 | |
|   Unused << mRemoteBackbufferClient->PresentDrawTarget(
 | |
|       IntRect(0, 0, size.width, size.height));
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| nsIWidget* CompositorWidgetParent::RealWidget() { return nullptr; }
 | |
| 
 | |
| void CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver) {
 | |
|   if (aObserver) {
 | |
|     Unused << SendObserveVsync();
 | |
|   } else {
 | |
|     Unused << SendUnobserveVsync();
 | |
|   }
 | |
|   mVsyncObserver = aObserver;
 | |
| }
 | |
| 
 | |
| RefPtr<VsyncObserver> CompositorWidgetParent::GetVsyncObserver() const {
 | |
|   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
 | |
|   return mVsyncObserver;
 | |
| }
 | |
| 
 | |
| void CompositorWidgetParent::UpdateCompositorWnd(const HWND aCompositorWnd,
 | |
|                                                  const HWND aParentWnd) {
 | |
|   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
 | |
|   MOZ_ASSERT(mRootLayerTreeID.isSome());
 | |
| 
 | |
|   RefPtr<CompositorWidgetParent> self = this;
 | |
|   SendUpdateCompositorWnd(reinterpret_cast<WindowsHandle>(aCompositorWnd),
 | |
|                           reinterpret_cast<WindowsHandle>(aParentWnd))
 | |
|       ->Then(
 | |
|           layers::CompositorThread(), __func__,
 | |
|           [self](const bool& aSuccess) {
 | |
|             if (aSuccess && self->mRootLayerTreeID.isSome()) {
 | |
|               self->mSetParentCompleted = true;
 | |
|               // Schedule composition after ::SetParent() call in parent
 | |
|               // process.
 | |
|               layers::CompositorBridgeParent::ScheduleForcedComposition(
 | |
|                   self->mRootLayerTreeID.ref());
 | |
|             }
 | |
|           },
 | |
|           [self](const mozilla::ipc::ResponseRejectReason&) {});
 | |
| }
 | |
| 
 | |
| void CompositorWidgetParent::SetRootLayerTreeID(
 | |
|     const layers::LayersId& aRootLayerTreeId) {
 | |
|   mRootLayerTreeID = Some(aRootLayerTreeId);
 | |
| }
 | |
| 
 | |
| void CompositorWidgetParent::ActorDestroy(ActorDestroyReason aWhy) {}
 | |
| 
 | |
| }  // namespace widget
 | |
| }  // namespace mozilla
 |