Bug 1419293 - Create SwapChain with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL if possible in ANGLE r=jgilbert

This commit is contained in:
sotaro 2018-02-01 21:39:31 +09:00
parent 7c3c6a5ff9
commit ae34263b07
9 changed files with 212 additions and 13 deletions

View File

@ -139,6 +139,8 @@ public:
#endif // defined(MOZ_WIDGET_ANDROID)
};
bool CreateConfig(EGLConfig* config, int32_t depth, bool enableDepthBuffer);
} // namespace gl
} // namespace mozilla

View File

@ -84,9 +84,6 @@ using namespace mozilla::widget;
static bool
CreateConfig(EGLConfig* aConfig, bool aEnableDepthBuffer);
static bool
CreateConfig(EGLConfig* aConfig, int32_t depth, bool aEnableDepthBuffer);
// append three zeros at the end of attribs list to work around
// EGL implementation bugs that iterate until they find 0, instead of
// EGL_NONE. See bug 948406.
@ -634,7 +631,7 @@ static const EGLint kEGLConfigAttribsRGBA32[] = {
EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
};
static bool
bool
CreateConfig(EGLConfig* aConfig, int32_t depth, bool aEnableDepthBuffer)
{
EGLConfig configs[64];

View File

@ -53,6 +53,12 @@
#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C
#define LOCAL_EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F
// EGL_ANGLE_d3d_texture_client_buffer
#define LOCAL_EGL_D3D_TEXTURE_ANGLE 0x33A3
// EGL_ANGLE_flexible_surface_compatibility
#define LOCAL_EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6
// EGL_ANGLE_experimental_present_path
#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4
#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9

View File

@ -43,7 +43,7 @@ public:
virtual bool UseANGLE() const { return false; }
virtual LayoutDeviceIntSize GetClientSize() = 0;
virtual LayoutDeviceIntSize GetBufferSize() = 0;
widget::CompositorWidget* GetWidget() const { return mWidget; }

View File

@ -13,8 +13,11 @@
#include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/widget/CompositorWidget.h"
#include "mozilla/widget/WinCompositorWidget.h"
#include "mozilla/WindowsVersion.h"
#include <d3d11.h>
#include <dxgi1_2.h>
namespace mozilla {
namespace wr {
@ -31,6 +34,8 @@ RenderCompositorANGLE::Create(RefPtr<widget::CompositorWidget>&& aWidget)
RenderCompositorANGLE::RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget)
: RenderCompositor(Move(aWidget))
, mEGLConfig(nullptr)
, mEGLSurface(nullptr)
{
}
@ -53,6 +58,74 @@ RenderCompositorANGLE::Initialize()
return false;
}
HWND hwnd = mWidget->AsWindows()->GetHwnd();
RefPtr<IDXGIDevice> dxgiDevice;
mDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
RefPtr<IDXGIFactory> dxgiFactory;
{
RefPtr<IDXGIAdapter> adapter;
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
adapter->GetParent(IID_PPV_ARGS((IDXGIFactory**)getter_AddRefs(dxgiFactory)));
}
RefPtr<IDXGIFactory2> dxgiFactory2;
if (SUCCEEDED(dxgiFactory->QueryInterface((IDXGIFactory2**)getter_AddRefs(dxgiFactory2))) &&
dxgiFactory2 &&
IsWin8OrLater())
{
RefPtr<IDXGISwapChain1> swapChain1;
DXGI_SWAP_CHAIN_DESC1 desc{};
desc.Width = 0;
desc.Height = 0;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.Scaling = DXGI_SCALING_NONE;
desc.Flags = 0;
HRESULT hr = dxgiFactory2->CreateSwapChainForHwnd(mDevice, hwnd, &desc,
nullptr, nullptr,
getter_AddRefs(swapChain1));
if (SUCCEEDED(hr) && swapChain1) {
DXGI_RGBA color = { 1.0f, 1.0f, 1.0f, 1.0f };
swapChain1->SetBackgroundColor(&color);
mSwapChain = swapChain1;
}
}
if (!mSwapChain) {
DXGI_SWAP_CHAIN_DESC 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 = hwnd;
swapDesc.Windowed = TRUE;
swapDesc.Flags = 0;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
HRESULT hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
if (FAILED(hr)) {
gfxCriticalNote << "Could not create swap chain: " << gfx::hexa(hr);
return false;
}
}
// We need this because we don't want DXGI to respond to Alt+Enter.
dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice);
if (!mSyncObject->Init()) {
// Some errors occur. Clear the mSyncObject here.
@ -60,28 +133,49 @@ RenderCompositorANGLE::Initialize()
return false;
}
mGL = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, true);
const auto flags = gl::CreateContextFlags::PREFER_ES3;
// Create GLContext with dummy EGLSurface, the EGLSurface is not used.
// Instread we override it with EGLSurface of SwapChain's back buffer.
nsCString discardFailureId;
mGL = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId);
if (!mGL || !mGL->IsANGLE()) {
gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get());
return false;
}
if (!mGL->MakeCurrent()) {
gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(mGL.get());
return false;
}
// Force enable alpha channel to make sure ANGLE use correct framebuffer formart
if (!gl::CreateConfig(&mEGLConfig, /* bpp */ 32, /* enableDepthBuffer */ true)) {
gfxCriticalNote << "Failed to create EGLConfig for WebRender";
}
MOZ_ASSERT(mEGLConfig);
if (!ResizeBufferIfNeeded()) {
return false;
}
return true;
}
bool
RenderCompositorANGLE::Destroy()
{
DestroyEGLSurface();
return true;
}
bool
RenderCompositorANGLE::BeginFrame()
{
if (!ResizeBufferIfNeeded()) {
return false;
}
if (!mGL->MakeCurrent()) {
gfxCriticalNote << "Failed to make render context current, can't draw.";
return false;
@ -99,7 +193,7 @@ RenderCompositorANGLE::EndFrame()
{
InsertPresentWaitQuery();
mGL->SwapBuffers();
mSwapChain->Present(0, 0);
// Note: this waits on the query we inserted in the previous frame,
// not the one we just inserted now. Example:
@ -117,6 +211,94 @@ RenderCompositorANGLE::EndFrame()
WaitForPreviousPresentQuery();
}
bool
RenderCompositorANGLE::ResizeBufferIfNeeded()
{
MOZ_ASSERT(mSwapChain);
LayoutDeviceIntSize size = mWidget->GetClientSize();
// Set size to non negative.
size.width = std::max(size.width, 0);
size.height = std::max(size.height, 0);
if (mBufferSize.isSome() && mBufferSize.ref() == size) {
MOZ_ASSERT(mEGLSurface);
return true;
}
HRESULT hr;
RefPtr<ID3D11Texture2D> backBuf;
// Release EGLSurface of back buffer before calling ResizeBuffers().
DestroyEGLSurface();
// Reset buffer size
mBufferSize.reset();
// Resize swap chain
DXGI_SWAP_CHAIN_DESC desc;
hr = mSwapChain->GetDesc(&desc);
if (FAILED(hr)) {
gfxCriticalNote << "Failed to read swap chain description: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
hr = mSwapChain->ResizeBuffers(desc.BufferCount, size.width, size.height, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
if (FAILED(hr)) {
gfxCriticalNote << "Failed to resize swap chain buffers: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)getter_AddRefs(backBuf));
if (hr == DXGI_ERROR_INVALID_CALL) {
// This happens on some GPUs/drivers when there's a TDR.
if (mDevice->GetDeviceRemovedReason() != S_OK) {
gfxCriticalError() << "GetBuffer returned invalid call: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
}
const auto& egl = &gl::sEGLLibrary;
const EGLint pbuffer_attribs[]{
LOCAL_EGL_WIDTH, size.width,
LOCAL_EGL_HEIGHT, size.height,
LOCAL_EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, LOCAL_EGL_TRUE,
LOCAL_EGL_NONE};
const auto buffer = reinterpret_cast<EGLClientBuffer>(backBuf.get());
const EGLSurface surface = egl->fCreatePbufferFromClientBuffer(
egl->Display(), LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, mEGLConfig,
pbuffer_attribs);
EGLint err = egl->fGetError();
if (err != LOCAL_EGL_SUCCESS) {
gfxCriticalError() << "Failed to create Pbuffer of back buffer error: " << gfx::hexa(err) << " Size : " << size;
return false;
}
gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(surface);
mEGLSurface = surface;
mBufferSize = Some(size);
return true;
}
void
RenderCompositorANGLE::DestroyEGLSurface()
{
const auto& egl = &gl::sEGLLibrary;
// Release EGLSurface of back buffer before calling ResizeBuffers().
if (mEGLSurface) {
gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
egl->fDestroySurface(egl->Display(), mEGLSurface);
mEGLSurface = nullptr;
}
}
void
RenderCompositorANGLE::Pause()
{
@ -129,9 +311,13 @@ RenderCompositorANGLE::Resume()
}
LayoutDeviceIntSize
RenderCompositorANGLE::GetClientSize()
RenderCompositorANGLE::GetBufferSize()
{
return mWidget->GetClientSize();
MOZ_ASSERT(mBufferSize.isSome());
if (mBufferSize.isNothing()) {
return LayoutDeviceIntSize();
}
return mBufferSize.ref();
}
void

View File

@ -7,11 +7,13 @@
#ifndef MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
#define MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
#include "mozilla/Maybe.h"
#include "mozilla/webrender/RenderCompositor.h"
struct ID3D11DeviceContext;
struct ID3D11Device;
struct ID3D11Query;
struct IDXGISwapChain;
namespace mozilla {
@ -36,20 +38,26 @@ public:
bool UseANGLE() const override { return true; }
LayoutDeviceIntSize GetClientSize() override;
LayoutDeviceIntSize GetBufferSize() override;
protected:
void InsertPresentWaitQuery();
void WaitForPreviousPresentQuery();
bool ResizeBufferIfNeeded();
void DestroyEGLSurface();
RefPtr<gl::GLContext> mGL;
EGLConfig mEGLConfig;
EGLSurface mEGLSurface;
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mCtx;
RefPtr<IDXGISwapChain> mSwapChain;
RefPtr<ID3D11Query> mWaitForPresentQuery;
RefPtr<ID3D11Query> mNextWaitForPresentQuery;
Maybe<LayoutDeviceIntSize> mBufferSize;
};
} // namespace wr

View File

@ -86,7 +86,7 @@ RenderCompositorOGL::Resume()
}
LayoutDeviceIntSize
RenderCompositorOGL::GetClientSize()
RenderCompositorOGL::GetBufferSize()
{
return mWidget->GetClientSize();
}

View File

@ -32,7 +32,7 @@ public:
bool UseANGLE() const override { return false; }
LayoutDeviceIntSize GetClientSize() override;
LayoutDeviceIntSize GetBufferSize() override;
protected:
RefPtr<gl::GLContext> mGL;

View File

@ -113,7 +113,7 @@ RendererOGL::UpdateAndRender()
wr_renderer_update(mRenderer);
auto size = mCompositor->GetClientSize();
auto size = mCompositor->GetBufferSize();
if (!wr_renderer_render(mRenderer, size.width, size.height)) {
NotifyWebRenderError(WebRenderError::RENDER);