зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1352163: Use buffer flipping for presenting to the browser window. r=mattwoodrow
MozReview-Commit-ID: JmJB6b9dP4S --HG-- extra : rebase_source : f2d5e7c1f037bb4af1a95932b22c2842f0c244f7
This commit is contained in:
Родитель
41dd51eec8
Коммит
7f457d5cb3
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "D3D11ShareHandleImage.h"
|
||||
|
||||
#include <dxgi1_2.h>
|
||||
#include <VersionHelpers.h> // For IsWindows8OrGreater
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -166,6 +166,7 @@ CompositorD3D11::CompositorD3D11(CompositorBridgeParent* aParent, widget::Compos
|
|||
, mDisableSequenceForNextFrame(false)
|
||||
, mAllowPartialPresents(false)
|
||||
, mVerifyBuffersFailed(false)
|
||||
, mIsDoubleBuffered(false)
|
||||
, mMaximumTriangles(kInitialMaximumTriangles)
|
||||
{
|
||||
}
|
||||
|
@ -487,36 +488,77 @@ CompositorD3D11::Initialize(nsCString* const out_failureReason)
|
|||
RefPtr<IDXGIFactory> dxgiFactory;
|
||||
dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
::ZeroMemory(&swapDesc, sizeof(swapDesc));
|
||||
swapDesc.BufferDesc.Width = 0;
|
||||
swapDesc.BufferDesc.Height = 0;
|
||||
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
|
||||
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
|
||||
swapDesc.SampleDesc.Count = 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.BufferCount = 1;
|
||||
swapDesc.OutputWindow = mHwnd;
|
||||
swapDesc.Windowed = TRUE;
|
||||
swapDesc.Flags = 0;
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
|
||||
RefPtr<IDXGIFactory2> dxgiFactory2;
|
||||
hr = dxgiFactory->QueryInterface((IDXGIFactory2**)getter_AddRefs(dxgiFactory2));
|
||||
|
||||
if (gfxPrefs::Direct3D11UseDoubleBuffering() && SUCCEEDED(hr) && dxgiFactory2 && IsWindows10OrGreater()) {
|
||||
// DXGI_SCALING_NONE is not available on Windows 7 with Platform Update.
|
||||
// This looks awful for things like the awesome bar and browser window resizing
|
||||
// so we don't use a flip buffer chain here. When using EFFECT_SEQUENTIAL
|
||||
// it looks like windows doesn't stretch the surface when resizing.
|
||||
RefPtr<IDXGISwapChain1> swapChain;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swapDesc;
|
||||
::ZeroMemory(&swapDesc, sizeof(swapDesc));
|
||||
swapDesc.Width = 0;
|
||||
swapDesc.Height = 0;
|
||||
swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
swapDesc.SampleDesc.Count = 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.BufferCount = 2;
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
swapDesc.Scaling = DXGI_SCALING_NONE;
|
||||
mIsDoubleBuffered = true;
|
||||
swapDesc.Flags = 0;
|
||||
|
||||
/**
|
||||
* Create a swap chain, this swap chain will contain the backbuffer for
|
||||
* the window we draw to. The front buffer is the full screen front
|
||||
* buffer.
|
||||
*/
|
||||
hr = dxgiFactory2->CreateSwapChainForHwnd(mDevice, mHwnd, &swapDesc, nullptr, nullptr, getter_AddRefs(swapChain));
|
||||
if (Failed(hr, "create swap chain")) {
|
||||
*out_failureReason = "FEATURE_FAILURE_D3D11_SWAP_CHAIN";
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_RGBA color = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
swapChain->SetBackgroundColor(&color);
|
||||
|
||||
mSwapChain = swapChain;
|
||||
} else {
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
::ZeroMemory(&swapDesc, sizeof(swapDesc));
|
||||
swapDesc.BufferDesc.Width = 0;
|
||||
swapDesc.BufferDesc.Height = 0;
|
||||
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
|
||||
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
|
||||
swapDesc.SampleDesc.Count = 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.BufferCount = 1;
|
||||
swapDesc.OutputWindow = mHwnd;
|
||||
swapDesc.Windowed = TRUE;
|
||||
swapDesc.Flags = 0;
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
|
||||
|
||||
|
||||
/**
|
||||
* Create a swap chain, this swap chain will contain the backbuffer for
|
||||
* the window we draw to. The front buffer is the full screen front
|
||||
* buffer.
|
||||
*/
|
||||
hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
|
||||
if (Failed(hr, "create swap chain")) {
|
||||
*out_failureReason = "FEATURE_FAILURE_D3D11_SWAP_CHAIN";
|
||||
return false;
|
||||
/**
|
||||
* Create a swap chain, this swap chain will contain the backbuffer for
|
||||
* the window we draw to. The front buffer is the full screen front
|
||||
* buffer.
|
||||
*/
|
||||
hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
|
||||
if (Failed(hr, "create swap chain")) {
|
||||
*out_failureReason = "FEATURE_FAILURE_D3D11_SWAP_CHAIN";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We need this because we don't want DXGI to respond to Alt+Enter.
|
||||
dxgiFactory->MakeWindowAssociation(swapDesc.OutputWindow,
|
||||
dxgiFactory->MakeWindowAssociation(mHwnd,
|
||||
DXGI_MWA_NO_WINDOW_CHANGES);
|
||||
}
|
||||
|
||||
|
@ -1262,13 +1304,7 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
|
||||
LayoutDeviceIntSize oldSize = mSize;
|
||||
|
||||
// Failed to create a render target or the view.
|
||||
if (!UpdateRenderTarget() || !mDefaultRT || !mDefaultRT->mRTView ||
|
||||
mSize.width <= 0 || mSize.height <= 0) {
|
||||
ReadUnlockTextures();
|
||||
*aRenderBoundsOut = IntRect();
|
||||
return;
|
||||
}
|
||||
EnsureSize();
|
||||
|
||||
IntRect intRect = IntRect(IntPoint(0, 0), mSize.ToUnknownSize());
|
||||
// Sometimes the invalid region is larger than we want to draw.
|
||||
|
@ -1295,8 +1331,19 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
|
||||
PrepareStaticVertexBuffer();
|
||||
|
||||
mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
|
||||
mInvalidRegion = invalidRegionSafe;
|
||||
mBackBufferInvalid.Or(mBackBufferInvalid, invalidRegionSafe);
|
||||
if (mIsDoubleBuffered) {
|
||||
mFrontBufferInvalid.Or(mFrontBufferInvalid, invalidRegionSafe);
|
||||
}
|
||||
|
||||
// We have to call UpdateRenderTarget after we've determined the invalid regi
|
||||
// Failed to create a render target or the view.
|
||||
if (!UpdateRenderTarget() || !mDefaultRT || !mDefaultRT->mRTView ||
|
||||
mSize.width <= 0 || mSize.height <= 0) {
|
||||
ReadUnlockTextures();
|
||||
*aRenderBoundsOut = IntRect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (aClipRectOut) {
|
||||
*aClipRectOut = IntRect(0, 0, mSize.width, mSize.height);
|
||||
|
@ -1305,14 +1352,14 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
*aRenderBoundsOut = IntRect(0, 0, mSize.width, mSize.height);
|
||||
}
|
||||
|
||||
mCurrentClip = IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
|
||||
mCurrentClip = mBackBufferInvalid.GetBounds();
|
||||
|
||||
mContext->RSSetState(mAttachments->mRasterizerState);
|
||||
|
||||
SetRenderTarget(mDefaultRT);
|
||||
|
||||
// ClearRect will set the correct blend state for us.
|
||||
ClearRect(Rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height));
|
||||
ClearRect(Rect(mCurrentClip.x, mCurrentClip.y, mCurrentClip.width, mCurrentClip.height));
|
||||
|
||||
if (mAttachments->mSyncTexture) {
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
|
@ -1381,17 +1428,22 @@ CompositorD3D11::EndFrame()
|
|||
}
|
||||
|
||||
if (oldSize == mSize) {
|
||||
// This must be called before present so our back buffer has the validated window content.
|
||||
if (mTarget) {
|
||||
PaintToTarget();
|
||||
}
|
||||
|
||||
RefPtr<IDXGISwapChain1> chain;
|
||||
HRESULT hr = mSwapChain->QueryInterface((IDXGISwapChain1**)getter_AddRefs(chain));
|
||||
|
||||
if (SUCCEEDED(hr) && chain && mAllowPartialPresents) {
|
||||
if (SUCCEEDED(hr) && mAllowPartialPresents) {
|
||||
DXGI_PRESENT_PARAMETERS params;
|
||||
PodZero(¶ms);
|
||||
params.DirtyRectsCount = mInvalidRegion.GetNumRects();
|
||||
params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
|
||||
StackArray<RECT, 4> rects(params.DirtyRectsCount);
|
||||
|
||||
uint32_t i = 0;
|
||||
for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const IntRect& r = iter.Get();
|
||||
rects[i].left = r.x;
|
||||
rects[i].top = r.y;
|
||||
|
@ -1403,16 +1455,21 @@ CompositorD3D11::EndFrame()
|
|||
params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr;
|
||||
chain->Present1(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0, ¶ms);
|
||||
} else {
|
||||
hr = mSwapChain->Present(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
|
||||
HRESULT hr = mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "D3D11 swap chain preset failed " << hexa(hr);
|
||||
HandleError(hr);
|
||||
}
|
||||
}
|
||||
mDisableSequenceForNextFrame = false;
|
||||
if (mTarget) {
|
||||
PaintToTarget();
|
||||
|
||||
if (mIsDoubleBuffered) {
|
||||
mBackBufferInvalid = mFrontBufferInvalid;
|
||||
mFrontBufferInvalid.SetEmpty();
|
||||
} else {
|
||||
mBackBufferInvalid.SetEmpty();
|
||||
}
|
||||
|
||||
mDisableSequenceForNextFrame = false;
|
||||
}
|
||||
|
||||
// Block until the previous frame's work has been completed.
|
||||
|
@ -1471,6 +1528,11 @@ CompositorD3D11::ForcePresent()
|
|||
|
||||
if (desc.BufferDesc.Width == size.width && desc.BufferDesc.Height == size.height) {
|
||||
mSwapChain->Present(0, 0);
|
||||
if (mIsDoubleBuffered) {
|
||||
// Make sure we present what was the front buffer before that we know is completely
|
||||
// valid. This non v-synced present should be pretty much 'free' for a flip chain.
|
||||
mSwapChain->Present(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1557,7 +1619,7 @@ CompositorD3D11::VerifyBufferSize()
|
|||
}
|
||||
}
|
||||
|
||||
hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
|
||||
hr = mSwapChain->ResizeBuffers(0, mSize.width, mSize.height,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
0);
|
||||
|
||||
|
@ -1567,31 +1629,28 @@ CompositorD3D11::VerifyBufferSize()
|
|||
HandleError(hr);
|
||||
}
|
||||
|
||||
mBackBufferInvalid = mFrontBufferInvalid = IntRect(0, 0, mSize.width, mSize.height);
|
||||
|
||||
return !mVerifyBuffersFailed;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorD3D11::UpdateRenderTarget()
|
||||
{
|
||||
EnsureSize();
|
||||
HRESULT hr;
|
||||
|
||||
RefPtr<ID3D11Texture2D> backBuf;
|
||||
|
||||
if (!VerifyBufferSize()) {
|
||||
gfxCriticalNote << "Failed VerifyBufferSize in UpdateRenderTarget " << mSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDefaultRT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSize.width <= 0 || mSize.height <= 0) {
|
||||
gfxCriticalNote << "Invalid size in UpdateRenderTarget " << mSize << ", " << (int)mVerifyBuffersFailed;
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
RefPtr<ID3D11Texture2D> backBuf;
|
||||
|
||||
hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuf.StartAssignment());
|
||||
if (hr == DXGI_ERROR_INVALID_CALL) {
|
||||
// This happens on some GPUs/drivers when there's a TDR.
|
||||
|
@ -1600,12 +1659,37 @@ CompositorD3D11::UpdateRenderTarget()
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed in UpdateRenderTarget " << hexa(hr) << ", " << mSize << ", " << (int)mVerifyBuffersFailed;
|
||||
HandleError(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
IntRegion validFront;
|
||||
validFront.Sub(mBackBufferInvalid, mFrontBufferInvalid);
|
||||
|
||||
if (!validFront.IsEmpty()) {
|
||||
RefPtr<ID3D11Texture2D> frontBuf;
|
||||
hr = mSwapChain->GetBuffer(1, __uuidof(ID3D11Texture2D), (void**)frontBuf.StartAssignment());
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
for (auto iter = validFront.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const IntRect& rect = iter.Get();
|
||||
|
||||
D3D11_BOX box;
|
||||
box.back = 1;
|
||||
box.front = 0;
|
||||
box.left = rect.x;
|
||||
box.right = rect.XMost();
|
||||
box.top = rect.y;
|
||||
box.bottom = rect.YMost();
|
||||
mContext->CopySubresourceRegion(backBuf, 0, rect.x, rect.y, 0, frontBuf, 0, &box);
|
||||
}
|
||||
mBackBufferInvalid = mFrontBufferInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0));
|
||||
mDefaultRT->SetSize(mSize.ToUnknownSize());
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/layers/Compositor.h"
|
||||
#include "TextureD3D11.h"
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
class nsWidget;
|
||||
|
||||
|
@ -237,11 +238,12 @@ private:
|
|||
PixelShaderConstants mPSConstants;
|
||||
bool mDisableSequenceForNextFrame;
|
||||
bool mAllowPartialPresents;
|
||||
bool mIsDoubleBuffered;
|
||||
|
||||
gfx::IntRect mInvalidRect;
|
||||
gfx::IntRegion mFrontBufferInvalid;
|
||||
gfx::IntRegion mBackBufferInvalid;
|
||||
// This is the clip rect applied to the default DrawTarget (i.e. the window)
|
||||
gfx::IntRect mCurrentClip;
|
||||
nsIntRegion mInvalidRegion;
|
||||
|
||||
bool mVerifyBuffersFailed;
|
||||
|
||||
|
|
|
@ -412,6 +412,7 @@ private:
|
|||
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.reuse-decoder-device", Direct3D11ReuseDecoderDevice, int32_t, -1);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.allow-intel-mutex", Direct3D11AllowIntelMutex, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.use-double-buffering", Direct3D11UseDoubleBuffering, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_variation_tables", KeepVariationTables, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.otl_validation", ValidateOTLTables, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
|
|
Загрузка…
Ссылка в новой задаче