Communicate GPU process device information across processes. (bug 1294988 part 5, r=mattwoodrow)

This commit is contained in:
David Anderson 2016-08-20 20:59:11 -07:00
parent 396d5d1191
commit 2e46480cbf
16 changed files with 238 additions and 9 deletions

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxConfig.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/GraphicsMessages.h"
#include "plstr.h"
namespace mozilla {
@ -250,13 +251,28 @@ gfxConfig::ForEachFallbackImpl(const FallbackIterCallback& aCallback)
}
}
/* static */ const nsACString&
/* static */ const nsCString&
gfxConfig::GetFailureId(Feature aFeature)
{
const FeatureState& state = sConfig->GetState(aFeature);
return state.GetFailureId();
}
/* static */ void
gfxConfig::ImportChange(Feature aFeature, const FeatureChange& aChange)
{
if (aChange.type() == FeatureChange::Tnull_t) {
return;
}
const FeatureFailure& failure = aChange.get_FeatureFailure();
gfxConfig::SetFailed(
aFeature,
failure.status(),
failure.message().get(),
failure.failureId());
}
/* static */ void
gfxConfig::Init()
{

View File

@ -14,6 +14,9 @@
namespace mozilla {
namespace gfx {
// Defined in GraphicsMessages.ipdlh.
class FeatureChange;
// Manages the history and state of a graphics feature. The flow of a feature
// is:
// - A default value, set by all.js, gfxPrefs, or gfxPlatform.
@ -44,6 +47,9 @@ public:
// IsDisabledByDefault returns whether or not the initial status of the
// feature, before adding user prefs and runtime decisions, was disabled.
static bool IsForcedOnByUser(Feature aFeature);
// This returns true if the feature was disabled by default, or was never
// initialized to begin with.
static bool IsDisabledByDefault(Feature aFeature);
// Query the status value of a parameter. This is computed similar to
@ -173,7 +179,9 @@ public:
static void ForEachFallback(const FallbackIterCallback& aCallback);
// Get the most descriptive failure id message for this feature.
static const nsACString& GetFailureId(Feature aFeature);
static const nsCString& GetFailureId(Feature aFeature);
static void ImportChange(Feature aFeature, const FeatureChange& aChange);
static void Init();
static void Shutdown();

View File

@ -160,7 +160,6 @@ FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
bool
FeatureState::DisabledByDefault() const
{
AssertInitialized();
return mDefault.mStatus != FeatureStatus::Available;
}
@ -256,7 +255,33 @@ FeatureState::SetFailureId(const nsACString& aFailureId)
}
}
const nsACString&
const char*
FeatureState::GetFailureMessage() const
{
AssertInitialized();
MOZ_ASSERT(!IsEnabled());
if (mRuntime.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mRuntime.mStatus))
{
return mRuntime.mMessage;
}
if (mEnvironment.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mEnvironment.mStatus))
{
return mEnvironment.mMessage;
}
if (mUser.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mUser.mStatus))
{
return mUser.mMessage;
}
MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
return mDefault.mMessage;
}
const nsCString&
FeatureState::GetFailureId() const
{
MOZ_ASSERT(!IsEnabled());

View File

@ -68,14 +68,16 @@ class FeatureState
const char* aMessage)> StatusIterCallback;
void ForEachStatusChange(const StatusIterCallback& aCallback) const;
const nsACString& GetFailureId() const;
const char* GetFailureMessage() const;
const nsCString& GetFailureId() const;
bool DisabledByDefault() const;
private:
void SetUser(FeatureStatus aStatus, const char* aMessage);
void SetEnvironment(FeatureStatus aStatus, const char* aMessage);
void SetRuntime(FeatureStatus aStatus, const char* aMessage);
bool IsForcedOnByUser() const;
bool DisabledByDefault() const;
const char* GetRuntimeMessage() const;
bool IsInitialized() const {
return mDefault.IsInitialized();

View File

@ -8,12 +8,16 @@
#include "gfxPrefs.h"
#include "GPUProcessHost.h"
#include "mozilla/gfx/gfxVars.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerD3D11.h"
#endif
namespace mozilla {
namespace gfx {
GPUChild::GPUChild(GPUProcessHost* aHost)
: mHost(aHost)
: mHost(aHost),
mGPUReady(false)
{
MOZ_COUNT_CTOR(GPUChild);
}
@ -62,6 +66,33 @@ GPUChild::OnVarChanged(const GfxVarUpdate& aVar)
SendUpdateVar(aVar);
}
void
GPUChild::EnsureGPUReady()
{
if (mGPUReady) {
return;
}
GPUDeviceData data;
SendGetDeviceStatus(&data);
gfxPlatform::GetPlatform()->ImportGPUDeviceData(data);
mGPUReady = true;
}
bool
GPUChild::RecvInitComplete(const GPUDeviceData& aData)
{
// We synchronously requested GPU parameters before this arrived.
if (mGPUReady) {
return true;
}
gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
mGPUReady = true;
return true;
}
void
GPUChild::ActorDestroy(ActorDestroyReason aWhy)
{

View File

@ -26,16 +26,20 @@ public:
void Init();
void EnsureGPUReady();
// gfxVarReceiver overrides.
void OnVarChanged(const GfxVarUpdate& aVar) override;
// PGPUChild overrides.
bool RecvInitComplete(const GPUDeviceData& aData) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
static void Destroy(UniquePtr<GPUChild>&& aChild);
private:
GPUProcessHost* mHost;
bool mGPUReady;
};
} // namespace gfx

View File

@ -84,6 +84,11 @@ GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
}
#endif
// Send a message to the UI process that we're done.
GPUDeviceData data;
RecvGetDeviceStatus(&data);
Unused << SendInitComplete(data);
return true;
}
@ -123,6 +128,43 @@ GPUParent::RecvUpdateVar(const GfxVarUpdate& aUpdate)
return true;
}
static void
CopyFeatureChange(Feature aFeature, FeatureChange* aOut)
{
FeatureState& feature = gfxConfig::GetFeature(aFeature);
if (feature.DisabledByDefault() || feature.IsEnabled()) {
// No change:
// - Disabled-by-default means the parent process told us not to use this feature.
// - Enabled means we were told to use this feature, and we didn't discover anything
// that would prevent us from doing so.
*aOut = null_t();
return;
}
MOZ_ASSERT(!feature.IsEnabled());
nsCString message;
message.AssignASCII(feature.GetFailureMessage());
*aOut = FeatureFailure(feature.GetValue(), message, feature.GetFailureId());
}
bool
GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut)
{
CopyFeatureChange(Feature::D3D11_COMPOSITING, &aOut->d3d11Compositing());
CopyFeatureChange(Feature::D3D9_COMPOSITING, &aOut->d3d9Compositing());
CopyFeatureChange(Feature::OPENGL_COMPOSITING, &aOut->oglCompositing());
#if defined(XP_WIN)
if (DeviceManagerD3D11* dm = DeviceManagerD3D11::Get()) {
dm->ExportDeviceInfo(&aOut->d3d11Device());
}
#endif
return true;
}
static void
OpenParent(RefPtr<CompositorBridgeParent> aParent,
Endpoint<PCompositorBridgeParent>&& aEndpoint)

View File

@ -42,6 +42,7 @@ public:
bool RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
bool RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
bool RecvDeallocateLayerTreeId(const uint64_t& aLayersId) override;
bool RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
void ActorDestroy(ActorDestroyReason aWhy) override;

View File

@ -134,6 +134,10 @@ GPUProcessManager::EnsureGPUReady()
return;
}
}
if (mGPUChild) {
mGPUChild->EnsureGPUReady();
}
}
void
@ -143,6 +147,8 @@ GPUProcessManager::EnsureImageBridgeChild()
return;
}
EnsureGPUReady();
if (!mGPUChild) {
ImageBridgeChild::InitSameProcess();
return;
@ -171,6 +177,8 @@ GPUProcessManager::EnsureVRManager()
return;
}
EnsureGPUReady();
if (!mGPUChild) {
VRManagerChild::InitSameProcess();
return;
@ -288,6 +296,7 @@ GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
{
uint64_t layerTreeId = AllocateLayerTreeId();
EnsureGPUReady();
EnsureImageBridgeChild();
EnsureVRManager();
@ -391,6 +400,8 @@ bool
GPUProcessManager::CreateContentCompositorBridge(base::ProcessId aOtherProcess,
ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint)
{
EnsureGPUReady();
ipc::Endpoint<PCompositorBridgeParent> parentPipe;
ipc::Endpoint<PCompositorBridgeChild> childPipe;

View File

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using struct DxgiAdapterDesc from "mozilla/D3DMessageUtils.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using mozilla::gfx::FeatureStatus from "gfxTelemetry.h";
using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
@ -35,6 +36,30 @@ struct ContentDeviceData
D3D11DeviceStatus d3d11;
};
// Represents the state of a feature that has failed to initialize.
struct FeatureFailure
{
FeatureStatus status;
nsCString message;
nsCString failureId;
};
// If a feature state has changed from Enabled -> Failure, this will be non-
// null.
union FeatureChange
{
null_t;
FeatureFailure;
};
struct GPUDeviceData
{
FeatureChange d3d11Compositing;
FeatureChange d3d9Compositing;
FeatureChange oglCompositing;
D3D11DeviceStatus d3d11Device;
};
union GfxVarValue
{
BackendType;

View File

@ -57,6 +57,15 @@ parent:
async NewContentVRManager(Endpoint<PVRManagerParent> endpoint);
async DeallocateLayerTreeId(uint64_t layersId);
// Request the current DeviceStatus from the GPU process. This blocks until
// one is available (i.e., Init has completed).
sync GetDeviceStatus() returns (GPUDeviceData status);
child:
// Sent when the GPU process has initialized devices. This occurs once, after
// Init().
async InitComplete(GPUDeviceData data);
};
} // namespace gfx

View File

@ -142,8 +142,10 @@ DeviceManagerD3D11::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus)
void
DeviceManagerD3D11::ExportDeviceInfo(D3D11DeviceStatus* aOut)
{
MOZ_ASSERT(ProcessOwnsCompositor());
MOZ_ASSERT(!!mCompositorDevice == !!mDeviceStatus);
// Even though the parent process might not own the compositor, we still
// populate DeviceManagerD3D11 with device statistics (for simplicity).
// That means it still gets queried for compositor information.
MOZ_ASSERT(XRE_IsParentProcess() || XRE_GetProcessType() == GeckoProcessType_GPU);
if (mDeviceStatus) {
*aOut = mDeviceStatus.value();

View File

@ -2447,10 +2447,22 @@ void
gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut)
{
MOZ_ASSERT(XRE_IsParentProcess());
// Make sure our settings are synchronized from the GPU process.
GPUProcessManager::Get()->EnsureGPUReady();
aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
}
void
gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
{
MOZ_ASSERT(XRE_IsParentProcess());
gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
}
bool
gfxPlatform::SupportsApzDragInput() const
{

View File

@ -52,6 +52,7 @@ class ScaledFont;
class DrawEventRecorder;
class VsyncSource;
class ContentDeviceData;
class GPUDeviceData;
inline uint32_t
BackendTypeBit(BackendType b)
@ -674,6 +675,12 @@ public:
*/
virtual void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut);
/**
* Imports settings from the GPU process. This should only be called through
* GPUProcessManager, in the UI process.
*/
virtual void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData);
protected:
gfxPlatform();
virtual ~gfxPlatform();

View File

@ -2029,6 +2029,39 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aB
}
}
void
gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
{
MOZ_ASSERT(XRE_IsParentProcess());
gfxPlatform::ImportGPUDeviceData(aData);
gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing());
gfxConfig::ImportChange(Feature::D3D9_COMPOSITING, aData.d3d9Compositing());
DeviceManagerD3D11* dm = DeviceManagerD3D11::Get();
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
dm->ImportDeviceInfo(aData.d3d11Device());
} else {
// There should be no devices, so this just takes away the device status.
dm->ResetDevices();
// Make sure we disable D2D if content processes might use it.
FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
if (d2d1.IsEnabled()) {
d2d1.SetFailed(
FeatureStatus::Unavailable,
"Direct2D requires Direct3D 11 compositing",
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
}
}
// For completeness (and messaging in about:support). Content recomputes this
// on its own, and we won't use ANGLE in the UI process if we're using a GPU
// process.
UpdateANGLEConfig();
}
void
gfxWindowsPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
{

View File

@ -252,6 +252,7 @@ protected:
void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends) override;
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override;
void ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) override;
void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut) override;