/* -*- 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/. */
// Flag for PrintWindow() that is defined in Winuser.h. It is defined since // Windows 8.1. This allows PrintWindow to capture window content that is // rendered with DirectComposition. #undef PW_RENDERFULLCONTENT #define PW_RENDERFULLCONTENT 0x00000002
bool RenderCompositorANGLE::Initialize(nsACString& aError) { // TODO(aosmond): This causes us to lose WebRender because it is unable to // distinguish why we failed and retry once the reset is complete. This does // appear to happen in the wild, so we really should try to do something // differently here. if (RenderThread::Get()->IsHandlingDeviceReset()) {
aError.Assign("RcANGLE(waiting device reset)"_ns); returnfalse;
}
// Force enable alpha channel to make sure ANGLE use correct framebuffer // formart constauto& gle = gl::GLContextEGL::Cast(mGL); constauto& egl = gle->mEgl; if (!gl::CreateConfig(*egl, &mEGLConfig, /* bpp */ 32, /* enableDepthBuffer */ false, mGL->IsGLES())) {
aError.Assign("RcANGLE(create EGLConfig failed)"_ns); returnfalse;
}
MOZ_ASSERT(mEGLConfig);
mDevice = GetDeviceOfEGLDisplay(aError);
if (!mDevice) { returnfalse;
}
mDevice->GetImmediateContext(getter_AddRefs(mCtx)); if (!mCtx) {
aError.Assign("RcANGLE(get immediate context failed)"_ns); returnfalse;
}
// Disable native compositor when fast snapshot is needed. // Taking snapshot of native compositor is very slow on Windows. if (mWidget->GetCompositorOptions().NeedFastSnaphot()) {
mUseNativeCompositor = false;
}
// Create DCLayerTree when DirectComposition is used. if (gfx::gfxVars::UseWebRenderDCompWin()) {
HWND compositorHwnd = GetCompositorHwnd(); if (compositorHwnd) {
mDCLayerTree = DCLayerTree::Create(mGL, mEGLConfig, mDevice, mCtx,
compositorHwnd, aError); if (!mDCLayerTree) { returnfalse;
}
} else {
aError.Assign("RcANGLE(no compositor window)"_ns); returnfalse;
}
}
// Create SwapChain when compositor is not used if (!UseCompositor()) { if (!CreateSwapChain(aError)) { // SwapChain creation failed. returnfalse;
}
}
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice); if (!mSyncObject->Init()) { // Some errors occur. Clear the mSyncObject here. // Then, there will be no texture synchronization.
aError.Assign("RcANGLE(create SyncObject failed)"_ns); returnfalse;
}
// We need this because we don't want DXGI to respond to Alt+Enter.
HWND hwnd = mWidget->AsWindows()->GetHwnd();
DXGIFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (!ResizeBufferIfNeeded()) {
aError.Assign("RcANGLE(resize buffer failed)"_ns); returnfalse;
} returntrue;
}
void RenderCompositorANGLE::CreateSwapChainForDCompIfPossible() { if (!mDCLayerTree) { return;
}
HWND hwnd = GetCompositorHwnd(); if (!hwnd) { // When DirectComposition or DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL is used, // compositor window needs to exist. if (gfx::gfxVars::UseWebRenderDCompWin() ||
gfx::gfxVars::UseWebRenderFlipSequentialWin()) {
gfxCriticalNote << "Compositor window was not created";
} return;
}
// When compositor is enabled, CompositionSurface is used for rendering. // It does not support triple buffering. constbool useTripleBuffering =
gfx::gfxVars::UseWebRenderTripleBufferingWin() && !UseCompositor();
RefPtr<IDXGISwapChain1> swapChain1 =
CreateSwapChainForDComp(useTripleBuffering); if (swapChain1) {
mSwapChain = swapChain1;
mSwapChain1 = swapChain1;
mUseTripleBuffering = useTripleBuffering;
mDCLayerTree->SetDefaultSwapChain(swapChain1);
} else { // Clear DCLayerTree on falire
mDCLayerTree = nullptr;
}
}
if (!UseCompositor()) { auto start = TimeStamp::Now(); if (auto* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler()) { // There is a Firefox Reality handler for this swapchain. Update this // window's contents to the VR window. if (fxrHandler->TryInitialize(mSwapChain, mDevice)) {
fxrHandler->UpdateOutput(mCtx);
}
}
const LayoutDeviceIntSize& bufferSize = mBufferSize.ref(); if (mUsePartialPresent && mSwapChain1) { // Clear full render flag.
mFullRender = false; // If there is no diry rect, we skip SwapChain present. if (!aDirtyRects.IsEmpty()) { int rectsCount = 0;
StackArray<RECT, 1> rects(aDirtyRects.Length());
for (size_t i = 0; i < aDirtyRects.Length(); ++i) { const DeviceIntRect& rect = aDirtyRects[i]; // Clip rect to bufferSize int left = std::clamp(rect.min.x, 0, bufferSize.width); int top = std::clamp(rect.min.y, 0, bufferSize.height); int right = std::clamp(rect.max.x, 0, bufferSize.width); int bottom = std::clamp(rect.max.y, 0, bufferSize.height);
// When rect is not empty, the rect could be passed to Present1(). if (left < right && top < bottom) {
rects[rectsCount].left = left;
rects[rectsCount].top = top;
rects[rectsCount].right = right;
rects[rectsCount].bottom = bottom;
rectsCount++;
}
}
if (mFirstPresent && mDCLayerTree) { // Wait for the GPU to finish executing its commands before // committing the DirectComposition tree, or else the swapchain // may flicker black when it's first presented.
RefPtr<IDXGIDevice2> dxgiDevice2;
mDevice->QueryInterface((IDXGIDevice2**)getter_AddRefs(dxgiDevice2));
MOZ_ASSERT(dxgiDevice2);
if (mDisablingNativeCompositor) { // During disabling native compositor, we need to wait all gpu tasks // complete. Otherwise, rendering window could cause white flash.
WaitForPreviousGraphicsCommandsFinishedQuery(/* aWaitAll */ true);
mDisablingNativeCompositor = false;
}
if (mDCLayerTree) {
mDCLayerTree->MaybeUpdateDebug();
mDCLayerTree->MaybeCommit();
}
return frameId;
}
bool RenderCompositorANGLE::WaitForGPU() { // Note: this waits on the query we inserted in the previous frame, // not the one we just inserted now. Example: // Insert query #1 // Present #1 // (first frame, no wait) // Insert query #2 // Present #2 // Wait for query #1. // Insert query #3 // Present #3 // Wait for query #2. // // This ensures we're done reading textures before swapping buffers. if (!StaticPrefs::gfx_webrender_wait_gpu_finished_disabled_AtStartup()) { return WaitForPreviousGraphicsCommandsFinishedQuery();
} returntrue;
}
// DXGI does not like 0x0 swapchains. ResizeBuffers() failed when 0x0 was set // when DComp is used.
size.width = std::max(size.width, 1);
size.height = std::max(size.height, 1);
if (mBufferSize.isSome() && mBufferSize.ref() == size) {
MOZ_ASSERT(mEGLSurface); returntrue;
}
// Release EGLSurface of back buffer before calling ResizeBuffers().
DestroyEGLSurface();
mBufferSize = Some(size);
if (!CreateEGLSurface()) {
mBufferSize.reset(); returnfalse;
}
if (mUsePartialPresent) {
mFullRender = true;
} returntrue;
}
void RenderCompositorANGLE::Update() { // Update compositor window's size if it exists. // It needs to be called here, since OS might update compositor // window's size at unexpected timing.
mWidget->AsWindows()->UpdateCompositorWndSizeIfNecessary();
}
LayoutDeviceIntSize RenderCompositorANGLE::GetBufferSize() { if (!UseCompositor()) {
MOZ_ASSERT(mBufferSize.isSome()); if (mBufferSize.isNothing()) { return LayoutDeviceIntSize();
} return mBufferSize.ref();
} else { auto size = mWidget->GetClientSize(); // This size is used for WR DEBUG_OVERLAY. Its DCTile does not like 0.
size.width = std::max(size.width, 1);
size.height = std::max(size.height, 1); return size;
}
}
gfx::DeviceResetReason RenderCompositorANGLE::IsContextLost(bool aForce) { // glGetGraphicsResetStatus does not always work to detect timeout detection // and recovery (TDR). On Windows, ANGLE itself is just relying upon the same // API, so we should not need to check it separately. auto reason = mDevice->GetDeviceRemovedReason(); return layers::DXGIErrorToDeviceResetReason(reason);
}
if (StaticPrefs::gfx_webrender_dcomp_use_virtual_surfaces_AtStartup()) {
aCaps->virtual_surface_size = VIRTUAL_SURFACE_SIZE;
} else {
aCaps->virtual_surface_size = 0;
} // DComp video overlay does not support negative scaling. See Bug 1831820
aCaps->supports_external_compositor_surface_negative_scaling = false;
}
void RenderCompositorANGLE::EnableNativeCompositor(bool aEnable) { // XXX Re-enable native compositor is not handled yet.
MOZ_RELEASE_ASSERT(!mDisablingNativeCompositor);
MOZ_RELEASE_ASSERT(!aEnable);
LOG("RenderCompositorANGLE::EnableNativeCompositor() aEnable %d", aEnable);
void RenderCompositorANGLE::InitializeUsePartialPresent() { // Even when mSwapChain1 is null, we could enable WR partial present, since // when mSwapChain1 is null, SwapChain is blit model swap chain with one // buffer.
mUsePartialPresent = !UseCompositor() &&
!mWidget->AsWindows()->HasFxrOutputHandler() &&
gfx::gfxVars::WebRenderMaxPartialPresentRects() > 0;
}
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 und die Messung sind noch experimentell.