diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp new file mode 100755 index 000000000..7c5214e82 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.cpp @@ -0,0 +1,553 @@ +// +// 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(const egl::SurfaceState &state, + RendererGL *renderer, + EGLNativeWindowType window, + ID3D11Device *device, + HANDLE deviceHandle, + HGLRC wglContext, + HDC deviceContext, + const FunctionsGL *functionsGL, + const FunctionsWGL *functionsWGL, + EGLint orientation) + : SurfaceGL(state, renderer), + mWindow(window), + mStateManager(renderer->getStateManager()), + mWorkarounds(renderer->getWorkarounds()), + mRenderer(renderer), + 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, ¶ms); + } + + 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) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + + if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mTextureHandle)) + { + mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle); + mTextureHandle = nullptr; + + return egl::Error(EGL_BAD_ALLOC, "Failed to lock D3D object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + + mTextureID = textureID; + + return egl::Error(EGL_SUCCESS); +} + +egl::Error DXGISwapChainWindowSurfaceWGL::releaseTexImage(EGLint buffer) +{ + ASSERT(mTextureHandle != nullptr); + + if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mTextureHandle)) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to unlock D3D object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + + if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle)) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to unregister D3D object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + + 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::FramebufferState &data) +{ + return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, + mRenderer->getBlitter(), 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)) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to lock object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + } + else + { + if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, count, resources)) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to lock object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + } + + 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) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%X.", + HRESULT_CODE(GetLastError())); + } + + // 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) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%X.", + HRESULT_CODE(GetLastError())); + } + } + + 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 |