Skip to content

Commit

Permalink
Bug 1587942 - Forwarding keyboard show/hide events to VR host API. r=…
Browse files Browse the repository at this point in the history
…thomasmo,PhilipLamb,masayuki,imanol

Forwarding keyboard focus/blur events to VR browser that runs at another process. We will need to set these events in VR shmem, then VR host can receive these states from other process.

Differential Revision: https://phabricator.services.mozilla.com/D48903

--HG--
extra : moz-landing-system : lando
  • Loading branch information
daoshengmu committed Oct 18, 2019
1 parent e7fd10b commit 183d99c
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 21 deletions.
14 changes: 14 additions & 0 deletions gfx/vr/FxRWindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "nsPIDOMWindow.h"
#include "mozilla/ClearOnShutdown.h"

#include "nsWindow.h"

static mozilla::StaticAutoPtr<FxRWindowManager> sFxrWinMgrInstance;

FxRWindowManager* FxRWindowManager::GetInstance() {
Expand All @@ -34,3 +36,15 @@ void FxRWindowManager::AddWindow(nsPIDOMWindowOuter* aWindow) {
bool FxRWindowManager::IsFxRWindow(uint64_t aOuterWindowID) {
return (mWindow != nullptr) && (mWindow->WindowID() == aOuterWindowID);
}

// Returns true if the window was created for Firefox Reality
bool FxRWindowManager::IsFxRWindow(const nsWindow* aWindow) const {
return (mWindow != nullptr) &&
(aWindow ==
mozilla::widget::WidgetUtils::DOMWindowToWidget(mWindow).take());
}

uint64_t FxRWindowManager::GetWindowID() const {
MOZ_ASSERT(mWindow);
return mWindow->WindowID();
}
3 changes: 3 additions & 0 deletions gfx/vr/FxRWindowManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <cstdint>

class nsPIDOMWindowOuter;
class nsWindow;

// FxRWindowManager is a singleton that is responsible for tracking all of
// the top-level windows created for Firefox Reality on Desktop. Only a
Expand All @@ -17,6 +18,8 @@ class FxRWindowManager final {

void AddWindow(nsPIDOMWindowOuter* aWindow);
bool IsFxRWindow(uint64_t aOuterWindowID);
bool IsFxRWindow(const nsWindow* aWindow) const;
uint64_t GetWindowID() const;

private:
FxRWindowManager();
Expand Down
51 changes: 46 additions & 5 deletions gfx/vr/VRShMem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@

using namespace mozilla::gfx;

// TODO: we might need to use different names for the mutexes
// and mapped files if we have both release and nightlies
// running at the same time? Or...what if we have multiple
// release builds running on same machine? (Bug 1563232)
#define SHMEM_VERSION "0.0.2"
#ifdef XP_WIN
static const char* kShmemName = "moz.gecko.vr_ext." SHMEM_VERSION;
static LPCTSTR kMutexName = TEXT("mozilla::vr::ShmemMutex" SHMEM_VERSION);
Expand Down Expand Up @@ -649,3 +644,49 @@ void VRShMem::PullWindowState(VRWindowState& aState) {
}
#endif // defined(XP_WIN)
}

void VRShMem::SendIMEState(uint64_t aWindowID,
mozilla::gfx::VRFxIMEState aImeState) {
MOZ_ASSERT(!HasExternalShmem());
if (JoinShMem()) {
mozilla::gfx::VRWindowState windowState = {0};
PullWindowState(windowState);
windowState.windowID = aWindowID;
windowState.eventType = mozilla::gfx::VRFxEventType::FxEvent_IME;
windowState.imeState = aImeState;
PushWindowState(windowState);
LeaveShMem();

#if defined(XP_WIN)
// Notify the waiting host process that the data is now available
HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess
FALSE, // bInheritHandle
windowState.signalName // lpName
);
::SetEvent(hSignal);
::CloseHandle(hSignal);
#endif // defined(XP_WIN)
}
}

// Note: this should be called from the VRShMem instance that created
// the external shmem rather than joined it.
void VRShMem::SendShutdowmState(uint64_t aWindowID) {
MOZ_ASSERT(HasExternalShmem());

mozilla::gfx::VRWindowState windowState = {0};
PullWindowState(windowState);
windowState.windowID = aWindowID;
windowState.eventType = mozilla::gfx::VRFxEventType::FxEvent_SHUTDOWN;
PushWindowState(windowState);

#if defined(XP_WIN)
// Notify the waiting host process that the data is now available
HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess
FALSE, // bInheritHandle
windowState.signalName // lpName
);
::SetEvent(hSignal);
::CloseHandle(hSignal);
#endif // defined(XP_WIN)
}
3 changes: 3 additions & 0 deletions gfx/vr/VRShMem.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class VRShMem final {
void PushWindowState(VRWindowState& aState);
void PullWindowState(VRWindowState& aState);

void SendIMEState(uint64_t aWindowID, mozilla::gfx::VRFxIMEState aImeState);
void SendShutdowmState(uint64_t aWindowID);

bool HasExternalShmem() const { return mExternalShmem != nullptr; }
bool IsSharedExternalShmem() const { return mIsSharedExternalShmem; }
volatile VRExternalShmem* GetExternalShmem() const;
Expand Down
22 changes: 21 additions & 1 deletion gfx/vr/external_api/moz_external_vr.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,15 @@ enum class GamepadCapabilityFlags : uint16_t;
#endif // MOZILLA_INTERNAL_API
namespace gfx {

static const int32_t kVRExternalVersion = 9;
// If there is any change of "SHMEM_VERSION" or "kVRExternalVersion",
// we need to change both of them at the same time.

// TODO: we might need to use different names for the mutexes
// and mapped files if we have both release and nightlies
// running at the same time? Or...what if we have multiple
// release builds running on same machine? (Bug 1563232)
#define SHMEM_VERSION "0.0.3"
static const int32_t kVRExternalVersion = 10;

// We assign VR presentations to groups with a bitmask.
// Currently, we will only display either content or chrome.
Expand Down Expand Up @@ -430,13 +438,25 @@ struct VRSystemState {
VRControllerState controllerState[kVRControllerMaxCount];
};

enum class VRFxEventType : uint8_t {
FxEvent_NONE = 0,
FxEvent_IME,
FxEvent_SHUTDOWN,
FxEvent_TOTAL
};

enum class VRFxIMEState : uint8_t { Blur, Focus };

// Data shared via shmem for running Firefox in a VR windowed environment
struct VRWindowState {
// State from Firefox
uint64_t hwndFx;
uint32_t widthFx;
uint32_t heightFx;
VRLayerTextureHandle textureFx;
uint32_t windowID;
VRFxEventType eventType;
VRFxIMEState imeState;

// State from VRHost
uint32_t dxgiAdapterHost;
Expand Down
5 changes: 5 additions & 0 deletions gfx/vr/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['NIGHTLY_BUILD']:
]

if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'/layout/generic',
'/widget',
'/widget/windows'
]
SOURCES += [
'FxROutputHandler.cpp',
'FxRWindowManager.cpp'
Expand Down
1 change: 1 addition & 0 deletions gfx/vr/vrhost/vrhost.def
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ EXPORTS
CreateVRWindow PRIVATE
CloseVRWindow PRIVATE
SendUIMessageToVRWindow PRIVATE
WaitForVREvent PRIVATE
102 changes: 90 additions & 12 deletions gfx/vr/vrhost/vrhostapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ class VRWindowManager {
}
}

uint32_t GetId(HWND hwnd) {
if (hwnd == hWindow) {
return nWindow;
} else {
return 0;
}
}

HANDLE GetProc(uint32_t nId) {
if (nId == nWindow) {
return hProc;
Expand All @@ -36,11 +44,14 @@ class VRWindowManager {
}
}

uint32_t SetHWND(HWND hwnd, HANDLE hproc) {
HANDLE GetEvent() { return hEvent; }

uint32_t SetHWND(HWND hwnd, HANDLE hproc, HANDLE hevent) {
if (hWindow == nullptr) {
MOZ_ASSERT(hwnd != nullptr && hproc != nullptr);
hWindow = hwnd;
hProc = hproc;
hEvent = hevent;
nWindow = GetRandomUInt();
#if defined(DEBUG) && defined(NIGHTLY_BUILD)
printf("VRWindowManager: Storing HWND: 0x%p as ID: 0x%X\n", hWindow,
Expand Down Expand Up @@ -69,6 +80,7 @@ class VRWindowManager {
uint32_t nWindow = 0;
HWND hWindow = nullptr;
HANDLE hProc = nullptr;
HANDLE hEvent = nullptr;
std::random_device randomGenerator;
};
VRWindowManager* VRWindowManager::Instance = nullptr;
Expand Down Expand Up @@ -118,6 +130,17 @@ DWORD StartFirefoxThreadProc(_In_ LPVOID lpParameter) {
return 0;
}

class VRShmemInstance {
public:
VRShmemInstance() = delete;
VRShmemInstance(const VRShmemInstance& aRHS) = delete;

static mozilla::gfx::VRShMem& GetInstance() {
static mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
return shmem;
}
};

// This export is responsible for starting up a new VR window in Firefox and
// returning data related to its creation back to the caller.
// See nsFxrCommandLineHandler::Handle for more details about the bootstrapping
Expand All @@ -134,15 +157,15 @@ void CreateVRWindow(char* firefoxFolderPath, char* firefoxProfilePath,

if (err > 0) {
HANDLE hEvent = ::CreateEventA(nullptr, // attributes
TRUE, // bManualReset
FALSE, // bManualReset
FALSE, // bInitialState
windowState.signalName);

if (hEvent != nullptr) {
// Create Shmem and push state
mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
shmem.CreateShMem(true /*aCreateOnSharedMemory*/);
shmem.PushWindowState(windowState);
VRShmemInstance::GetInstance().CreateShMem(
true /*aCreateOnSharedMemory*/);
VRShmemInstance::GetInstance().PushWindowState(windowState);

// Start Firefox in another thread so that this thread can wait for the
// window state to be updated during Firefox startup
Expand All @@ -157,24 +180,68 @@ void CreateVRWindow(char* firefoxFolderPath, char* firefoxProfilePath,
::WaitForSingleObject(hEvent, INFINITE);

// Update local WindowState with data from Firefox
shmem.PullWindowState(windowState);
VRShmemInstance::GetInstance().PullWindowState(windowState);

(*hTex) = windowState.textureFx;
(*windowId) = VRWindowManager::GetManager()->SetHWND(
(HWND)windowState.hwndFx, fxParams.hProcessFx);
(HWND)windowState.hwndFx, fxParams.hProcessFx, hEvent);
(*width) = windowState.widthFx;
(*height) = windowState.heightFx;

// Neither the Shmem nor its window state are needed anymore
windowState = {0};
shmem.PushWindowState(windowState);
} else {
// How do I failfast?
}
}
}
}

shmem.CloseShMem();
// Keep track of when WaitForVREvent is running to manage shutdown of
// this vrhost. See CloseVRWindow for more details.
volatile bool s_WaitingForVREvent = false;

// Blocks until a new event is set on the shmem.
// Note: this function can be called from any thread.
void WaitForVREvent(uint32_t& nVRWindowID, uint32_t& eventType,
uint32_t& eventData1, uint32_t& eventData2) {
MOZ_ASSERT(!s_WaitingForVREvent);
s_WaitingForVREvent = true;

// Initialize all of the out params
nVRWindowID = 0;
eventType = 0;
eventData1 = 0;
eventData2 = 0;

if (VRShmemInstance::GetInstance().HasExternalShmem()) {
HANDLE evt = VRWindowManager::GetManager()->GetEvent();
const DWORD waitResult = ::WaitForSingleObject(evt, INFINITE);
if (waitResult != WAIT_OBJECT_0) {
MOZ_ASSERT(false && "Error WaitForVREvent().\n");
return;
}
mozilla::gfx::VRWindowState windowState = {0};
VRShmemInstance::GetInstance().PullWindowState(windowState);

nVRWindowID =
VRWindowManager::GetManager()->GetId((HWND)windowState.hwndFx);
if (nVRWindowID != 0) {
eventType = (uint32_t)windowState.eventType;
mozilla::gfx::VRFxEventType fxEvent =
mozilla::gfx::VRFxEventType(eventType);

switch (fxEvent) {
case mozilla::gfx::VRFxEventType::FxEvent_IME:
eventData1 = (uint32_t)windowState.imeState;
break;
case mozilla::gfx::VRFxEventType::FxEvent_SHUTDOWN:
VRShmemInstance::GetInstance().CloseShMem();
break;
default:
MOZ_ASSERT(false && "Undefined VR Fx event.");
break;
}
}
}
s_WaitingForVREvent = false;
}

// Sends a message to the VR window to close.
Expand All @@ -189,6 +256,17 @@ void CloseVRWindow(uint32_t nVRWindowID, bool waitForTerminate) {
INFINITE);
}
}

// If a thread is currently blocked on WaitForVREvent, then defer closing the
// shmem to that thread by sending an async event.
// If WaitForVREvent is not running, it is safe to close the shmem now.
// Subsequent calls to WaitForVREvent will return early because it does not
// have an external shmem.
if (s_WaitingForVREvent) {
VRShmemInstance::GetInstance().SendShutdowmState(nVRWindowID);
} else {
VRShmemInstance::GetInstance().CloseShMem();
}
}

// Forwards Win32 UI window messages to the Firefox widget/window associated
Expand Down
3 changes: 3 additions & 0 deletions gfx/vr/vrhost/vrhostex.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ typedef void (*PFN_CLOSEVRWINDOW)(uint32_t nVRWindowID, bool waitForTerminate);

typedef void (*PFN_SENDUIMSG)(uint32_t nVRWindowID, uint32_t msg,
uint64_t wparam, uint64_t lparam);

typedef void (*PFN_WAITFORVREVENT)(uint32_t& nVRWindowID, uint32_t& eventType,
uint32_t& eventData1, uint32_t& eventData2);
1 change: 1 addition & 0 deletions gfx/vr/vrhost/vrhostnightly.def
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ EXPORTS
CreateVRWindow PRIVATE
CloseVRWindow PRIVATE
SendUIMessageToVRWindow PRIVATE
WaitForVREvent PRIVATE

;+= Exports only available in Nightlies for testing
SampleExport PRIVATE
Expand Down
Loading

0 comments on commit 183d99c

Please sign in to comment.