/* -*- Mode: C++; tab-width: 20; 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/. */
// We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h, // since it doesn't include d3d11.h, so we use a static here. It should only // be used within InitializeD3D11.
decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
// It should only be used within CreateDirectCompositionDevice.
decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr;
decltype(DCompositionCreateDevice3)* sDcompCreateDevice3Fn = nullptr;
// It should only be used within CreateDCompSurfaceHandle
decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn =
nullptr;
// We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h, // since it doesn't include ddraw.h, so we use a static here. It should only // be used within InitializeDirectDrawConfig.
decltype(DirectDrawCreateEx)* sDirectDrawCreateExFn = nullptr;
DeviceManagerDx::DeviceManagerDx()
: mDeviceLock("gfxWindowsPlatform.mDeviceLock"),
mCompositorDeviceSupportsVideo(false) { // Set up the D3D11 feature levels we can ask for.
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
MOZ_COUNT_CTOR(DeviceManagerDx);
}
nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll")); if (!module) {
d3d11.SetFailed(FeatureStatus::Unavailable, "Direct3D11 not available on this computer", "FEATURE_FAILURE_D3D11_LIB"_ns); returnfalse;
}
sD3D11CreateDeviceFn =
(decltype(D3D11CreateDevice)*)GetProcAddress(module, "D3D11CreateDevice"); if (!sD3D11CreateDeviceFn) { // We should just be on Windows Vista or XP in this case.
d3d11.SetFailed(FeatureStatus::Unavailable, "Direct3D11 not available on this computer", "FEATURE_FAILURE_D3D11_FUNCPTR"_ns); returnfalse;
}
staticbool ColorSpaceIsHDR(const DXGI_OUTPUT_DESC1& aDesc) { // Set isHDR to true if the output has a BT2020 colorspace with EOTF2084 // gamma curve, this indicates the system is sending an HDR format to // this monitor. The colorspace returned by DXGI is very vague - we only // see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR and // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the // monitor is using something like YCbCr444 according to Settings // (System -> Display Settings -> Advanced Display). To get more specific // info we would need to query the DISPLAYCONFIG values in WinGDI. // // Note that we don't check bit depth here, since as of Windows 11 22H2, // HDR is supported with 8bpc for lower bandwidth, where DWM converts to // dithered RGB8 rather than RGB10, which doesn't really matter here. // // Since RefreshScreens(), the caller of this function, is triggered // by WM_DISPLAYCHANGE, this will pick up changes to the monitors in // all the important cases (resolution/color changes by the user). // // Further reading: // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level bool isHDR = (aDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
if (!adapter) {
NS_WARNING( "Failed to acquire a DXGI adapter for checking hardware stretching " "support.");
++aRv.mError; return;
}
for (UINT i = 0;; ++i) {
RefPtr<IDXGIOutput> output = nullptr;
HRESULT result = adapter->EnumOutputs(i, getter_AddRefs(output)); if (result == DXGI_ERROR_NOT_FOUND) { // No more outputs to check. break;
}
if (int32_t sleepSec =
StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) {
printf_stderr("Attach to PID: %lu\n", GetCurrentProcessId());
Sleep(sleepSec * 1000);
}
if (!LoadD3D11()) { returnfalse;
}
CreateCompositorDevice(d3d11);
if (!d3d11.IsEnabled()) {
MOZ_ASSERT(!mCompositorDevice);
ReleaseD3D11();
returnfalse;
}
// We leak these everywhere and we need them our entire runtime anyway, let's // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around // as well for D2D1 and device resets.
mD3D11Module.disown();
MOZ_ASSERT(mCompositorDevice); if (!d3d11.IsEnabled()) { returnfalse;
}
// When WR is used, do not preload attachments for D3D11 Non-WR compositor. // // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process // could happen when WR causes error. In this case, the attachments are loaded // synchronously. if (gfx::gfxVars::UseSoftwareWebRender()) {
PreloadAttachmentsOnCompositorThread();
}
// We should have been assigned a DeviceStatus from the parent process, // GPU process, or the same process if using in-process compositing.
MOZ_RELEASE_ASSERT(mDeviceStatus);
if (CreateContentDevice() == FeatureStatus::CrashedInHandler) {
DisableD3D11AfterCrash();
}
}
// Try to use a DXGI 1.1 adapter in order to share resources // across processes. if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) { if (fCreateDXGIFactory2) { auto hr = fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG,
__uuidof(IDXGIFactory2),
getter_AddRefs(mFactory));
MOZ_ALWAYS_TRUE(!FAILED(hr));
} else {
NS_WARNING( "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
}
} if (!mFactory) {
HRESULT hr =
createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(mFactory)); if (FAILED(hr) || !mFactory) { // This seems to happen with some people running the iZ3D driver. // They won't get acceleration. return nullptr;
}
}
if (mDeviceStatus) { // Match the adapter to our mDeviceStatus, if possible. for (UINT index = 0;; index++) {
RefPtr<IDXGIAdapter1> adapter; if (FAILED(mFactory->EnumAdapters1(index, getter_AddRefs(adapter)))) { break;
}
if (!mAdapter) {
mDeviceStatus.reset(); // Pick the first adapter available.
mFactory->EnumAdapters1(0, getter_AddRefs(mAdapter));
}
// We leak this module everywhere, we might as well do so here as well.
dxgiModule.disown(); return mAdapter;
}
bool DeviceManagerDx::CreateCompositorDeviceHelper(
FeatureState& aD3d11, IDXGIAdapter1* aAdapter, bool aAttemptVideoSupport,
RefPtr<ID3D11Device>& aOutDevice) { // Check if a failure was injected for testing. if (StaticPrefs::gfx_testing_device_fail()) {
aD3d11.SetFailed(FeatureStatus::Failed, "Direct3D11 device failure simulated by preference", "FEATURE_FAILURE_D3D11_SIM"_ns); returnfalse;
}
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
DXGI_ADAPTER_DESC desc;
aAdapter->GetDesc(&desc); if (desc.VendorId != 0x1414) { // 0x1414 is Microsoft (e.g. WARP) // When not using WARP, use // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent // bug 1092260. IE 11 also uses this flag.
flags |= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
}
if (aAttemptVideoSupport) {
flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
}
HRESULT hr;
RefPtr<ID3D11Device> device; if (!CreateDevice(aAdapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) { if (!aAttemptVideoSupport) {
gfxCriticalError() << "Crash during D3D11 device creation";
aD3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed trying to acquire a D3D11 device", "FEATURE_FAILURE_D3D11_DEVICE1"_ns);
} returnfalse;
}
if (FAILED(hr) || !device) { if (!aAttemptVideoSupport) {
aD3d11.SetFailed(FeatureStatus::Failed, "Failed to acquire a D3D11 device", "FEATURE_FAILURE_D3D11_DEVICE2"_ns);
} returnfalse;
} if (!D3D11Checks::DoesDeviceWork()) { if (!aAttemptVideoSupport) {
aD3d11.SetFailed(FeatureStatus::Broken, "Direct3D11 device was determined to be broken", "FEATURE_FAILURE_D3D11_BROKEN"_ns);
} returnfalse;
}
aOutDevice = device; returntrue;
}
// Note that it's enough for us to just use a counter for a unique ID, // even though the counter isn't synchronized between processes. If we // start in the GPU process and wind up in the parent process, the // whole graphics stack is blown away anyway. But just in case, we // make gpu process IDs negative and parent process IDs positive. staticinline int32_t GetNextDeviceCounter() { static int32_t sDeviceCounter = 0; return XRE_IsGPUProcess() ? --sDeviceCounter : ++sDeviceCounter;
}
void DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) { if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
CreateWARPCompositorDevice(); return;
}
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); if (!adapter) {
d3d11.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a DXGI adapter", "FEATURE_FAILURE_D3D11_DXGI"_ns); return;
}
if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter)) {
d3d11.SetFailed(FeatureStatus::Unavailable, "DXGI does not support out-of-process presentation", "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns); return;
}
RefPtr<ID3D11Device> device; if (!CreateCompositorDeviceHelper(d3d11, adapter, true, device)) { // Try again without video support and record that it failed.
mCompositorDeviceSupportsVideo = false; if (!CreateCompositorDeviceHelper(d3d11, adapter, false, device)) { return;
}
} else {
mCompositorDeviceSupportsVideo = true;
}
// Only test this when not using WARP since it can fail and cause // GetDeviceRemovedReason to return weird values. bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
if (!textureSharingWorks) {
gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken, "Texture sharing doesn't work", "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns);
} if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device)) {
gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken, "RenderTargetViews need recreating", "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns);
} if (XRE_IsParentProcess()) { // It seems like this may only happen when we're using the NVIDIA gpu
D3D11Checks::WarnOnAdapterMismatch(device);
}
if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) { do { if (!aOutDevice) break;
RefPtr<ID3D11Debug> debug; if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug),
getter_AddRefs(debug)))) break;
RefPtr<ID3D11InfoQueue> infoQueue; if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue),
getter_AddRefs(infoQueue)))) break;
D3D11_INFO_QUEUE_FILTER filter;
PodZero(&filter);
// Disable warnings caused by Advanced Layers that are known and not // problematic.
D3D11_MESSAGE_ID blockIDs[] = {
D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL};
filter.DenyList.NumIDs = std::size(blockIDs);
filter.DenyList.pIDList = blockIDs;
infoQueue->PushStorageFilter(&filter);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
} while (false);
}
// Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS // to prevent bug 1092260. IE 11 also uses this flag.
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) {
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
d3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed creating a D3D11 WARP device", "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
}
if (FAILED(hr) || !device) { // This should always succeed... in theory.
gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
<< hexa(hr);
d3d11.SetFailed(FeatureStatus::Failed, "Failed to create a D3D11 WARP device", "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns); return;
}
FeatureStatus DeviceManagerDx::CreateContentDevice() {
RefPtr<IDXGIAdapter1> adapter; if (!mDeviceStatus->isWARP()) {
adapter = GetDXGIAdapterLocked(); if (!adapter) {
gfxCriticalNote << "Could not get a DXGI adapter"; return FeatureStatus::Unavailable;
}
}
HRESULT hr;
RefPtr<ID3D11Device> device;
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D_DRIVER_TYPE type =
mDeviceStatus->isWARP() ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN; if (!CreateDevice(adapter, type, flags, hr, device)) {
gfxCriticalNote
<< "Recovered from crash while creating a D3D11 content device";
gfxWindowsPlatform::RecordContentDeviceFailure(
TelemetryDeviceCode::Content); return FeatureStatus::CrashedInHandler;
}
if (FAILED(hr) || !device) {
gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr);
gfxWindowsPlatform::RecordContentDeviceFailure(
TelemetryDeviceCode::Content); return FeatureStatus::Failed;
}
// InitializeD2D() will abort early if the compositor device did not support // texture sharing. If we're in the content process, we can't rely on the // parent device alone: some systems have dual GPUs that are capable of // binding the parent and child processes to different GPUs. As a safety net, // we re-check texture sharing against the newly created D3D11 content device. // If it fails, we won't use Direct2D. if (XRE_IsContentProcess()) { if (!D3D11Checks::DoesTextureSharingWork(device)) { return FeatureStatus::Failed;
}
DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device);
MOZ_ASSERT(ok);
}
bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002; bool reuseDevice = false; if (gfxVars::ReuseDecoderDevice()) {
reuseDevice = true;
} elseif (isAMD) {
reuseDevice = true;
gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD";
}
if (reuseDevice) { // Use mCompositorDevice for decoder device only for hardware WebRender. if (aFlags.contains(DeviceFlag::isHardwareWebRenderInUse) &&
mCompositorDevice && mCompositorDeviceSupportsVideo &&
!mDecoderDevice) {
mDecoderDevice = mCompositorDevice;
RefPtr<ID3D10Multithread> multi;
mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread),
getter_AddRefs(multi)); if (multi) {
MOZ_ASSERT(multi->GetMultithreadProtected());
}
}
if (mDecoderDevice) {
RefPtr<ID3D11Device> dev = mDecoderDevice; return dev.forget();
}
}
if (!sD3D11CreateDeviceFn) { // We should just be on Windows Vista or XP in this case. return nullptr;
}
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); if (!adapter) { return nullptr;
}
if (createCompositorDevice && !CreateCompositorDevicesLocked()) { // Just stop, don't try anything more returntrue;
} if (createContentDevice) {
CreateContentDevicesLocked();
} if (createCanvasDevice) {
CreateCanvasDeviceLocked();
} if (createDirectCompositionDevice) {
CreateDirectCompositionDeviceLocked();
}
if (mDirectDraw) { // Already initialized. return;
}
FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW); if (!ddraw.IsEnabled()) { return;
}
// Check if DirectDraw is available on this system.
mDirectDrawDLL.own(LoadLibrarySystem32(L"ddraw.dll")); if (!mDirectDrawDLL) {
ddraw.SetFailed(FeatureStatus::Unavailable, "DirectDraw not available on this computer", "FEATURE_FAILURE_DDRAW_LIB"_ns); return;
}
sDirectDrawCreateExFn = (decltype(DirectDrawCreateEx)*)GetProcAddress(
mDirectDrawDLL, "DirectDrawCreateEx"); if (!sDirectDrawCreateExFn) {
ddraw.SetFailed(FeatureStatus::Unavailable, "DirectDraw not available on this computer", "FEATURE_FAILURE_DDRAW_LIB"_ns); return;
}
// Otherwise, we'll try to create attachments outside the lock.
device = mCompositorDevice;
}
// We save the attachments object even if it fails to initialize, so the // compositor can grab the failure ID.
RefPtr<layers::DeviceAttachmentsD3D11> attachments =
layers::DeviceAttachmentsD3D11::Create(device);
{
MutexAutoLock lock(mDeviceLock); if (device != mCompositorDevice) { return;
}
mCompositorAttachments = attachments;
}
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.