Commit 722b0d31 by Geoff Lang

Add a WGL Surface implementation that renders to a DXGI swap chain.

This avoids sandbox issues when calling SetPixelFormat on windows from other processes while in a sandboxed process. BUG=540829 Change-Id: I012168531d8c2e5b189671533cea9f57ec713538 Reviewed-on: https://chromium-review.googlesource.com/296340Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Tryjob-Request: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 0dfa807f
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DXGISwapChainWindowSurfaceWGL.cpp: WGL implementation of egl::Surface for windows using a DXGI
// swapchain.
#include "libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h"
#include <EGL/eglext.h>
namespace rx
{
DXGISwapChainWindowSurfaceWGL::DXGISwapChainWindowSurfaceWGL(RendererGL *renderer,
EGLNativeWindowType window,
ID3D11Device *device,
HANDLE deviceHandle,
HGLRC wglContext,
HDC deviceContext,
const FunctionsGL *functionsGL,
const FunctionsWGL *functionsWGL,
EGLint orientation)
: SurfaceGL(renderer),
mWindow(window),
mStateManager(renderer->getStateManager()),
mWorkarounds(renderer->getWorkarounds()),
mFunctionsGL(functionsGL),
mFunctionsWGL(functionsWGL),
mDevice(device),
mDeviceHandle(deviceHandle),
mWGLDevice(deviceContext),
mWGLContext(wglContext),
mSwapChainFormat(DXGI_FORMAT_UNKNOWN),
mSwapChainFlags(0),
mDepthBufferFormat(GL_NONE),
mFirstSwap(true),
mSwapChain(nullptr),
mSwapChain1(nullptr),
mColorRenderbufferID(0),
mRenderbufferBufferHandle(nullptr),
mDepthRenderbufferID(0),
mFramebufferID(0),
mTextureID(0),
mTextureHandle(nullptr),
mWidth(0),
mHeight(0),
mSwapInterval(1),
mOrientation(orientation)
{
}
DXGISwapChainWindowSurfaceWGL::~DXGISwapChainWindowSurfaceWGL()
{
if (mRenderbufferBufferHandle != nullptr)
{
mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mRenderbufferBufferHandle);
mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mRenderbufferBufferHandle);
}
if (mColorRenderbufferID != 0)
{
mStateManager->deleteRenderbuffer(mColorRenderbufferID);
mColorRenderbufferID = 0;
}
if (mDepthRenderbufferID != 0)
{
mStateManager->deleteRenderbuffer(mDepthRenderbufferID);
mDepthRenderbufferID = 0;
}
SafeRelease(mSwapChain);
SafeRelease(mSwapChain1);
}
egl::Error DXGISwapChainWindowSurfaceWGL::initialize()
{
if (mOrientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE)
{
// TODO(geofflang): Support the orientation extensions fully. Currently only inverting Y is
// supported. To support all orientations, an intermediate framebuffer will be needed with
// a blit before swap.
return egl::Error(EGL_BAD_ATTRIBUTE,
"DXGISwapChainWindowSurfaceWGL requires an orientation of "
"EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE.");
}
RECT rect;
if (!GetClientRect(mWindow, &rect))
{
return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the window size.");
}
mWidth = rect.right - rect.left;
mHeight = rect.bottom - rect.top;
mSwapChainFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
mSwapChainFlags = 0;
mDepthBufferFormat = GL_DEPTH24_STENCIL8;
mFunctionsGL->genFramebuffers(1, &mFramebufferID);
mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID);
mFunctionsGL->genRenderbuffers(1, &mDepthRenderbufferID);
return createSwapChain();
}
egl::Error DXGISwapChainWindowSurfaceWGL::makeCurrent()
{
if (!mFunctionsWGL->makeCurrent(mWGLDevice, mWGLContext))
{
// TODO: What error type here?
return egl::Error(EGL_CONTEXT_LOST, "Failed to make the WGL context current.");
}
return egl::Error(EGL_SUCCESS);
}
egl::Error DXGISwapChainWindowSurfaceWGL::swap()
{
mFunctionsGL->flush();
egl::Error error = setObjectsLocked(false);
if (error.isError())
{
return error;
}
HRESULT result = mSwapChain->Present(mSwapInterval, 0);
mFirstSwap = false;
error = setObjectsLocked(true);
if (error.isError())
{
return error;
}
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to present swap chain, result: 0x%X", result);
}
return checkForResize();
}
egl::Error DXGISwapChainWindowSurfaceWGL::postSubBuffer(EGLint x,
EGLint y,
EGLint width,
EGLint height)
{
ASSERT(mSwapChain1 != nullptr);
mFunctionsGL->flush();
egl::Error error = setObjectsLocked(false);
if (error.isError())
{
return error;
}
HRESULT result = S_OK;
if (mFirstSwap)
{
result = mSwapChain1->Present(mSwapInterval, 0);
mFirstSwap = false;
}
else
{
RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr};
result = mSwapChain1->Present1(mSwapInterval, 0, &params);
}
error = setObjectsLocked(true);
if (error.isError())
{
return error;
}
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to present swap chain, result: 0x%X", result);
}
return checkForResize();
}
egl::Error DXGISwapChainWindowSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value)
{
UNREACHABLE();
return egl::Error(EGL_SUCCESS);
}
egl::Error DXGISwapChainWindowSurfaceWGL::bindTexImage(gl::Texture *texture, EGLint buffer)
{
ASSERT(mTextureHandle == nullptr);
const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
GLuint textureID = textureGL->getTextureID();
ID3D11Texture2D *colorBuffer = nullptr;
HRESULT result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
reinterpret_cast<void **>(&colorBuffer));
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to query texture from swap chain, result: 0x%X",
result);
}
mTextureHandle = mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, textureID,
GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
SafeRelease(colorBuffer);
if (mTextureHandle == nullptr)
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%08x.",
HRESULT_CODE(error));
}
if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mTextureHandle))
{
mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle);
mTextureHandle = nullptr;
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to lock D3D object, error: 0x%08x.",
HRESULT_CODE(error));
}
mTextureID = textureID;
return egl::Error(EGL_SUCCESS);
}
egl::Error DXGISwapChainWindowSurfaceWGL::releaseTexImage(EGLint buffer)
{
ASSERT(mTextureHandle != nullptr);
if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mTextureHandle))
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to unlock D3D object, error: 0x%08x.",
HRESULT_CODE(error));
}
if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle))
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to unregister D3D object, error: 0x%08x.",
HRESULT_CODE(error));
}
mTextureID = 0;
mTextureHandle = nullptr;
return egl::Error(EGL_SUCCESS);
}
void DXGISwapChainWindowSurfaceWGL::setSwapInterval(EGLint interval)
{
mSwapInterval = interval;
}
EGLint DXGISwapChainWindowSurfaceWGL::getWidth() const
{
return static_cast<EGLint>(mWidth);
}
EGLint DXGISwapChainWindowSurfaceWGL::getHeight() const
{
return static_cast<EGLint>(mHeight);
}
EGLint DXGISwapChainWindowSurfaceWGL::isPostSubBufferSupported() const
{
return mSwapChain1 != nullptr;
}
EGLint DXGISwapChainWindowSurfaceWGL::getSwapBehavior() const
{
return EGL_BUFFER_DESTROYED;
}
FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
const gl::Framebuffer::Data &data)
{
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, mStateManager);
}
egl::Error DXGISwapChainWindowSurfaceWGL::setObjectsLocked(bool locked)
{
if (mRenderbufferBufferHandle == nullptr)
{
ASSERT(mTextureHandle == nullptr);
return egl::Error(EGL_SUCCESS);
}
HANDLE resources[] = {
mRenderbufferBufferHandle, mTextureHandle,
};
GLint count = (mTextureHandle != nullptr) ? 2 : 1;
if (locked)
{
if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, count, resources))
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to lock object, error: 0x%08x.",
HRESULT_CODE(error));
}
}
else
{
if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, count, resources))
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to lock object, error: 0x%08x.",
HRESULT_CODE(error));
}
}
return egl::Error(EGL_SUCCESS);
}
egl::Error DXGISwapChainWindowSurfaceWGL::checkForResize()
{
RECT rect;
if (!GetClientRect(mWindow, &rect))
{
return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the window size.");
}
size_t newWidth = rect.right - rect.left;
size_t newHeight = rect.bottom - rect.top;
if (newWidth != mWidth || newHeight != mHeight)
{
mWidth = newWidth;
mHeight = newHeight;
// TODO(geofflang): Handle resize by resizing the swap chain instead of re-creating it.
egl::Error error = createSwapChain();
if (error.isError())
{
return error;
}
}
return egl::Error(EGL_SUCCESS);
}
static IDXGIFactory *GetDXGIFactoryFromDevice(ID3D11Device *device)
{
IDXGIDevice *dxgiDevice = nullptr;
HRESULT result =
device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDevice));
if (FAILED(result))
{
return nullptr;
}
IDXGIAdapter *dxgiAdapter = nullptr;
result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void **>(&dxgiAdapter));
SafeRelease(dxgiDevice);
if (FAILED(result))
{
return nullptr;
}
IDXGIFactory *dxgiFactory = nullptr;
result =
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&dxgiFactory));
SafeRelease(dxgiAdapter);
if (FAILED(result))
{
return nullptr;
}
return dxgiFactory;
}
egl::Error DXGISwapChainWindowSurfaceWGL::createSwapChain()
{
egl::Error error = setObjectsLocked(false);
if (error.isError())
{
return error;
}
if (mRenderbufferBufferHandle)
{
mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mRenderbufferBufferHandle);
mRenderbufferBufferHandle = nullptr;
}
// If this surface is bound to a texture, unregister it.
bool hadBoundSurface = (mTextureHandle != nullptr);
if (hadBoundSurface)
{
mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle);
mTextureHandle = nullptr;
}
IDXGIFactory *dxgiFactory = GetDXGIFactoryFromDevice(mDevice);
if (dxgiFactory == nullptr)
{
return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the DXGIFactory.");
}
IDXGIFactory2 *dxgiFactory2 = nullptr;
HRESULT result = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2),
reinterpret_cast<void **>(&dxgiFactory2));
if (SUCCEEDED(result))
{
ASSERT(dxgiFactory2 != nullptr);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.BufferCount = 1;
swapChainDesc.Format = mSwapChainFormat;
swapChainDesc.Width = static_cast<UINT>(mWidth);
swapChainDesc.Height = static_cast<UINT>(mHeight);
swapChainDesc.Format = mSwapChainFormat;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage =
DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = mSwapChainFlags;
result = dxgiFactory2->CreateSwapChainForHwnd(mDevice, mWindow, &swapChainDesc, nullptr,
nullptr, &mSwapChain1);
SafeRelease(dxgiFactory2);
SafeRelease(dxgiFactory);
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to create swap chain for window, result: 0x%X",
result);
}
mSwapChain = mSwapChain1;
mSwapChain->AddRef();
}
else
{
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Format = mSwapChainFormat;
swapChainDesc.BufferDesc.Width = static_cast<UINT>(mWidth);
swapChainDesc.BufferDesc.Height = static_cast<UINT>(mHeight);
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage =
DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.Flags = mSwapChainFlags;
swapChainDesc.OutputWindow = mWindow;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
result = dxgiFactory->CreateSwapChain(mDevice, &swapChainDesc, &mSwapChain);
SafeRelease(dxgiFactory);
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to create swap chain for window, result: 0x%X",
result);
}
}
ID3D11Texture2D *colorBuffer = nullptr;
result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
reinterpret_cast<void **>(&colorBuffer));
if (FAILED(result))
{
return egl::Error(EGL_BAD_ALLOC, "Failed to query texture from swap chain, result: 0x%X",
result);
}
mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID);
mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID);
mRenderbufferBufferHandle =
mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, mColorRenderbufferID,
GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
SafeRelease(colorBuffer);
if (mRenderbufferBufferHandle == nullptr)
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%X.",
HRESULT_CODE(error));
}
// Rebind the surface to the texture if needed.
if (hadBoundSurface)
{
mTextureHandle = mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, mTextureID,
GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
if (mTextureHandle == nullptr)
{
DWORD error = GetLastError();
return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%X.",
HRESULT_CODE(error));
}
}
error = setObjectsLocked(true);
if (error.isError())
{
return error;
}
ASSERT(mFramebufferID != 0);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
mColorRenderbufferID);
if (mDepthBufferFormat != GL_NONE)
{
ASSERT(mDepthRenderbufferID != 0);
mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbufferID);
mFunctionsGL->renderbufferStorage(GL_RENDERBUFFER, mDepthBufferFormat,
static_cast<GLsizei>(mWidth),
static_cast<GLsizei>(mHeight));
const gl::InternalFormat &depthStencilFormatInfo =
gl::GetInternalFormatInfo(mDepthBufferFormat);
if (depthStencilFormatInfo.depthBits > 0)
{
mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, mDepthRenderbufferID);
}
if (depthStencilFormatInfo.stencilBits > 0)
{
mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, mDepthRenderbufferID);
}
}
mFirstSwap = true;
return egl::Error(EGL_SUCCESS);
}
} // namespace rx
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DXGISwapChainWindowSurfaceWGL.h: WGL implementation of egl::Surface for windows using a DXGI
// swapchain.
#ifndef LIBANGLE_RENDERER_GL_WGL_DXGISWAPCHAINSURFACEWGL_H_
#define LIBANGLE_RENDERER_GL_WGL_DXGISWAPCHAINSURFACEWGL_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include <GL/wglext.h>
namespace rx
{
class FunctionsGL;
class FunctionsWGL;
class DisplayWGL;
class StateManagerGL;
struct WorkaroundsGL;
class DXGISwapChainWindowSurfaceWGL : public SurfaceGL
{
public:
DXGISwapChainWindowSurfaceWGL(RendererGL *renderer,
EGLNativeWindowType window,
ID3D11Device *device,
HANDLE deviceHandle,
HGLRC wglContext,
HDC deviceContext,
const FunctionsGL *functionsGL,
const FunctionsWGL *functionsWGL,
EGLint orientation);
~DXGISwapChainWindowSurfaceWGL() override;
egl::Error initialize() override;
egl::Error makeCurrent() override;
egl::Error swap() override;
egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override;
egl::Error releaseTexImage(EGLint buffer) override;
void setSwapInterval(EGLint interval) override;
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override;
private:
egl::Error setObjectsLocked(bool locked);
egl::Error checkForResize();
egl::Error createSwapChain();
EGLNativeWindowType mWindow;
StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds;
const FunctionsGL *mFunctionsGL;
const FunctionsWGL *mFunctionsWGL;
ID3D11Device *mDevice;
HANDLE mDeviceHandle;
HDC mWGLDevice;
HGLRC mWGLContext;
DXGI_FORMAT mSwapChainFormat;
UINT mSwapChainFlags;
GLenum mDepthBufferFormat;
bool mFirstSwap;
IDXGISwapChain *mSwapChain;
IDXGISwapChain1 *mSwapChain1;
GLuint mColorRenderbufferID;
HANDLE mRenderbufferBufferHandle;
GLuint mDepthRenderbufferID;
GLuint mFramebufferID;
GLuint mTextureID;
HANDLE mTextureHandle;
size_t mWidth;
size_t mHeight;
EGLint mSwapInterval;
EGLint mOrientation;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_WGL_DXGISWAPCHAINSURFACEWGL_H_
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/renderergl_utils.h" #include "libANGLE/renderer/gl/renderergl_utils.h"
#include "libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h"
#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" #include "libANGLE/renderer/gl/wgl/FunctionsWGL.h"
#include "libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h" #include "libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h"
#include "libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h" #include "libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h"
...@@ -65,6 +66,11 @@ DisplayWGL::DisplayWGL() ...@@ -65,6 +66,11 @@ DisplayWGL::DisplayWGL()
mDeviceContext(nullptr), mDeviceContext(nullptr),
mPixelFormat(0), mPixelFormat(0),
mWGLContext(nullptr), mWGLContext(nullptr),
mUseDXGISwapChains(false),
mDxgiModule(nullptr),
mD3d11Module(nullptr),
mD3D11DeviceHandle(nullptr),
mD3D11Device(nullptr),
mDisplay(nullptr) mDisplay(nullptr)
{ {
} }
...@@ -323,6 +329,31 @@ egl::Error DisplayWGL::initialize(egl::Display *display) ...@@ -323,6 +329,31 @@ egl::Error DisplayWGL::initialize(egl::Display *display)
mFunctionsGL = new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress); mFunctionsGL = new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress);
mFunctionsGL->initialize(); mFunctionsGL->initialize();
// Create DXGI swap chains for windows that come from other processes. Windows is unable to
// SetPixelFormat on windows from other processes when a sandbox is enabled.
HDC nativeDisplay = display->getNativeDisplayId();
HWND nativeWindow = WindowFromDC(nativeDisplay);
if (nativeWindow != nullptr)
{
DWORD currentProcessId = GetCurrentProcessId();
DWORD windowProcessId;
GetWindowThreadProcessId(nativeWindow, &windowProcessId);
mUseDXGISwapChains = (currentProcessId != windowProcessId);
}
else
{
mUseDXGISwapChains = false;
}
if (mUseDXGISwapChains)
{
egl::Error error = initializeD3DDevice();
if (error.isError())
{
return error;
}
}
return DisplayGL::initialize(display); return DisplayGL::initialize(display);
} }
...@@ -330,6 +361,8 @@ void DisplayWGL::terminate() ...@@ -330,6 +361,8 @@ void DisplayWGL::terminate()
{ {
DisplayGL::terminate(); DisplayGL::terminate();
releaseD3DDevice(mD3D11DeviceHandle);
mFunctionsWGL->makeCurrent(mDeviceContext, NULL); mFunctionsWGL->makeCurrent(mDeviceContext, NULL);
mFunctionsWGL->deleteContext(mWGLContext); mFunctionsWGL->deleteContext(mWGLContext);
mWGLContext = NULL; mWGLContext = NULL;
...@@ -348,14 +381,40 @@ void DisplayWGL::terminate() ...@@ -348,14 +381,40 @@ void DisplayWGL::terminate()
FreeLibrary(mOpenGLModule); FreeLibrary(mOpenGLModule);
mOpenGLModule = nullptr; mOpenGLModule = nullptr;
SafeRelease(mD3D11Device);
if (mDxgiModule)
{
FreeLibrary(mDxgiModule);
mDxgiModule = nullptr;
}
if (mD3d11Module)
{
FreeLibrary(mD3d11Module);
mD3d11Module = nullptr;
}
ASSERT(mRegisteredD3DDevices.empty());
} }
SurfaceImpl *DisplayWGL::createWindowSurface(const egl::Config *configuration, SurfaceImpl *DisplayWGL::createWindowSurface(const egl::Config *configuration,
EGLNativeWindowType window, EGLNativeWindowType window,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
EGLint orientation = attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
if (mUseDXGISwapChains)
{
return new DXGISwapChainWindowSurfaceWGL(this->getRenderer(), window, mD3D11Device,
mD3D11DeviceHandle, mWGLContext, mDeviceContext,
mFunctionsGL, mFunctionsWGL, orientation);
}
else
{
return new WindowSurfaceWGL(this->getRenderer(), window, mPixelFormat, mWGLContext, return new WindowSurfaceWGL(this->getRenderer(), window, mPixelFormat, mWGLContext,
mFunctionsWGL); mFunctionsWGL, orientation);
}
} }
SurfaceImpl *DisplayWGL::createPbufferSurface(const egl::Config *configuration, SurfaceImpl *DisplayWGL::createPbufferSurface(const egl::Config *configuration,
...@@ -418,6 +477,9 @@ egl::ConfigSet DisplayWGL::generateConfigs() const ...@@ -418,6 +477,9 @@ egl::ConfigSet DisplayWGL::generateConfigs() const
return wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, attrib, mFunctionsWGL); return wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, attrib, mFunctionsWGL);
}; };
const EGLint optimalSurfaceOrientation =
mUseDXGISwapChains ? EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE : 0;
egl::Config config; egl::Config config;
config.renderTargetFormat = GL_RGBA8; // TODO: use the bit counts to determine the format config.renderTargetFormat = GL_RGBA8; // TODO: use the bit counts to determine the format
config.depthStencilFormat = GL_DEPTH24_STENCIL8; // TODO: use the bit counts to determine the format config.depthStencilFormat = GL_DEPTH24_STENCIL8; // TODO: use the bit counts to determine the format
...@@ -453,6 +515,8 @@ egl::ConfigSet DisplayWGL::generateConfigs() const ...@@ -453,6 +515,8 @@ egl::ConfigSet DisplayWGL::generateConfigs() const
((getAttrib(WGL_DRAW_TO_PBUFFER_ARB) == TRUE) ? EGL_PBUFFER_BIT : 0) | ((getAttrib(WGL_DRAW_TO_PBUFFER_ARB) == TRUE) ? EGL_PBUFFER_BIT : 0) |
((getAttrib(WGL_SWAP_METHOD_ARB) == WGL_SWAP_COPY_ARB) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT ((getAttrib(WGL_SWAP_METHOD_ARB) == WGL_SWAP_COPY_ARB) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT
: 0); : 0);
config.optimalOrientation = optimalSurfaceOrientation;
config.transparentType = EGL_NONE; config.transparentType = EGL_NONE;
config.transparentRedValue = 0; config.transparentRedValue = 0;
config.transparentGreenValue = 0; config.transparentGreenValue = 0;
...@@ -497,10 +561,60 @@ const FunctionsGL *DisplayWGL::getFunctionsGL() const ...@@ -497,10 +561,60 @@ const FunctionsGL *DisplayWGL::getFunctionsGL() const
return mFunctionsGL; return mFunctionsGL;
} }
egl::Error DisplayWGL::initializeD3DDevice()
{
if (mD3D11Device != nullptr)
{
return egl::Error(EGL_SUCCESS);
}
mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
if (!mDxgiModule)
{
return egl::Error(EGL_NOT_INITIALIZED, "Failed to load DXGI library.");
}
mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
if (!mD3d11Module)
{
return egl::Error(EGL_NOT_INITIALIZED, "Failed to load d3d11 library.");
}
PFN_D3D11_CREATE_DEVICE d3d11CreateDevice = nullptr;
d3d11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
if (d3d11CreateDevice == nullptr)
{
return egl::Error(EGL_NOT_INITIALIZED, "Could not retrieve D3D11CreateDevice address.");
}
HRESULT result = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr);
if (FAILED(result))
{
return egl::Error(EGL_NOT_INITIALIZED, "Could not create D3D11 device, error: 0x%X",
result);
}
egl::Error error = registerD3DDevice(mD3D11Device, &mD3D11DeviceHandle);
if (error.isError())
{
return error;
}
return egl::Error(EGL_SUCCESS);
}
void DisplayWGL::generateExtensions(egl::DisplayExtensions *outExtensions) const void DisplayWGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{ {
outExtensions->createContext = true; outExtensions->createContext = true;
outExtensions->createContextNoError = true; outExtensions->createContextNoError = true;
// Only enable the surface orientation and post sub buffer for DXGI swap chain surfaces, they
// prefer to swap with
// inverted Y.
outExtensions->postSubBuffer = mUseDXGISwapChains;
outExtensions->surfaceOrientation = mUseDXGISwapChains;
} }
void DisplayWGL::generateCaps(egl::Caps *outCaps) const void DisplayWGL::generateCaps(egl::Caps *outCaps) const
...@@ -521,4 +635,52 @@ egl::Error DisplayWGL::waitNative(EGLint engine, ...@@ -521,4 +635,52 @@ egl::Error DisplayWGL::waitNative(EGLint engine,
// Unimplemented as this is not needed for WGL // Unimplemented as this is not needed for WGL
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error DisplayWGL::registerD3DDevice(IUnknown *device, HANDLE *outHandle)
{
ASSERT(device != nullptr);
ASSERT(outHandle != nullptr);
auto iter = mRegisteredD3DDevices.find(device);
if (iter != mRegisteredD3DDevices.end())
{
iter->second.refCount++;
*outHandle = iter->second.handle;
return egl::Error(EGL_SUCCESS);
}
HANDLE handle = mFunctionsWGL->dxOpenDeviceNV(device);
if (!handle)
{
return egl::Error(EGL_BAD_PARAMETER, "Failed to open D3D device.");
}
device->AddRef();
D3DObjectHandle newDeviceInfo;
newDeviceInfo.handle = handle;
newDeviceInfo.refCount = 1;
mRegisteredD3DDevices[device] = newDeviceInfo;
*outHandle = handle;
return egl::Error(EGL_SUCCESS);
}
void DisplayWGL::releaseD3DDevice(HANDLE deviceHandle)
{
for (auto iter = mRegisteredD3DDevices.begin(); iter != mRegisteredD3DDevices.end(); iter++)
{
if (iter->second.handle == deviceHandle)
{
iter->second.refCount--;
if (iter->second.refCount == 0)
{
mFunctionsWGL->dxCloseDeviceNV(iter->second.handle);
iter->first->Release();
mRegisteredD3DDevices.erase(iter);
break;
}
}
}
}
} }
...@@ -57,9 +57,14 @@ class DisplayWGL : public DisplayGL ...@@ -57,9 +57,14 @@ class DisplayWGL : public DisplayGL
egl::Surface *drawSurface, egl::Surface *drawSurface,
egl::Surface *readSurface) const override; egl::Surface *readSurface) const override;
egl::Error registerD3DDevice(IUnknown *device, HANDLE *outHandle);
void releaseD3DDevice(HANDLE handle);
private: private:
const FunctionsGL *getFunctionsGL() const override; const FunctionsGL *getFunctionsGL() const override;
egl::Error initializeD3DDevice();
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override; void generateCaps(egl::Caps *outCaps) const override;
...@@ -74,6 +79,19 @@ class DisplayWGL : public DisplayGL ...@@ -74,6 +79,19 @@ class DisplayWGL : public DisplayGL
int mPixelFormat; int mPixelFormat;
HGLRC mWGLContext; HGLRC mWGLContext;
bool mUseDXGISwapChains;
HMODULE mDxgiModule;
HMODULE mD3d11Module;
HANDLE mD3D11DeviceHandle;
ID3D11Device *mD3D11Device;
struct D3DObjectHandle
{
HANDLE handle;
size_t refCount;
};
std::map<IUnknown *, D3DObjectHandle> mRegisteredD3DDevices;
egl::Display *mDisplay; egl::Display *mDisplay;
}; };
......
...@@ -20,7 +20,8 @@ WindowSurfaceWGL::WindowSurfaceWGL(RendererGL *renderer, ...@@ -20,7 +20,8 @@ WindowSurfaceWGL::WindowSurfaceWGL(RendererGL *renderer,
EGLNativeWindowType window, EGLNativeWindowType window,
int pixelFormat, int pixelFormat,
HGLRC wglContext, HGLRC wglContext,
const FunctionsWGL *functions) const FunctionsWGL *functions,
EGLint orientation)
: SurfaceGL(renderer), : SurfaceGL(renderer),
mPixelFormat(pixelFormat), mPixelFormat(pixelFormat),
mWGLContext(wglContext), mWGLContext(wglContext),
...@@ -29,6 +30,8 @@ WindowSurfaceWGL::WindowSurfaceWGL(RendererGL *renderer, ...@@ -29,6 +30,8 @@ WindowSurfaceWGL::WindowSurfaceWGL(RendererGL *renderer,
mFunctionsWGL(functions), mFunctionsWGL(functions),
mSwapBehavior(0) mSwapBehavior(0)
{ {
// EGL_ANGLE_surface_orientation is not supported for regular WGL window surfaces
ASSERT(orientation == 0);
} }
WindowSurfaceWGL::~WindowSurfaceWGL() WindowSurfaceWGL::~WindowSurfaceWGL()
......
...@@ -25,7 +25,8 @@ class WindowSurfaceWGL : public SurfaceGL ...@@ -25,7 +25,8 @@ class WindowSurfaceWGL : public SurfaceGL
EGLNativeWindowType window, EGLNativeWindowType window,
int pixelFormat, int pixelFormat,
HGLRC wglContext, HGLRC wglContext,
const FunctionsWGL *functions); const FunctionsWGL *functions,
EGLint orientation);
~WindowSurfaceWGL() override; ~WindowSurfaceWGL() override;
egl::Error initialize() override; egl::Error initialize() override;
......
...@@ -461,6 +461,8 @@ ...@@ -461,6 +461,8 @@
[ [
'libANGLE/renderer/gl/wgl/DisplayWGL.cpp', 'libANGLE/renderer/gl/wgl/DisplayWGL.cpp',
'libANGLE/renderer/gl/wgl/DisplayWGL.h', 'libANGLE/renderer/gl/wgl/DisplayWGL.h',
'libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp',
'libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h',
'libANGLE/renderer/gl/wgl/FunctionsWGL.cpp', 'libANGLE/renderer/gl/wgl/FunctionsWGL.cpp',
'libANGLE/renderer/gl/wgl/FunctionsWGL.h', 'libANGLE/renderer/gl/wgl/FunctionsWGL.h',
'libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.cpp', 'libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.cpp',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment