/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
DCForMetrics::DCForMetrics() { // Get the whole screen DC:
mDC = GetDC(nullptr);
SetGraphicsMode(mDC, GM_ADVANCED);
}
class GfxD2DVramReporter final : public nsIMemoryReporter {
~GfxD2DVramReporter() {}
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) override {
MOZ_COLLECT_REPORT("gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
Factory::GetD2DVRAMUsageDrawTarget(), "Video memory used by D2D DrawTargets.");
MOZ_COLLECT_REPORT("gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES,
Factory::GetD2DVRAMUsageSourceSurface(), "Video memory used by D2D SourceSurfaces.");
class GPUAdapterReporter final : public nsIMemoryReporter { // Callers must Release the DXGIAdapter after use or risk mem-leak staticbool GetDXGIAdapter(IDXGIAdapter** aDXGIAdapter) {
RefPtr<ID3D11Device> d3d11Device;
RefPtr<IDXGIDevice> dxgiDevice; bool result = false;
if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) { if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice),
getter_AddRefs(dxgiDevice)) == S_OK) {
result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
}
}
MOZ_COLLECT_REPORT("gpu-committed", KIND_OTHER, UNITS_BYTES,
committedBytesUsed, "Memory committed by the Windows graphics system.");
MOZ_COLLECT_REPORT( "gpu-dedicated", KIND_OTHER, UNITS_BYTES, dedicatedBytesUsed, "Out-of-process memory allocated for this process in a physical " "GPU adapter's memory.");
MOZ_COLLECT_REPORT("gpu-shared", KIND_OTHER, UNITS_BYTES, sharedBytesUsed, "In-process memory that is shared with the GPU.");
gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) { // If win32k is locked down then we can't use COM STA and shouldn't need it. // Also, we won't be using any GPU memory in this process. if (!IsWin32kLockedDown()) { /* * Initialize COM
*/
CoInitialize(nullptr);
/* static */
nsresult gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(
uint64_t* aResult) { // If win32k is locked down then we should not have any GPU processing and // cannot use these APIs either way. if (IsWin32kLockedDown()) {
*aResult = 0; return NS_OK;
}
nsModuleHandle module(LoadLibrary(L"gdi32.dll")); if (!module) { return NS_ERROR_NOT_AVAILABLE;
}
gfx::DeviceManagerDx* dm = DeviceManagerDx::Get(); if (!dm) { return NS_ERROR_NOT_AVAILABLE;
}
D3D11DeviceStatus status; if (!dm->ExportDeviceInfo(&status)) { // Assume that we used 0ms of GPU time if the device manager // doesn't know the device status.
*aResult = 0; return NS_OK;
}
InitializeConfig();
InitGPUProcessSupport(); // Ensure devices initialization. SharedSurfaceANGLE and // SharedSurfaceD3D11Interop use them. The devices are lazily initialized // with WebRender to reduce memory usage. // Initialize them now when running non-e10s. if (!BrowserTabsRemoteAutostart()) {
EnsureDevicesInitialized();
}
UpdateANGLEConfig();
UpdateRenderMode();
// If we have Skia and we didn't init dwrite already, do it now. if (!DWriteEnabled() && GetDefaultContentBackend() == BackendType::SKIA) {
InitDWriteSupport();
} // We need to listen for font setting changes even if DWrite is not used.
Factory::SetSystemTextQuality(gfxVars::SystemTextQuality());
gfxVars::SetSystemTextQualityListener(
gfxDWriteFont::SystemTextQualityChanged);
// CanUseHardwareVideoDecoding depends on DeviceManagerDx state, // so update the cached value now.
UpdateCanUseHardwareVideoDecoding();
// Our ScreenHelperWin also depends on DeviceManagerDx state. if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) {
ScreenHelperWin::RefreshScreens();
}
void gfxWindowsPlatform::UpdateBackendPrefs() {
BackendPrefsData data = GetBackendPrefs(); // Remove DIRECT2D1 preference if D2D1Device does not exist. if (!Factory::HasD2D1Device()) {
data.mContentBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1); if (data.mContentDefault == BackendType::DIRECT2D1_1) {
data.mContentDefault = BackendType::SKIA;
}
// Don't exclude DIRECT2D1_1 if using remote canvas, because DIRECT2D1_1 and // hence the device will be used in the GPU process. if (!gfxPlatform::UseRemoteCanvas()) {
data.mCanvasBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1); if (data.mCanvasDefault == BackendType::DIRECT2D1_1) {
data.mCanvasDefault = BackendType::SKIA;
}
}
}
InitBackendPrefs(std::move(data));
}
if (backend == BackendType::DIRECT2D1_1) { if (!gfx::gfxVars::UseWebRenderANGLE()) { // We can't have D2D without ANGLE when WebRender is enabled, so fallback // to Skia. return BackendType::SKIA;
}
// Fall back to software when remote canvas has been deactivated. if (CanvasChild::Deactivated()) { return BackendType::SKIA;
}
} return backend;
}
bool gfxWindowsPlatform::CreatePlatformFontList() { if (DWriteEnabled()) { if (gfxPlatformFontList::Initialize(new gfxDWriteFontList)) { returntrue;
}
// DWrite font initialization failed! Don't know why this would happen, // but apparently it can - see bug 594865. // So we're going to fall back to GDI fonts & rendering.
DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts", "FEATURE_FAILURE_FONT_FAIL"_ns);
}
// Make sure the static variable is initialized...
gfxPlatform::HasVariationFontSupport(); // ...then force it to false, even if the Windows version was recent enough // to permit it, as we're using GDI fonts.
sHasVariationFontSupport = false;
// This function will permanently disable D2D for the session. It's intended to // be used when, after initially chosing to use Direct2D, we encounter a // scenario we can't support. // // This is called during gfxPlatform::Init() so at this point there should be no // DrawTargetD2D/1 instances. void gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, constchar* aMessage, const nsACString& aFailureId) {
gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId);
Factory::SetDirect3D11Device(nullptr);
UpdateBackendPrefs();
}
switch (aRunScript) { case Script::INVALID: case Script::NUM_SCRIPT_CODES: // Ensure the switch covers all the Script enum values.
MOZ_ASSERT_UNREACHABLE("bad script code"); break;
case Script::COMMON: case Script::INHERITED: // In most cases, COMMON and INHERITED characters will be merged into // their context, but if they occur without context, we'll just treat // them like Latin, etc. case Script::LATIN: case Script::CYRILLIC: case Script::GREEK: case Script::ARMENIAN: case Script::HEBREW: // We always append Arial below, so no need to add it here. // aFontList.AppendElement("Arial"); break;
case Script::MATHEMATICAL_NOTATION: case Script::SYMBOLS: case Script::SYMBOLS_EMOJI: // Not currently returned by script run resolution (but some symbols may // be handled below). break;
// CJK-related script codes are a bit troublesome because of unification; // we'll probably just get HAN much of the time, so the choice of which // language font to try for fallback is rather arbitrary. Usually, though, // we hope that font prefs will have handled this earlier. case Script::BOPOMOFO: case Script::HAN_WITH_BOPOMOFO: case Script::SIMPLIFIED_HAN: case Script::HAN:
aFontList.AppendElement("SimSun"); if (aCh > 0xFFFF) {
aFontList.AppendElement("SimSun-ExtB");
} break; // Currently, we don't resolve script runs to this value, but we may do so // in future if we get better at handling things like `lang=zh-Hant`, not // just resolving based on the Unicode text. case Script::TRADITIONAL_HAN:
aFontList.AppendElement("MingLiU"); if (aCh > 0xFFFF) {
aFontList.AppendElement("MingLiU-ExtB");
} break; case Script::HIRAGANA: case Script::KATAKANA: case Script::KATAKANA_OR_HIRAGANA: case Script::JAPANESE:
aFontList.AppendElement("Yu Gothic");
aFontList.AppendElement("MS PGothic"); break; case Script::HANGUL: case Script::JAMO: case Script::KOREAN:
aFontList.AppendElement("Malgun Gothic"); break;
case Script::YI:
aFontList.AppendElement("Microsoft Yi Baiti"); break; case Script::MONGOLIAN:
aFontList.AppendElement("Mongolian Baiti"); break; case Script::TIBETAN:
aFontList.AppendElement("Microsoft Himalaya"); break; case Script::PHAGS_PA:
aFontList.AppendElement("Microsoft PhagsPa"); break;
case Script::ARABIC: // Default to Arial (added unconditionally below) for Arabic script. break; case Script::ARABIC_NASTALIQ:
aFontList.AppendElement("Urdu Typesetting"); break; case Script::SYRIAC: case Script::ESTRANGELO_SYRIAC:
aFontList.AppendElement("Estrangelo Edessa"); break; case Script::THAANA:
aFontList.AppendElement("MV Boli"); break;
case Script::BENGALI:
aFontList.AppendElement("Vrinda");
aFontList.AppendElement("Nirmala UI"); break; case Script::DEVANAGARI:
aFontList.AppendElement("Kokila");
aFontList.AppendElement("Nirmala UI"); break; case Script::GUJARATI:
aFontList.AppendElement("Shruti");
aFontList.AppendElement("Nirmala UI"); break; case Script::GURMUKHI:
aFontList.AppendElement("Raavi");
aFontList.AppendElement("Nirmala UI"); break; case Script::KANNADA:
aFontList.AppendElement("Tunga");
aFontList.AppendElement("Nirmala UI"); break; case Script::MALAYALAM:
aFontList.AppendElement("Kartika");
aFontList.AppendElement("Nirmala UI"); break; case Script::ORIYA:
aFontList.AppendElement("Kalinga");
aFontList.AppendElement("Nirmala UI"); break; case Script::TAMIL:
aFontList.AppendElement("Latha");
aFontList.AppendElement("Nirmala UI"); break; case Script::TELUGU:
aFontList.AppendElement("Gautami");
aFontList.AppendElement("Nirmala UI"); break; case Script::SINHALA:
aFontList.AppendElement("Iskoola Pota");
aFontList.AppendElement("Nirmala UI"); break;
case Script::CHAKMA: case Script::MEETEI_MAYEK: case Script::OL_CHIKI: case Script::SORA_SOMPENG:
aFontList.AppendElement("Nirmala UI"); break;
case Script::MYANMAR:
aFontList.AppendElement("Myanmar Text"); break; case Script::KHMER:
aFontList.AppendElement("Khmer UI"); break; case Script::LAO:
aFontList.AppendElement("Lao UI"); break; case Script::THAI:
aFontList.AppendElement("Tahoma");
aFontList.AppendElement("Leelawadee UI"); break; case Script::TAI_LE:
aFontList.AppendElement("Microsoft Tai Le"); break; case Script::BUGINESE:
aFontList.AppendElement("Leelawadee UI"); break; case Script::NEW_TAI_LUE:
aFontList.AppendElement("Microsoft New Tai Lue"); break; case Script::JAVANESE:
aFontList.AppendElement("Javanese Text"); break;
case Script::GEORGIAN: case Script::KHUTSURI: case Script::LISU:
aFontList.AppendElement("Segoe UI"); break;
case Script::ETHIOPIC:
aFontList.AppendElement("Nyala");
aFontList.AppendElement("Ebrima"); break;
case Script::ADLAM: case Script::NKO: case Script::OSMANYA: case Script::TIFINAGH: case Script::VAI:
aFontList.AppendElement("Ebrima"); break;
case Script::CANADIAN_ABORIGINAL:
aFontList.AppendElement("Euphemia"); break;
case Script::CHEROKEE: case Script::OSAGE:
aFontList.AppendElement("Gadugi"); break;
case Script::BRAILLE: case Script::DESERET:
aFontList.AppendElement("Segoe UI Symbol"); break;
case Script::BRAHMI: case Script::CARIAN: case Script::CUNEIFORM: case Script::CYPRIOT: case Script::EGYPTIAN_HIEROGLYPHS: case Script::GLAGOLITIC: case Script::GOTHIC: case Script::IMPERIAL_ARAMAIC: case Script::INSCRIPTIONAL_PAHLAVI: case Script::INSCRIPTIONAL_PARTHIAN: case Script::KHAROSHTHI: case Script::LYCIAN: case Script::LYDIAN: case Script::MEROITIC_CURSIVE: case Script::OGHAM: case Script::OLD_ITALIC: case Script::OLD_PERSIAN: case Script::OLD_SOUTH_ARABIAN: case Script::OLD_TURKIC: case Script::PHOENICIAN: case Script::RUNIC: case Script::SHAVIAN: case Script::UGARITIC:
aFontList.AppendElement("Segoe UI Historic"); break;
// For some scripts where Windows doesn't supply a font by default, // there are Noto fonts that users might have installed: case Script::AHOM:
aFontList.AppendElement("Noto Serif Ahom"); break; case Script::AVESTAN:
aFontList.AppendElement("Noto Sans Avestan"); break; case Script::BALINESE:
aFontList.AppendElement("Noto Sans Balinese"); break; case Script::BAMUM:
aFontList.AppendElement("Noto Sans Bamum"); break; case Script::BASSA_VAH:
aFontList.AppendElement("Noto Sans Bassa Vah"); break; case Script::BATAK:
aFontList.AppendElement("Noto Sans Batak"); break; case Script::BHAIKSUKI:
aFontList.AppendElement("Noto Sans Bhaiksuki"); break; case Script::BUHID:
aFontList.AppendElement("Noto Sans Buhid"); break; case Script::CAUCASIAN_ALBANIAN:
aFontList.AppendElement("Noto Sans Caucasian Albanian"); break; case Script::CHAM:
aFontList.AppendElement("Noto Sans Cham"); break; case Script::COPTIC:
aFontList.AppendElement("Noto Sans Coptic"); break; case Script::DUPLOYAN:
aFontList.AppendElement("Noto Sans Duployan"); break; case Script::ELBASAN:
aFontList.AppendElement("Noto Sans Elbasan"); break; case Script::GRANTHA:
aFontList.AppendElement("Noto Sans Grantha"); break; case Script::HANIFI_ROHINGYA:
aFontList.AppendElement("Noto Sans Hanifi Rohingya"); break; case Script::HANUNOO:
aFontList.AppendElement("Noto Sans Hanunoo"); break; case Script::HATRAN:
aFontList.AppendElement("Noto Sans Hatran"); break; case Script::KAITHI:
aFontList.AppendElement("Noto Sans Kaithi"); break; case Script::KAYAH_LI:
aFontList.AppendElement("Noto Sans Kayah Li"); break; case Script::KHOJKI:
aFontList.AppendElement("Noto Sans Khojki"); break; case Script::KHUDAWADI:
aFontList.AppendElement("Noto Sans Khudawadi"); break; case Script::LEPCHA:
aFontList.AppendElement("Noto Sans Lepcha"); break; case Script::LIMBU:
aFontList.AppendElement("Noto Sans Limbu"); break; case Script::LINEAR_A:
aFontList.AppendElement("Noto Sans Linear A"); break; case Script::LINEAR_B:
aFontList.AppendElement("Noto Sans Linear B"); break; case Script::MAHAJANI:
aFontList.AppendElement("Noto Sans Mahajani"); break; case Script::MANDAIC:
aFontList.AppendElement("Noto Sans Mandaic"); break; case Script::MANICHAEAN:
aFontList.AppendElement("Noto Sans Manichaean"); break; case Script::MARCHEN:
aFontList.AppendElement("Noto Sans Marchen"); break; case Script::MENDE_KIKAKUI:
aFontList.AppendElement("Noto Sans Mende Kikakui"); break; case Script::MEROITIC_HIEROGLYPHS:
aFontList.AppendElement("Noto Sans Meroitic"); break; case Script::MIAO:
aFontList.AppendElement("Noto Sans Miao"); break; case Script::MODI:
aFontList.AppendElement("Noto Sans Modi"); break; case Script::MRO:
aFontList.AppendElement("Noto Sans Mro"); break; case Script::MULTANI:
aFontList.AppendElement("Noto Sans Multani"); break; case Script::NABATAEAN:
aFontList.AppendElement("Noto Sans Nabataean"); break; case Script::NEWA:
aFontList.AppendElement("Noto Sans Newa"); break; case Script::OLD_HUNGARIAN:
aFontList.AppendElement("Noto Sans Old Hungarian"); break; case Script::OLD_NORTH_ARABIAN:
aFontList.AppendElement("Noto Sans Old North Arabian"); break; case Script::OLD_PERMIC:
aFontList.AppendElement("Noto Sans Old Permic"); break; case Script::PAHAWH_HMONG:
aFontList.AppendElement("Noto Sans Pahawh Hmong"); break; case Script::PALMYRENE:
aFontList.AppendElement("Noto Sans Palmyrene"); break; case Script::PAU_CIN_HAU:
aFontList.AppendElement("Noto Sans Pau Cin Hau"); break; case Script::PSALTER_PAHLAVI:
aFontList.AppendElement("Noto Sans Psalter Pahlavi"); break; case Script::REJANG:
aFontList.AppendElement("Noto Sans Rejang"); break; case Script::SAMARITAN:
aFontList.AppendElement("Noto Sans Samaritan"); break; case Script::SAURASHTRA:
aFontList.AppendElement("Noto Sans Saurashtra"); break; case Script::SHARADA:
aFontList.AppendElement("Noto Sans Sharada"); break; case Script::SIDDHAM:
aFontList.AppendElement("Noto Sans Siddham"); break; case Script::SUNDANESE:
aFontList.AppendElement("Noto Sans Sundanese"); break; case Script::SYLOTI_NAGRI:
aFontList.AppendElement("Noto Sans Syloti Nagri"); break; case Script::TAGALOG:
aFontList.AppendElement("Noto Sans Tagalog"); break; case Script::TAGBANWA:
aFontList.AppendElement("Noto Sans Tagbanwa"); break; case Script::TAI_THAM:
aFontList.AppendElement("Noto Sans Tai Tham"); break; case Script::TAI_VIET:
aFontList.AppendElement("Noto Sans Tai Viet"); break; case Script::TAKRI:
aFontList.AppendElement("Noto Sans Takri"); break; case Script::TIRHUTA:
aFontList.AppendElement("Noto Sans Tirhuta"); break; case Script::WANCHO:
aFontList.AppendElement("Noto Sans Wancho"); break; case Script::WARANG_CITI:
aFontList.AppendElement("Noto Sans Warang Citi"); break;
case Script::AFAKA: case Script::ANATOLIAN_HIEROGLYPHS: case Script::BLISSYMBOLS: case Script::BOOK_PAHLAVI: case Script::CHORASMIAN: case Script::CIRTH: case Script::CYPRO_MINOAN: case Script::DEMOTIC_EGYPTIAN: case Script::DIVES_AKURU: case Script::DOGRA: case Script::EASTERN_SYRIAC: case Script::ELYMAIC: case Script::GARAY: case Script::GUNJALA_GONDI: case Script::GURUNG_KHEMA: case Script::HARAPPAN_INDUS: case Script::HIERATIC_EGYPTIAN: case Script::JURCHEN: case Script::KAWI: case Script::KHITAN_SMALL_SCRIPT: case Script::KIRAT_RAI: case Script::KPELLE: case Script::LATIN_FRAKTUR: case Script::LATIN_GAELIC: case Script::LOMA: case Script::MAKASAR: case Script::MASARAM_GONDI: case Script::MAYAN_HIEROGLYPHS: case Script::MEDEFAIDRIN: case Script::MOON: case Script::NAG_MUNDARI: case Script::NAKHI_GEBA: case Script::NANDINAGARI: case Script::NUSHU: case Script::NYIAKENG_PUACHUE_HMONG: case Script::OL_ONAL: case Script::OLD_CHURCH_SLAVONIC_CYRILLIC: case Script::OLD_SOGDIAN: case Script::OLD_UYGHUR: case Script::RONGORONGO: case Script::SARATI: case Script::SIGNWRITING: case Script::SOGDIAN: case Script::SOYOMBO: case Script::SUNUWAR: case Script::TANGSA: case Script::TANGUT: case Script::TENGWAR: case Script::TODHRI: case Script::TOTO: case Script::TULU_TIGALARI: case Script::UNKNOWN: case Script::UNWRITTEN_LANGUAGES: case Script::VISIBLE_SPEECH: case Script::VITHKUQI: case Script::WESTERN_SYRIAC: case Script::WOLEAI: case Script::YEZIDI: case Script::ZANABAZAR_SQUARE: break;
}
// Arial is used as default fallback for system fallback, so always try that.
aFontList.AppendElement("Arial");
// Symbols/dingbats are generally Script=COMMON but may be resolved to any // surrounding script run. So we'll always append a couple of likely fonts // for such characters. const uint32_t b = aCh >> 8; if (aRunScript == Script::COMMON || // Stray COMMON chars not resolved
(b >= 0x20 && b <= 0x2b) || b == 0x2e || // BMP symbols/punctuation/etc
GetGenCategory(aCh) == nsUGenCategory::kSymbol ||
GetGenCategory(aCh) == nsUGenCategory::kPunctuation) {
aFontList.AppendElement("Segoe UI Symbol");
aFontList.AppendElement("Cambria Math");
}
// Arial Unicode MS has lots of glyphs for obscure characters; try it as a // last resort.
aFontList.AppendElement("Arial Unicode MS");
// If we didn't begin with the color-emoji fonts, include them here // so that they'll be preferred over user-installed (and possibly // broken) fonts in the global fallback path. if (!PrefersColor(aPresentation)) {
aFontList.AppendElement("Segoe UI Emoji");
aFontList.AppendElement("Twemoji Mozilla");
}
}
// The parent process doesn't know about the reset yet, or the reset is // local to our device. if (isContentOnlyTDR) {
gfxCriticalNote << "A content-only TDR is detected.";
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
cc->RecvReinitRenderingForDeviceReset();
}
}
nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() { if (XRE_IsContentProcess()) { auto& cmsOutputProfileData = GetCMSOutputProfileData(); // We should have set our profile data when we received our initial // ContentDeviceData.
MOZ_ASSERT(cmsOutputProfileData.isSome(), "Should have created output profile data when we received " "initial content device data.");
// If we have data, it should not be empty.
MOZ_ASSERT_IF(cmsOutputProfileData.isSome(),
!cmsOutputProfileData->IsEmpty());
if (cmsOutputProfileData.isSome()) { return cmsOutputProfileData.ref().Clone();
} return nsTArray<uint8_t>();
}
void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath,
nsAString& aVersion) {
DWORD versInfoSize, vers[4] = {0}; // version info not available case
aVersion.AssignLiteral(u"0.0.0.0");
versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
AutoTArray<BYTE, 512> versionInfo;
if (versInfoSize == 0) { return;
}
// XXX(Bug 1631371) Check if this should use a fallible operation as it // pretended earlier.
versionInfo.AppendElements(uint32_t(versInfoSize));
if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
LPBYTE(versionInfo.Elements()))) { return;
}
UINT len = 0;
VS_FIXEDFILEINFO* fileInfo = nullptr; if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
(LPVOID*)&fileInfo, &len) ||
len == 0 || fileInfo == nullptr) { return;
}
void gfxWindowsPlatform::InitializeConfig() { if (XRE_IsParentProcess()) { // The parent process first determines which features can be attempted. // This information is relayed to content processes and the GPU process.
InitializeD3D11Config();
InitializeANGLEConfig();
InitializeD2DConfig();
} else {
ImportCachedContentDeviceData();
InitializeANGLEConfig();
}
}
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled", "FEATURE_FAILURE_D3D11_NEED_HWCOMP"_ns); return;
}
d3d11.EnableByDefault();
// Check if the user really, really wants WARP. if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) { // Force D3D11 on even if we disabled it.
d3d11.UserForceEnable("User force-enabled WARP");
}
/* static */ void gfxWindowsPlatform::RecordContentDeviceFailure(
TelemetryDeviceCode aDevice) { // If the parent process fails to acquire a device, we record this // normally as part of the environment. The exceptional case we're // looking for here is when the parent process successfully acquires // a device, but the content process fails to acquire the same device. // This would not normally be displayed in about:support. if (!XRE_IsContentProcess()) { return;
}
Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE,
uint32_t(aDevice));
}
void gfxWindowsPlatform::RecordStartupTelemetry() { if (!XRE_IsParentProcess()) { return;
}
// Supports lazy device initialization on Windows, so that WebRender can avoid // initializing GPU state and allocating swap chains for most non-GPU processes. void gfxWindowsPlatform::EnsureDevicesInitialized() {
MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
if (!mInitializedDevices) {
mInitializedDevices = true;
InitializeDevices();
UpdateBackendPrefs();
}
}
if (XRE_IsParentProcess()) { // If we're the UI process, and the GPU process is enabled, then we don't // initialize any DirectX devices. We do leave them enabled in gfxConfig // though. If the GPU process fails to create these devices it will send // a message back and we'll update their status. if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { return;
}
// No GPU process, continue initializing devices as normal.
}
// If acceleration is disabled, we refuse to initialize anything. if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { return;
}
// If we previously crashed initializing devices, bail out now.
D3D11LayersCrashGuard detectCrashes; if (detectCrashes.Crashed()) {
gfxConfig::SetFailed(Feature::HW_COMPOSITING,
FeatureStatus::CrashedOnStartup, "Crashed during startup in a previous session");
gfxConfig::SetFailed(
Feature::D3D11_COMPOSITING, FeatureStatus::CrashedOnStartup, "Harware acceleration crashed during startup in a previous session");
gfxConfig::SetFailed(
Feature::DIRECT2D, FeatureStatus::CrashedOnStartup, "Harware acceleration crashed during startup in a previous session"); return;
}
// First, initialize D3D11. If this succeeds we attempt to use Direct2D.
InitializeD3D11();
InitializeD2D();
if (!gfxConfig::IsEnabled(Feature::DIRECT2D) && XRE_IsContentProcess() &&
shouldUseD2D) {
RecordContentDeviceFailure(TelemetryDeviceCode::D2D1);
}
}
void gfxWindowsPlatform::InitializeD3D11() { // This function attempts to initialize our D3D11 devices, if the hardware // is not blocklisted for D3D11 layers. This first attempt will try to create // a hardware accelerated device. If this creation fails or the hardware is // blocklisted, then this function will abort if WARP is disabled, causing us // to fallback to Basic layers. If WARP is not disabled it will use a WARP // device which should always be available on Windows 7 and higher. if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { return;
}
DeviceManagerDx* dm = DeviceManagerDx::Get(); if (XRE_IsParentProcess()) { if (!dm->CreateCompositorDevices()) { return;
}
}
dm->CreateContentDevices();
// Content process failed to create the d3d11 device while parent process // succeed. if (XRE_IsContentProcess() &&
!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
gfxCriticalError()
<< "[D3D11] Failed to create the D3D11 device in content \
process.";
}
}
// We don't know this value ahead of time, but the user can force-override // it, so we use Disable instead of SetFailed. if (dm->IsWARP()) {
d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP", "FEATURE_FAILURE_D2D_WARP_BLOCK"_ns);
}
// If we pass all the initial checks, we can proceed to runtime decisions. if (!d2d1.IsEnabled()) { return;
}
if (!Factory::SupportsD2D1()) {
d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory", "FEATURE_FAILURE_D2D_FACTORY"_ns); return;
}
if (!dm->GetContentDevice()) {
d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device", "FEATURE_FAILURE_D2D_DEVICE"_ns); return;
}
if (!dm->TextureSharingWorks()) {
d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing", "FEATURE_FAILURE_D2D_TXT_SHARING"_ns); return;
}
// Using Direct2D depends on DWrite support. if (!DWriteEnabled() && !InitDWriteSupport()) {
d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support", "FEATURE_FAILURE_D2D_DWRITE"_ns); return;
}
// Verify that Direct2D device creation succeeded.
RefPtr<ID3D11Device> contentDevice = dm->GetContentDevice(); if (!Factory::SetDirect3D11Device(contentDevice)) {
d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device", "FEATURE_FAILURE_D2D_CREATE_FAILED"_ns); return;
}
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { // Don't use the GPU process if not using D3D11, unless software // compositor is allowed if (StaticPrefs::layers_gpu_process_allow_software_AtStartup()) { return;
}
gpuProc.Disable(FeatureStatus::Unavailable, "Not using GPU Process since D3D11 is unavailable", "FEATURE_FAILURE_NO_D3D11"_ns);
} // If we're still enabled at this point, the user set the force-enabled pref.
}
class D3DVsyncSource final : public VsyncSource { public:
D3DVsyncSource()
: mPrevVsync(TimeStamp::Now()),
mVsyncEnabled(false),
mWaitVBlankMonitor(NULL) {
mVsyncThread = new base::Thread("WindowsVsyncThread");
MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "GFX: Could not start Windows vsync thread");
SetVsyncRate();
}
void SetVsyncRate() {
DWM_TIMING_INFO vblankTime; // Make sure to init the cbSize, otherwise GetCompositionTiming will fail
vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime); if (SUCCEEDED(hr)) {
UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh; // We get the rate in hertz / time, but we want the rate in ms. float rate =
((float)refreshRate.uiDenominator / (float)refreshRate.uiNumerator) *
1000;
mVsyncRate = TimeDuration::FromMilliseconds(rate);
} else {
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
}
}
// On Windows 10 and on, DWMGetCompositionTimingInfo, mostly // reports the upcoming vsync time, which is in the future. // It can also sometimes report a vblank time in the past. // Since large parts of Gecko assume TimeStamps can't be in future, // use the previous vsync.
// Windows 10 and Intel HD vsync timestamps are messy and // all over the place once in a while. Most of the time, // it reports the upcoming vsync. Sometimes, that upcoming // vsync is in the past. Sometimes that upcoming vsync is before // the previously seen vsync. // In these error cases, normalize to Now(); if (vsync >= now) {
vsync = vsync - mVsyncRate;
}
// On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime // from DWMGetCompositionTimingInfo. We can return the adjusted vsync. if (vsync >= now) {
vsync = now;
}
// Our vsync time is some time very far in the past, adjust to Now. // 4 ms is arbitrary, so feel free to pick something else if this isn't // working. See the comment above. if ((now - vsync).ToMilliseconds() > 4.0) {
vsync = now;
}
for (;;) {
{ // scope lock if (!mVsyncEnabled) return;
}
// Large parts of gecko assume that the refresh driver timestamp // must be <= Now() and cannot be in the future.
MOZ_ASSERT(vsync <= TimeStamp::Now());
NotifyVsync(vsync, vsync + mVsyncRate);
HRESULT hr = E_FAIL; if (!StaticPrefs::gfx_vsync_force_disable_waitforvblank()) {
UpdateVBlankOutput(); if (mWaitVBlankOutput) { const TimeStamp vblank_begin_wait = TimeStamp::Now();
{
AUTO_PROFILER_THREAD_SLEEP;
hr = mWaitVBlankOutput->WaitForVBlank();
} if (SUCCEEDED(hr)) { // vblank might return instantly when running headless, // monitor powering off, etc. Since we're on a dedicated // thread, instant-return should not happen in the normal // case, so catch any odd behavior with a time cutoff:
TimeDuration vblank_wait = TimeStamp::Now() - vblank_begin_wait; if (vblank_wait.ToMilliseconds() < 1.0) {
hr = E_FAIL; // fall back on old behavior
}
}
}
} if (!SUCCEEDED(hr)) {
hr = DwmFlush();
} if (!SUCCEEDED(hr)) { // DWMFlush isn't working, fallback to software vsync.
ScheduleSoftwareVsync(TimeStamp::Now()); return;
}
TimeStamp now = TimeStamp::Now();
TimeDuration flushDiff = now - flushTime;
flushTime = now; if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) { // Our vblank took longer than 2 intervals, readjust our timestamps
vsync = GetVBlankTime();
mPrevVsync = vsync;
} else { // Instead of giving the actual vsync time, a constant interval // between vblanks instead of the noise generated via hardware // is actually what we want. Most apps just care about the diff // between vblanks to animate, so a clean constant interval is // smoother.
vsync = mPrevVsync + mVsyncRate; if (vsync > now) { // DWMFlush woke up very early, so readjust our times again
vsync = GetVBlankTime();
}
if (vsync <= mPrevVsync) {
vsync = TimeStamp::Now();
}
if ((now - vsync).ToMilliseconds() > 2.0) { // Account for time drift here where vsync never quite catches up to // Now and we'd fall ever so slightly further behind Now().
vsync = GetVBlankTime();
}
mPrevVsync = vsync;
}
} // end for
} virtual ~D3DVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
already_AddRefed<mozilla::gfx::VsyncSource>
gfxWindowsPlatform::CreateGlobalHardwareVsyncSource() {
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
RefPtr<VsyncSource> d3dVsyncSource = new D3DVsyncSource(); return d3dVsyncSource.forget();
}
DeviceManagerDx* dm = DeviceManagerDx::Get(); if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
dm->ImportDeviceInfo(aData.gpuDevice().ref());
} 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", "FEATURE_FAILURE_D2D_D3D11_COMP"_ns);
}
}
// CanUseHardwareVideoDecoding depends on d3d11 state, so update // the cached value now.
UpdateCanUseHardwareVideoDecoding();
// 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();
}
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
DeviceManagerDx* dm = DeviceManagerDx::Get();
dm->ImportDeviceInfo(aData.d3d11());
}
}
void gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData* aOut) { // Check for device resets before giving back new graphics information.
UpdateRenderMode();
bool gfxWindowsPlatform::CheckVariationFontSupport() { // Variation font support is only available on Fall Creators Update or later. return IsWin10FallCreatorsUpdateOrLater();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.