mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-13 19:41:49 +00:00
Bug 1419293 - Create SwapChain with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL if possible in ANGLE r=jgilbert
This commit is contained in:
parent
7c3c6a5ff9
commit
ae34263b07
@ -139,6 +139,8 @@ public:
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
};
|
||||
|
||||
bool CreateConfig(EGLConfig* config, int32_t depth, bool enableDepthBuffer);
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -86,7 +86,7 @@ RenderCompositorOGL::Resume()
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize
|
||||
RenderCompositorOGL::GetClientSize()
|
||||
RenderCompositorOGL::GetBufferSize()
|
||||
{
|
||||
return mWidget->GetClientSize();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
|
||||
bool UseANGLE() const override { return false; }
|
||||
|
||||
LayoutDeviceIntSize GetClientSize() override;
|
||||
LayoutDeviceIntSize GetBufferSize() override;
|
||||
|
||||
protected:
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user