Bug 1946657 - Re-add workaround of video overlay's SwapChain Present() r=gfx-reviewers,lsalzman
New video SwapChain workaround has a workaround of Bug 1940023. Differential Revision: https://phabricator.services.mozilla.com/D238720
This commit is contained in:
@@ -660,8 +660,6 @@ void DCLayerTree::CompositorEndFrame() {
|
||||
// Disable video overlay if mCompositionDevice->Commit() with video overlay is
|
||||
// too slow. It drops fps.
|
||||
|
||||
const auto maxCommitWaitDurationMs = 20;
|
||||
const auto maxSlowCommitCount = 5;
|
||||
const auto commitDurationMs =
|
||||
static_cast<uint32_t>((end - start).ToMilliseconds());
|
||||
|
||||
@@ -669,36 +667,12 @@ void DCLayerTree::CompositorEndFrame() {
|
||||
(uint8_t)mUsedOverlayTypesInFrame, commitDurationMs);
|
||||
PROFILER_MARKER_TEXT("CommitWait", GRAPHICS, {}, marker);
|
||||
|
||||
if (mUsedOverlayTypesInFrame != DCompOverlayTypes::NO_OVERLAY &&
|
||||
commitDurationMs > maxCommitWaitDurationMs) {
|
||||
mSlowCommitCount++;
|
||||
} else {
|
||||
mSlowCommitCount = 0;
|
||||
}
|
||||
|
||||
if (mSlowCommitCount <= maxSlowCommitCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = mDCSurfaces.begin(); it != mDCSurfaces.end(); it++) {
|
||||
auto* surfaceVideo = it->second->AsDCSurfaceVideo();
|
||||
if (surfaceVideo) {
|
||||
surfaceVideo->DisableVideoOverlay();
|
||||
surfaceVideo->OnCompositorEndFrame(mCurrentFrame, commitDurationMs);
|
||||
}
|
||||
}
|
||||
|
||||
if (mUsedOverlayTypesInFrame & DCompOverlayTypes::SOFTWARE_DECODED_VIDEO) {
|
||||
gfxCriticalNoteOnce << "Sw video swapchain present is slow";
|
||||
|
||||
nsPrintfCString marker("Sw video swapchain present is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
}
|
||||
if (mUsedOverlayTypesInFrame & DCompOverlayTypes::HARDWARE_DECODED_VIDEO) {
|
||||
gfxCriticalNoteOnce << "Hw video swapchain present is slow";
|
||||
|
||||
nsPrintfCString marker("Hw video swapchain present is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
}
|
||||
}
|
||||
|
||||
void DCLayerTree::BindSwapChain(wr::NativeSurfaceId aId) {
|
||||
@@ -1701,9 +1675,65 @@ void DCSurfaceVideo::PresentVideo() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto device = mDCLayerTree->GetDevice();
|
||||
HRESULT hr;
|
||||
if (mFirstPresent) {
|
||||
mFirstPresent = false;
|
||||
UINT flags = DXGI_PRESENT_USE_DURATION;
|
||||
// DirectComposition can display black for a swap chain between the first
|
||||
// and second time it's presented to - maybe the first Present can get lost
|
||||
// somehow and it shows the wrong buffer. In that case copy the buffers so
|
||||
// all have the correct contents, which seems to help. The first Present()
|
||||
// after this needs to have SyncInterval > 0, or else the workaround doesn't
|
||||
// help.
|
||||
for (size_t i = 0; i < mSwapChainBufferCount - 1; ++i) {
|
||||
hr = mVideoSwapChain->Present(0, flags);
|
||||
// Ignore DXGI_STATUS_OCCLUDED since that's not an error but only
|
||||
// indicates that the window is occluded and we can stop rendering.
|
||||
if (FAILED(hr) && hr != DXGI_STATUS_OCCLUDED) {
|
||||
gfxCriticalNoteOnce << "video Present failed during first present: "
|
||||
<< gfx::hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> destTexture;
|
||||
mVideoSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
||||
(void**)getter_AddRefs(destTexture));
|
||||
MOZ_ASSERT(destTexture);
|
||||
RefPtr<ID3D11Texture2D> srcTexture;
|
||||
hr = mVideoSwapChain->GetBuffer(1, __uuidof(ID3D11Texture2D),
|
||||
(void**)getter_AddRefs(srcTexture));
|
||||
MOZ_ASSERT(srcTexture);
|
||||
RefPtr<ID3D11DeviceContext> context;
|
||||
device->GetImmediateContext(getter_AddRefs(context));
|
||||
MOZ_ASSERT(context);
|
||||
context->CopyResource(destTexture, srcTexture);
|
||||
}
|
||||
|
||||
// Additionally wait for the GPU to finish executing its commands, or
|
||||
// there still may be a black flicker when presenting expensive content
|
||||
// (e.g. 4k video).
|
||||
|
||||
RefPtr<IDXGIDevice2> dxgiDevice2;
|
||||
device->QueryInterface((IDXGIDevice2**)getter_AddRefs(dxgiDevice2));
|
||||
MOZ_ASSERT(dxgiDevice2);
|
||||
|
||||
HANDLE event = ::CreateEvent(nullptr, false, false, nullptr);
|
||||
hr = dxgiDevice2->EnqueueSetEvent(event);
|
||||
if (SUCCEEDED(hr)) {
|
||||
DebugOnly<DWORD> result = ::WaitForSingleObject(event, INFINITE);
|
||||
MOZ_ASSERT(result == WAIT_OBJECT_0);
|
||||
} else {
|
||||
gfxCriticalNoteOnce << "EnqueueSetEvent failed: " << gfx::hexa(hr);
|
||||
}
|
||||
::CloseHandle(event);
|
||||
}
|
||||
|
||||
UINT flags = DXGI_PRESENT_USE_DURATION;
|
||||
UINT interval = 1;
|
||||
if (StaticPrefs::gfx_webrender_dcomp_video_swap_chain_present_interval_0()) {
|
||||
interval = 0;
|
||||
}
|
||||
|
||||
auto start = TimeStamp::Now();
|
||||
hr = mVideoSwapChain->Present(interval, flags);
|
||||
@@ -1722,8 +1752,6 @@ void DCSurfaceVideo::PresentVideo() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto maxPresentWaitDurationMs = 2;
|
||||
const auto maxSlowPresentCount = 5;
|
||||
const auto presentDurationMs =
|
||||
static_cast<uint32_t>((end - start).ToMilliseconds());
|
||||
const auto overlayType = mRenderTextureHost->IsSoftwareDecodedVideo()
|
||||
@@ -1734,36 +1762,20 @@ void DCSurfaceVideo::PresentVideo() {
|
||||
presentDurationMs);
|
||||
PROFILER_MARKER_TEXT("PresentWait", GRAPHICS, {}, marker);
|
||||
|
||||
if (presentDurationMs > maxPresentWaitDurationMs) {
|
||||
mSlowPresentCount++;
|
||||
} else {
|
||||
mSlowPresentCount = 0;
|
||||
if (mRenderTextureHostUsageInfo) {
|
||||
mRenderTextureHostUsageInfo->OnVideoPresent(mDCLayerTree->GetFrameId(),
|
||||
presentDurationMs);
|
||||
}
|
||||
|
||||
if (mSlowPresentCount <= maxSlowPresentCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisableVideoOverlay();
|
||||
|
||||
if (overlayType == DCompOverlayTypes::SOFTWARE_DECODED_VIDEO) {
|
||||
gfxCriticalNoteOnce << "Sw video swapchain present is slow";
|
||||
|
||||
nsPrintfCString marker("Sw video swapchain present is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
} else {
|
||||
gfxCriticalNoteOnce << "Hw video swapchain present is slow";
|
||||
|
||||
nsPrintfCString marker("Hw video swapchain present is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
}
|
||||
// printf_stderr("DCSurfaceVideo::PresentVideo() 5 presentDurationMs %u\n",
|
||||
// presentDurationMs);
|
||||
}
|
||||
|
||||
void DCSurfaceVideo::DisableVideoOverlay() {
|
||||
void DCSurfaceVideo::OnCompositorEndFrame(int aFrameId, uint32_t aDurationMs) {
|
||||
if (!mRenderTextureHostUsageInfo) {
|
||||
return;
|
||||
}
|
||||
mRenderTextureHostUsageInfo->DisableVideoOverlay();
|
||||
mRenderTextureHostUsageInfo->OnCompositorEndFrame(aFrameId, aDurationMs);
|
||||
}
|
||||
|
||||
DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat(bool aUseVpAutoHDR) {
|
||||
@@ -1779,6 +1791,8 @@ DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat(bool aUseVpAutoHDR) {
|
||||
bool DCSurfaceVideo::CreateVideoSwapChain(DXGI_FORMAT aSwapChainFormat) {
|
||||
MOZ_ASSERT(mRenderTextureHost);
|
||||
|
||||
mFirstPresent = true;
|
||||
|
||||
const auto device = mDCLayerTree->GetDevice();
|
||||
|
||||
RefPtr<IDXGIDevice> dxgiDevice;
|
||||
|
||||
@@ -185,6 +185,8 @@ class DCLayerTree {
|
||||
|
||||
void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes);
|
||||
|
||||
int GetFrameId() { return mCurrentFrame; }
|
||||
|
||||
protected:
|
||||
bool Initialize(HWND aHwnd, nsACString& aError);
|
||||
bool InitializeVideoOverlaySupport();
|
||||
@@ -265,7 +267,6 @@ class DCLayerTree {
|
||||
mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;
|
||||
|
||||
DCompOverlayTypes mUsedOverlayTypesInFrame = DCompOverlayTypes::NO_OVERLAY;
|
||||
int mSlowCommitCount = 0;
|
||||
|
||||
public:
|
||||
const color::ColorProfileDesc& OutputColorProfile() const {
|
||||
@@ -423,11 +424,10 @@ class DCSurfaceVideo : public DCSurface {
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
|
||||
bool CalculateSwapChainSize(gfx::Matrix& aTransform);
|
||||
void PresentVideo();
|
||||
void OnCompositorEndFrame(int aFrameId, uint32_t aDurationMs);
|
||||
|
||||
DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
|
||||
|
||||
void DisableVideoOverlay();
|
||||
|
||||
protected:
|
||||
virtual ~DCSurfaceVideo();
|
||||
|
||||
@@ -449,7 +449,7 @@ class DCSurfaceVideo : public DCSurface {
|
||||
RefPtr<RenderTextureHost> mRenderTextureHost;
|
||||
RefPtr<RenderTextureHost> mPrevTexture;
|
||||
RefPtr<RenderTextureHostUsageInfo> mRenderTextureHostUsageInfo;
|
||||
int mSlowPresentCount = 0;
|
||||
bool mFirstPresent = true;
|
||||
const UINT mSwapChainBufferCount;
|
||||
bool mUseVpAutoHDR = false;
|
||||
bool mVpAutoHDRFailed = false;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
#include "RenderThread.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -25,6 +27,63 @@ void ActivateBindAndTexParameteri(gl::GLContext* aGL, GLenum aActiveTexture,
|
||||
LOCAL_GL_LINEAR);
|
||||
}
|
||||
|
||||
void RenderTextureHostUsageInfo::OnVideoPresent(int aFrameId,
|
||||
uint32_t aDurationMs) {
|
||||
MOZ_ASSERT(RenderThread::IsInRenderThread());
|
||||
|
||||
const auto maxPresentWaitDurationMs = 2;
|
||||
const auto maxSlowPresentCount = 5;
|
||||
|
||||
mVideoPresentFrameId = aFrameId;
|
||||
|
||||
if (aDurationMs < maxPresentWaitDurationMs) {
|
||||
mSlowPresentCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mSlowPresentCount++;
|
||||
|
||||
if (mSlowPresentCount <= maxSlowPresentCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisableVideoOverlay();
|
||||
|
||||
gfxCriticalNoteOnce << "Video swapchain present is slow";
|
||||
|
||||
nsPrintfCString marker("Video swapchain present is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
}
|
||||
|
||||
void RenderTextureHostUsageInfo::OnCompositorEndFrame(int aFrameId,
|
||||
uint32_t aDurationMs) {
|
||||
MOZ_ASSERT(RenderThread::IsInRenderThread());
|
||||
|
||||
const auto maxCommitWaitDurationMs = 20;
|
||||
const auto maxSlowCommitCount = 5;
|
||||
|
||||
// Check if video was presented in current frame.
|
||||
if (mVideoPresentFrameId != aFrameId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aDurationMs < maxCommitWaitDurationMs) {
|
||||
mSlowCommitCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mSlowCommitCount++;
|
||||
|
||||
if (mSlowCommitCount <= maxSlowCommitCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxCriticalNoteOnce << "Video swapchain is slow";
|
||||
|
||||
nsPrintfCString marker("Video swapchain is slow");
|
||||
PROFILER_MARKER_TEXT("DisableOverlay", GRAPHICS, {}, marker);
|
||||
}
|
||||
|
||||
RenderTextureHost::RenderTextureHost() : mIsFromDRMSource(false) {
|
||||
MOZ_COUNT_CTOR(RenderTextureHost);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "mozilla/layers/OverlayInfo.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/webrender/webrender_ffi.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
@@ -57,6 +58,9 @@ class RenderTextureHostUsageInfo final {
|
||||
bool VideoOverlayDisabled() { return mVideoOverlayDisabled; }
|
||||
void DisableVideoOverlay() { mVideoOverlayDisabled = true; }
|
||||
|
||||
void OnVideoPresent(int aFrameId, uint32_t aDurationMs);
|
||||
void OnCompositorEndFrame(int aFrameId, uint32_t aDurationMs);
|
||||
|
||||
const TimeStamp mCreationTimeStamp;
|
||||
|
||||
protected:
|
||||
@@ -64,6 +68,10 @@ class RenderTextureHostUsageInfo final {
|
||||
|
||||
// RenderTextureHost prefers to disable video overlay.
|
||||
Atomic<bool> mVideoOverlayDisabled{false};
|
||||
|
||||
int mVideoPresentFrameId = 0;
|
||||
int mSlowPresentCount = 0;
|
||||
int mSlowCommitCount = 0;
|
||||
};
|
||||
|
||||
class RenderTextureHost {
|
||||
|
||||
Reference in New Issue
Block a user