Backed out changeset 71e63781b38c (bug 1604412) for failures on /browser_startup_syncIPC.js -PCompositorWidget. CLOSED TREE

This commit is contained in:
Csoregi Natalia 2020-02-13 12:13:06 +02:00
Родитель ff0444bf80
Коммит 9c0442f988
9 изменённых файлов: 180 добавлений и 731 удалений

Просмотреть файл

@ -1111,21 +1111,18 @@ description = legacy sync IPC - please add detailed description
description = legacy sync IPC - please add detailed description
[PCompositorBridge::CheckContentOnlyTDR]
description = legacy sync IPC - please add detailed description
[PCompositorWidget::Initialize]
description = Fallable initialization for the widget. Must be called right after construction before any other messages are sent
platform = win
[PCompositorWidget::EnterPresentLock]
description = Obtain exclusive access to the widget surface. Used to ensure events don't change the surface while it's being used as a render target
description = legacy sync IPC - please add detailed description
platform = win
[PCompositorWidget::LeavePresentLock]
description = Release the exclusive lock that EnterPresentLock obtained
description = legacy sync IPC - please add detailed description
platform = win
[PCompositorBridge::SupportsAsyncDXGISurface]
description = legacy sync IPC - please add detailed description
[PCompositorBridge::PreferredDXGIAdapter]
description = legacy sync IPC - please add detailed description
[PCompositorWidget::ClearTransparentWindow]
description = Synchronously clear the widget surface. Does not rely on (Enter|Leave)PresentLock. When call returns, window surface has been fully updated with cleared pixel values.
description = legacy sync IPC - please add detailed description
platform = win
[PImageBridge::WillClose]
description = legacy sync IPC - please add detailed description

Просмотреть файл

@ -10,7 +10,6 @@
#include "nsBaseWidget.h"
#include "VsyncDispatcher.h"
#include "gfxPlatform.h"
#include "RemoteBackbuffer.h"
namespace mozilla {
namespace widget {
@ -25,8 +24,7 @@ CompositorWidgetChild::CompositorWidgetChild(
mWnd(reinterpret_cast<HWND>(
aInitData.get_WinCompositorWidgetInitData().hWnd())),
mTransparencyMode(
aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
mRemoteBackbufferProvider() {
aInitData.get_WinCompositorWidgetInitData().transparencyMode()) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!gfxPlatform::IsHeadless());
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
@ -34,21 +32,7 @@ CompositorWidgetChild::CompositorWidgetChild(
CompositorWidgetChild::~CompositorWidgetChild() {}
bool CompositorWidgetChild::Initialize() {
mRemoteBackbufferProvider = std::make_unique<remote_backbuffer::Provider>();
if (!mRemoteBackbufferProvider->Initialize(mWnd, OtherPid())) {
return false;
}
auto maybeRemoteHandles = mRemoteBackbufferProvider->CreateRemoteHandles();
if (!maybeRemoteHandles) {
return false;
}
Unused << SendInitialize(*maybeRemoteHandles);
return true;
}
bool CompositorWidgetChild::Initialize() { return true; }
void CompositorWidgetChild::EnterPresentLock() {
Unused << SendEnterPresentLock();

Просмотреть файл

@ -15,10 +15,6 @@ class CompositorVsyncDispatcher;
namespace widget {
namespace remote_backbuffer {
class Provider;
}
class CompositorWidgetChild final : public PCompositorWidgetChild,
public PlatformCompositorWidgetDelegate {
public:
@ -50,8 +46,6 @@ class CompositorWidgetChild final : public PCompositorWidgetChild,
HWND mWnd;
nsTransparencyMode mTransparencyMode;
std::unique_ptr<remote_backbuffer::Provider> mRemoteBackbufferProvider;
};
} // namespace widget

Просмотреть файл

@ -18,7 +18,6 @@
#include "VsyncDispatcher.h"
#include "WinCompositorWindowThread.h"
#include "VRShMem.h"
#include "RemoteBackbuffer.h"
#include <ddraw.h>
@ -35,26 +34,24 @@ CompositorWidgetParent::CompositorWidgetParent(
aOptions),
mWnd(reinterpret_cast<HWND>(
aInitData.get_WinCompositorWidgetInitData().hWnd())),
mTransparentSurfaceLock("mTransparentSurfaceLock"),
mTransparencyMode(
aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
mLockedBackBufferData(nullptr),
mRemoteBackbufferClient() {
mMemoryDC(nullptr),
mCompositeDC(nullptr),
mLockedBackBufferData(nullptr) {
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
// mNotDeferEndRemoteDrawing is set on the main thread during init,
// but is only accessed after on the compositor thread.
mNotDeferEndRemoteDrawing =
StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
gfxPlatform::IsInLayoutAsapMode() || gfxPlatform::ForceSoftwareVsync();
}
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
@ -77,18 +74,88 @@ LayoutDeviceIntSize CompositorWidgetParent::GetClientSize() {
}
already_AddRefed<gfx::DrawTarget> CompositorWidgetParent::StartRemoteDrawing() {
MOZ_ASSERT(mRemoteBackbufferClient);
MutexAutoLock lock(mTransparentSurfaceLock);
return mRemoteBackbufferClient->BorrowDrawTarget();
MOZ_ASSERT(!mCompositeDC);
RefPtr<gfxASurface> surf;
if (mTransparencyMode == eTransparencyTransparent) {
surf = EnsureTransparentSurface();
}
// Must call this after EnsureTransparentSurface(), since it could update
// the DC.
HDC dc = GetWindowSurface();
if (!surf) {
if (!dc) {
return nullptr;
}
uint32_t flags = (mTransparencyMode == eTransparencyOpaque)
? 0
: gfxWindowsSurface::FLAG_IS_TRANSPARENT;
surf = new gfxWindowsSurface(dc, flags);
}
IntSize size = surf->GetSize();
if (size.width <= 0 || size.height <= 0) {
if (dc) {
FreeWindowSurface(dc);
}
return nullptr;
}
RefPtr<DrawTarget> dt =
mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(
surf->CairoSurface(), size);
if (dt) {
mCompositeDC = dc;
} else {
FreeWindowSurface(dc);
}
return dt.forget();
}
void CompositorWidgetParent::EndRemoteDrawing() {
MOZ_ASSERT(!mLockedBackBufferData);
Unused << mRemoteBackbufferClient->PresentDrawTarget();
if (mTransparencyMode == eTransparencyTransparent) {
MOZ_ASSERT(mTransparentSurface);
RedrawTransparentWindow();
}
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() {
if (mNotDeferEndRemoteDrawing) {
return false;
}
IDirectDraw7* ddraw = DeviceManagerDx::Get()->GetDirectDraw();
if (!ddraw) {
return false;
}
DWORD scanLine = 0;
int height = ::GetSystemMetrics(SM_CYSCREEN);
HRESULT ret = ddraw->GetScanLine(&scanLine);
if (ret == DDERR_VERTICALBLANKINPROGRESS) {
scanLine = 0;
} else if (ret != DD_OK) {
return false;
}
// Check if there is a risk of tearing with GDI.
if (static_cast<int>(scanLine) > height / 2) {
// No need to defer.
return false;
}
return true;
}
already_AddRefed<gfx::DrawTarget>
CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
@ -137,6 +204,31 @@ bool CompositorWidgetParent::InitCompositor(layers::Compositor* aCompositor) {
return true;
}
RefPtr<gfxASurface> CompositorWidgetParent::EnsureTransparentSurface() {
mTransparentSurfaceLock.AssertCurrentThreadOwns();
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
IntSize size = GetClientSize().ToUnknownSize();
if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
CreateTransparentSurface(size);
}
RefPtr<gfxASurface> surface = mTransparentSurface;
return surface.forget();
}
void CompositorWidgetParent::CreateTransparentSurface(
const gfx::IntSize& aSize) {
mTransparentSurfaceLock.AssertCurrentThreadOwns();
MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
RefPtr<gfxWindowsSurface> surface =
new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
mTransparentSurface = surface;
mMemoryDC = surface->GetDC();
}
bool CompositorWidgetParent::HasGlass() const {
MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
wr::RenderThread::IsInRenderThread());
@ -146,14 +238,36 @@ bool CompositorWidgetParent::HasGlass() const {
transparencyMode == eTransparencyBorderlessGlass;
}
bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
bool CompositorWidgetParent::RedrawTransparentWindow() {
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
mozilla::ipc::IPCResult CompositorWidgetParent::RecvInitialize(
const RemoteBackbufferHandles& aRemoteHandles) {
Unused << Initialize(aRemoteHandles);
return IPC_OK();
LayoutDeviceIntSize size = GetClientSize();
::GdiFlush();
BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
SIZE winSize = {size.width, size.height};
POINT srcPos = {0, 0};
HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
RECT winRect;
::GetWindowRect(hWnd, &winRect);
// perform the alpha blend
return !!::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize,
mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
}
HDC CompositorWidgetParent::GetWindowSurface() {
return eTransparencyTransparent == mTransparencyMode ? mMemoryDC
: ::GetDC(mWnd);
}
void CompositorWidgetParent::FreeWindowSurface(HDC dc) {
if (eTransparencyTransparent != mTransparencyMode) ::ReleaseDC(mWnd, dc);
}
bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnterPresentLock() {
mPresentLock.Enter();
return IPC_OK();
@ -166,28 +280,39 @@ mozilla::ipc::IPCResult CompositorWidgetParent::RecvLeavePresentLock() {
mozilla::ipc::IPCResult CompositorWidgetParent::RecvUpdateTransparency(
const nsTransparencyMode& aMode) {
mTransparencyMode = aMode;
MutexAutoLock lock(mTransparentSurfaceLock);
if (mTransparencyMode == aMode) {
return IPC_OK();
}
mTransparencyMode = aMode;
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
if (mTransparencyMode == eTransparencyTransparent) {
EnsureTransparentSurface();
}
return IPC_OK();
}
mozilla::ipc::IPCResult CompositorWidgetParent::RecvClearTransparentWindow() {
gfx::CriticalSectionAutoEnter lock(&mPresentLock);
RefPtr<DrawTarget> drawTarget = mRemoteBackbufferClient->BorrowDrawTarget();
if (!drawTarget) {
MutexAutoLock lock(mTransparentSurfaceLock);
if (!mTransparentSurface) {
return IPC_OK();
}
IntSize size = drawTarget->GetSize();
if (size.IsEmpty()) {
return IPC_OK();
EnsureTransparentSurface();
IntSize size = mTransparentSurface->GetSize();
if (!size.IsEmpty()) {
RefPtr<DrawTarget> drawTarget =
gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface, size);
if (!drawTarget) {
return IPC_OK();
}
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
RedrawTransparentWindow();
}
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
Unused << mRemoteBackbufferClient->PresentDrawTarget();
return IPC_OK();
}

Просмотреть файл

@ -13,10 +13,6 @@
namespace mozilla {
namespace widget {
namespace remote_backbuffer {
class Client;
}
class CompositorWidgetParent final : public PCompositorWidgetParent,
public WinCompositorWidget {
public:
@ -24,8 +20,6 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
const layers::CompositorOptions& aOptions);
~CompositorWidgetParent() override;
bool Initialize(const RemoteBackbufferHandles& aRemoteHandles);
bool PreRender(WidgetRenderingContext*) override;
void PostRender(WidgetRenderingContext*) override;
already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
@ -41,8 +35,6 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
bool HasGlass() const override;
mozilla::ipc::IPCResult RecvInitialize(
const RemoteBackbufferHandles& aRemoteHandles) override;
mozilla::ipc::IPCResult RecvEnterPresentLock() override;
mozilla::ipc::IPCResult RecvLeavePresentLock() override;
mozilla::ipc::IPCResult RecvUpdateTransparency(
@ -60,6 +52,16 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
void SetRootLayerTreeID(const layers::LayersId& aRootLayerTreeId) override;
private:
bool RedrawTransparentWindow();
// Ensure that a transparent surface exists, then return it.
RefPtr<gfxASurface> EnsureTransparentSurface();
HDC GetWindowSurface();
void FreeWindowSurface(HDC dc);
void CreateTransparentSurface(const gfx::IntSize& aSize);
RefPtr<VsyncObserver> mVsyncObserver;
Maybe<layers::LayersId> mRootLayerTreeID;
@ -68,13 +70,17 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
gfx::CriticalSection mPresentLock;
// Transparency handling.
mozilla::Mutex mTransparentSurfaceLock;
mozilla::Atomic<nsTransparencyMode, MemoryOrdering::Relaxed>
mTransparencyMode;
RefPtr<gfxASurface> mTransparentSurface;
HDC mMemoryDC;
HDC mCompositeDC;
// Locked back buffer of BasicCompositor
uint8_t* mLockedBackBufferData;
std::unique_ptr<remote_backbuffer::Client> mRemoteBackbufferClient;
bool mNotDeferEndRemoteDrawing;
};
} // namespace widget

Просмотреть файл

@ -13,19 +13,11 @@ using nsTransparencyMode from "mozilla/widget/WidgetMessageUtils.h";
namespace mozilla {
namespace widget {
struct RemoteBackbufferHandles {
WindowsHandle fileMapping;
WindowsHandle requestReadyEvent;
WindowsHandle responseReadyEvent;
};
sync protocol PCompositorWidget
{
manager PCompositorBridge;
parent:
sync Initialize(RemoteBackbufferHandles aRemoteHandles);
sync EnterPresentLock();
sync LeavePresentLock();
async UpdateTransparency(nsTransparencyMode aMode);

Просмотреть файл

@ -1,567 +0,0 @@
/* -*- 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 "RemoteBackbuffer.h"
namespace mozilla {
namespace widget {
namespace remote_backbuffer {
enum class ResponseResult {
Unknown,
Error,
BorrowSuccess,
BorrowSameBuffer,
PresentSuccess
};
enum class SharedDataType {
BorrowRequest,
BorrowResponse,
PresentRequest,
PresentResponse
};
struct BorrowResponseData {
ResponseResult result;
int32_t width;
int32_t height;
HANDLE fileMapping;
};
struct PresentResponseData {
ResponseResult result;
};
struct SharedData {
SharedDataType dataType;
union {
BorrowResponseData borrowResponse;
PresentResponseData presentResponse;
} data;
};
class SharedImage {
public:
SharedImage()
: mWidth(0), mHeight(0), mFileMapping(nullptr), mPixelData(nullptr) {}
~SharedImage() {
if (mPixelData) {
MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mPixelData));
}
if (mFileMapping) {
MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
}
}
bool Initialize(int32_t aWidth, int32_t aHeight) {
MOZ_ASSERT(aWidth);
MOZ_ASSERT(aHeight);
mWidth = aWidth;
mHeight = aHeight;
DWORD bufferSize = static_cast<DWORD>(mHeight * GetStride());
mFileMapping = ::CreateFileMappingW(
INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE,
0 /*sizeHigh*/, bufferSize, nullptr /*name*/);
if (!mFileMapping) {
return false;
}
void* mappedFilePtr =
::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
0 /*offsetLow*/, 0 /*bytesToMap*/);
if (!mappedFilePtr) {
return false;
}
mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
return true;
}
bool InitializeRemote(int32_t aWidth, int32_t aHeight, HANDLE aFileMapping) {
MOZ_ASSERT(aWidth);
MOZ_ASSERT(aHeight);
MOZ_ASSERT(aFileMapping);
mWidth = aWidth;
mHeight = aHeight;
mFileMapping = aFileMapping;
void* mappedFilePtr =
::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
0 /*offsetLow*/, 0 /*bytesToMap*/);
if (!mappedFilePtr) {
return false;
}
mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
return true;
}
HBITMAP CreateDIBSection() {
BITMAPINFO bitmapInfo = {};
bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader);
bitmapInfo.bmiHeader.biWidth = mWidth;
bitmapInfo.bmiHeader.biHeight = -mHeight;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
void* dummy = nullptr;
return ::CreateDIBSection(nullptr /*paletteDC*/, &bitmapInfo,
DIB_RGB_COLORS, &dummy, mFileMapping,
0 /*offset*/);
}
HANDLE CreateRemoteFileMapping(DWORD aTargetProcessId) {
MOZ_ASSERT(aTargetProcessId);
HANDLE fileMapping = nullptr;
if (!ipc::DuplicateHandle(mFileMapping, aTargetProcessId, &fileMapping,
0 /*desiredAccess*/, DUPLICATE_SAME_ACCESS)) {
return nullptr;
}
return fileMapping;
}
already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
return gfx::Factory::CreateDrawTargetForData(
gfx::BackendType::CAIRO, mPixelData, IntSize(mWidth, mHeight),
GetStride(), gfx::SurfaceFormat::B8G8R8A8);
}
int32_t GetWidth() { return mWidth; }
int32_t GetHeight() { return mHeight; }
SharedImage(const SharedImage&) = delete;
SharedImage(SharedImage&&) = delete;
SharedImage& operator=(const SharedImage&) = delete;
SharedImage& operator=(SharedImage&&) = delete;
private:
int32_t GetStride() {
constexpr int32_t kBytesPerPixel = 4;
// DIB requires 32-bit row alignment
return (((mWidth * kBytesPerPixel) + 3) / 4) * 4;
}
int32_t mWidth;
int32_t mHeight;
HANDLE mFileMapping;
unsigned char* mPixelData;
};
class PresentableSharedImage {
public:
PresentableSharedImage()
: mSharedImage(),
mDeviceContext(nullptr),
mDIBSection(nullptr),
mSavedObject(nullptr) {}
~PresentableSharedImage() {
if (mSavedObject) {
MOZ_ALWAYS_TRUE(::SelectObject(mDeviceContext, mSavedObject));
}
if (mDIBSection) {
MOZ_ALWAYS_TRUE(::DeleteObject(mDIBSection));
}
if (mDeviceContext) {
MOZ_ALWAYS_TRUE(::DeleteDC(mDeviceContext));
}
}
bool Initialize(int32_t aWidth, int32_t aHeight) {
if (!mSharedImage.Initialize(aWidth, aHeight)) {
return false;
}
mDeviceContext = ::CreateCompatibleDC(nullptr);
if (!mDeviceContext) {
return false;
}
mDIBSection = mSharedImage.CreateDIBSection();
if (!mDIBSection) {
return false;
}
mSavedObject = ::SelectObject(mDeviceContext, mDIBSection);
if (!mSavedObject) {
return false;
}
return true;
}
bool PresentToWindow(HWND aWindowHandle) {
bool isLayered =
::GetWindowLongPtrW(aWindowHandle, GWL_EXSTYLE) & WS_EX_LAYERED;
if (isLayered) {
BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
SIZE winSize = {mSharedImage.GetWidth(), mSharedImage.GetHeight()};
POINT srcPos = {0, 0};
return !!::UpdateLayeredWindow(
aWindowHandle, nullptr /*paletteDC*/, nullptr /*newPos*/, &winSize,
mDeviceContext, &srcPos, 0 /*colorKey*/, &bf, ULW_ALPHA);
}
HDC windowDC = ::GetDC(aWindowHandle);
if (!windowDC) {
return false;
}
bool result = ::BitBlt(windowDC, 0 /*dstX*/, 0 /*dstY*/,
mSharedImage.GetWidth(), mSharedImage.GetHeight(),
mDeviceContext, 0 /*srcX*/, 0 /*srcY*/, SRCCOPY);
MOZ_ALWAYS_TRUE(::ReleaseDC(aWindowHandle, windowDC));
return result;
}
HANDLE CreateRemoteFileMapping(DWORD aTargetProcessId) {
return mSharedImage.CreateRemoteFileMapping(aTargetProcessId);
}
already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
return mSharedImage.CreateDrawTarget();
}
int32_t GetWidth() { return mSharedImage.GetWidth(); }
int32_t GetHeight() { return mSharedImage.GetHeight(); }
PresentableSharedImage(const PresentableSharedImage&) = delete;
PresentableSharedImage(PresentableSharedImage&&) = delete;
PresentableSharedImage& operator=(const PresentableSharedImage&) = delete;
PresentableSharedImage& operator=(PresentableSharedImage&&) = delete;
private:
SharedImage mSharedImage;
HDC mDeviceContext;
HBITMAP mDIBSection;
HGDIOBJ mSavedObject;
};
Provider::Provider()
: mWindowHandle(nullptr),
mTargetProcessId(0),
mFileMapping(nullptr),
mRequestReadyEvent(nullptr),
mResponseReadyEvent(nullptr),
mSharedDataPtr(nullptr),
mStopServiceThread(false),
mServiceThread(),
mBackbuffer() {}
Provider::~Provider() {
mBackbuffer.reset();
if (mServiceThread.joinable()) {
mStopServiceThread = true;
MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
mServiceThread.join();
}
if (mSharedDataPtr) {
MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
}
if (mResponseReadyEvent) {
MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
}
if (mRequestReadyEvent) {
MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
}
if (mFileMapping) {
MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
}
}
bool Provider::Initialize(HWND aWindowHandle, DWORD aTargetProcessId) {
MOZ_ASSERT(aWindowHandle);
MOZ_ASSERT(aTargetProcessId);
mWindowHandle = aWindowHandle;
mTargetProcessId = aTargetProcessId;
mFileMapping = ::CreateFileMappingW(
INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE, 0 /*sizeHigh*/,
static_cast<DWORD>(sizeof(SharedData)), nullptr /*name*/);
if (!mFileMapping) {
return false;
}
mRequestReadyEvent =
::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
FALSE /*initialState*/, nullptr /*name*/);
if (!mRequestReadyEvent) {
return false;
}
mResponseReadyEvent =
::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
FALSE /*initialState*/, nullptr /*name*/);
if (!mResponseReadyEvent) {
return false;
}
void* mappedFilePtr =
::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
0 /*offsetLow*/, 0 /*bytesToMap*/);
if (!mappedFilePtr) {
return false;
}
mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
mStopServiceThread = false;
mServiceThread = std::thread([this] { this->ThreadMain(); });
return true;
}
Maybe<RemoteBackbufferHandles> Provider::CreateRemoteHandles() {
HANDLE fileMapping = nullptr;
if (!ipc::DuplicateHandle(mFileMapping, mTargetProcessId, &fileMapping,
0 /*desiredAccess*/, DUPLICATE_SAME_ACCESS)) {
return Nothing();
}
HANDLE requestReadyEvent = nullptr;
if (!ipc::DuplicateHandle(mRequestReadyEvent, mTargetProcessId,
&requestReadyEvent, 0 /*desiredAccess*/,
DUPLICATE_SAME_ACCESS)) {
return Nothing();
}
HANDLE responseReadyEvent = nullptr;
if (!ipc::DuplicateHandle(mResponseReadyEvent, mTargetProcessId,
&responseReadyEvent, 0 /*desiredAccess*/,
DUPLICATE_SAME_ACCESS)) {
return Nothing();
}
return Some(RemoteBackbufferHandles(
reinterpret_cast<WindowsHandle>(fileMapping),
reinterpret_cast<WindowsHandle>(requestReadyEvent),
reinterpret_cast<WindowsHandle>(responseReadyEvent)));
}
void Provider::ThreadMain() {
while (true) {
MOZ_ALWAYS_TRUE(::WaitForSingleObject(mRequestReadyEvent, INFINITE) ==
WAIT_OBJECT_0);
if (mStopServiceThread) {
break;
}
switch (mSharedDataPtr->dataType) {
case SharedDataType::BorrowRequest: {
BorrowResponseData responseData = {};
HandleBorrowRequest(&responseData);
mSharedDataPtr->dataType = SharedDataType::BorrowResponse;
mSharedDataPtr->data.borrowResponse = responseData;
MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
break;
}
case SharedDataType::PresentRequest: {
PresentResponseData responseData = {};
HandlePresentRequest(&responseData);
mSharedDataPtr->dataType = SharedDataType::PresentResponse;
mSharedDataPtr->data.presentResponse = responseData;
MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
break;
}
default:
break;
};
}
}
void Provider::HandleBorrowRequest(BorrowResponseData* aResponseData) {
MOZ_ASSERT(aResponseData);
aResponseData->result = ResponseResult::Error;
RECT clientRect = {};
if (!::GetClientRect(mWindowHandle, &clientRect)) {
return;
}
MOZ_ASSERT(clientRect.left == 0);
MOZ_ASSERT(clientRect.top == 0);
int32_t width = clientRect.right ? clientRect.right : 1;
int32_t height = clientRect.bottom ? clientRect.bottom : 1;
bool needNewBackbuffer = !mBackbuffer || (mBackbuffer->GetWidth() != width) ||
(mBackbuffer->GetHeight() != height);
if (!needNewBackbuffer) {
aResponseData->result = ResponseResult::BorrowSameBuffer;
return;
}
mBackbuffer.reset();
mBackbuffer = std::make_unique<PresentableSharedImage>();
if (!mBackbuffer->Initialize(width, height)) {
return;
}
HANDLE remoteFileMapping =
mBackbuffer->CreateRemoteFileMapping(mTargetProcessId);
if (!remoteFileMapping) {
return;
}
aResponseData->result = ResponseResult::BorrowSuccess;
aResponseData->width = width;
aResponseData->height = height;
aResponseData->fileMapping = remoteFileMapping;
}
void Provider::HandlePresentRequest(PresentResponseData* aResponseData) {
MOZ_ASSERT(aResponseData);
aResponseData->result = ResponseResult::Error;
if (!mBackbuffer) {
return;
}
if (!mBackbuffer->PresentToWindow(mWindowHandle)) {
return;
}
aResponseData->result = ResponseResult::PresentSuccess;
}
Client::Client()
: mFileMapping(nullptr),
mRequestReadyEvent(nullptr),
mResponseReadyEvent(nullptr),
mSharedDataPtr(nullptr),
mBackbuffer() {}
Client::~Client() {
mBackbuffer.reset();
if (mSharedDataPtr) {
MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
}
if (mResponseReadyEvent) {
MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
}
if (mRequestReadyEvent) {
MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
}
if (mFileMapping) {
MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
}
}
bool Client::Initialize(const RemoteBackbufferHandles& aRemoteHandles) {
MOZ_ASSERT(aRemoteHandles.fileMapping());
MOZ_ASSERT(aRemoteHandles.requestReadyEvent());
MOZ_ASSERT(aRemoteHandles.responseReadyEvent());
mFileMapping = reinterpret_cast<HANDLE>(aRemoteHandles.fileMapping());
mRequestReadyEvent =
reinterpret_cast<HANDLE>(aRemoteHandles.requestReadyEvent());
mResponseReadyEvent =
reinterpret_cast<HANDLE>(aRemoteHandles.responseReadyEvent());
void* mappedFilePtr =
::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
0 /*offsetLow*/, 0 /*bytesToMap*/);
if (!mappedFilePtr) {
return false;
}
mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
return true;
}
already_AddRefed<gfx::DrawTarget> Client::BorrowDrawTarget() {
mSharedDataPtr->dataType = SharedDataType::BorrowRequest;
MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
WAIT_OBJECT_0);
if (mSharedDataPtr->dataType != SharedDataType::BorrowResponse) {
return nullptr;
}
BorrowResponseData responseData = mSharedDataPtr->data.borrowResponse;
if ((responseData.result != ResponseResult::BorrowSameBuffer) &&
(responseData.result != ResponseResult::BorrowSuccess)) {
return nullptr;
}
if (responseData.result == ResponseResult::BorrowSuccess) {
mBackbuffer.reset();
mBackbuffer = std::make_unique<SharedImage>();
if (!mBackbuffer->InitializeRemote(responseData.width, responseData.height,
responseData.fileMapping)) {
return nullptr;
}
}
return mBackbuffer->CreateDrawTarget();
}
bool Client::PresentDrawTarget() {
mSharedDataPtr->dataType = SharedDataType::PresentRequest;
MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
WAIT_OBJECT_0);
if (mSharedDataPtr->dataType != SharedDataType::PresentResponse) {
return false;
}
if (mSharedDataPtr->data.presentResponse.result !=
ResponseResult::PresentSuccess) {
return false;
}
return true;
}
} // namespace remote_backbuffer
} // namespace widget
} // namespace mozilla

Просмотреть файл

@ -1,81 +0,0 @@
/* -*- 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/. */
#ifndef widget_windows_RemoteBackbuffer_h
#define widget_windows_RemoteBackbuffer_h
#include <thread>
#include <windows.h>
#include "mozilla/Maybe.h"
namespace mozilla {
namespace widget {
namespace remote_backbuffer {
struct SharedData;
struct BorrowResponseData;
struct PresentResponseData;
class SharedImage;
class PresentableSharedImage;
class Provider {
public:
Provider();
~Provider();
bool Initialize(HWND aWindowHandle, DWORD aTargetProcessId);
Maybe<RemoteBackbufferHandles> CreateRemoteHandles();
Provider(const Provider&) = delete;
Provider(Provider&&) = delete;
Provider& operator=(const Provider&) = delete;
Provider& operator=(Provider&&) = delete;
private:
void ThreadMain();
void HandleBorrowRequest(BorrowResponseData* aResponseData);
void HandlePresentRequest(PresentResponseData* aResponseData);
HWND mWindowHandle;
DWORD mTargetProcessId;
HANDLE mFileMapping;
HANDLE mRequestReadyEvent;
HANDLE mResponseReadyEvent;
SharedData* mSharedDataPtr;
bool mStopServiceThread;
std::thread mServiceThread;
std::unique_ptr<PresentableSharedImage> mBackbuffer;
};
class Client {
public:
Client();
~Client();
bool Initialize(const RemoteBackbufferHandles& aRemoteHandles);
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget();
bool PresentDrawTarget();
Client(const Client&) = delete;
Client(Client&&) = delete;
Client& operator=(const Client&) = delete;
Client& operator=(Client&&) = delete;
private:
HANDLE mFileMapping;
HANDLE mRequestReadyEvent;
HANDLE mResponseReadyEvent;
SharedData* mSharedDataPtr;
std::unique_ptr<SharedImage> mBackbuffer;
};
} // namespace remote_backbuffer
} // namespace widget
} // namespace mozilla
#endif // widget_windows_RemoteBackbuffer_h

Просмотреть файл

@ -68,7 +68,6 @@ UNIFIED_SOURCES += [
'nsWindowGfx.cpp',
'nsWinGesture.cpp',
'ProcInfo.cpp',
'RemoteBackbuffer.cpp',
'ScreenHelperWin.cpp',
'TaskbarPreview.cpp',
'TaskbarPreviewButton.cpp',