diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/wgl')
15 files changed, 2929 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.cpp new file mode 100644 index 000000000..f19e8fdf3 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.cpp @@ -0,0 +1,384 @@ +// +// 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. +// + +// D3DTextureSurfaceWGL.cpp: WGL implementation of egl::Surface for D3D texture interop. + +#include "libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.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" + +namespace rx +{ + +namespace +{ + +egl::Error GetD3DTextureInfo(EGLClientBuffer clientBuffer, + size_t *width, + size_t *height, + IUnknown **object, + IUnknown **device) +{ + IUnknown *buffer = static_cast<IUnknown *>(clientBuffer); + + IDirect3DTexture9 *texture9 = nullptr; + ID3D11Texture2D *texture11 = nullptr; + if (SUCCEEDED(buffer->QueryInterface<ID3D11Texture2D>(&texture11))) + { + D3D11_TEXTURE2D_DESC textureDesc; + texture11->GetDesc(&textureDesc); + + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (textureDesc.Format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + break; + + default: + SafeRelease(texture11); + return egl::Error(EGL_BAD_PARAMETER, "Unknown client buffer texture format: %u.", + textureDesc.Format); + } + + ID3D11Device *d3d11Device = nullptr; + texture11->GetDevice(&d3d11Device); + if (d3d11Device == nullptr) + { + SafeRelease(texture11); + return egl::Error(EGL_BAD_PARAMETER, + "Could not query the D3D11 device from the client buffer."); + } + + if (width) + { + *width = textureDesc.Width; + } + if (height) + { + *height = textureDesc.Height; + } + + if (device) + { + *device = d3d11Device; + } + else + { + SafeRelease(d3d11Device); + } + + if (object) + { + *object = texture11; + } + else + { + SafeRelease(texture11); + } + + return egl::Error(EGL_SUCCESS); + } + else if (SUCCEEDED(buffer->QueryInterface<IDirect3DTexture9>(&texture9))) + { + D3DSURFACE_DESC surfaceDesc; + if (FAILED(texture9->GetLevelDesc(0, &surfaceDesc))) + { + SafeRelease(texture9); + return egl::Error(EGL_BAD_PARAMETER, + "Could not query description of the D3D9 surface."); + } + + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (surfaceDesc.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + break; + + default: + SafeRelease(texture9); + return egl::Error(EGL_BAD_PARAMETER, "Unknown client buffer texture format: %u.", + surfaceDesc.Format); + } + + if (width) + { + *width = surfaceDesc.Width; + } + if (height) + { + *height = surfaceDesc.Height; + } + + IDirect3DDevice9 *d3d9Device = nullptr; + HRESULT result = texture9->GetDevice(&d3d9Device); + if (FAILED(result)) + { + SafeRelease(texture9); + return egl::Error(EGL_BAD_PARAMETER, + "Could not query the D3D9 device from the client buffer."); + } + + if (device) + { + *device = d3d9Device; + } + else + { + SafeRelease(d3d9Device); + } + + if (object) + { + *object = texture9; + } + else + { + SafeRelease(texture9); + } + + return egl::Error(EGL_SUCCESS); + } + else + { + return egl::Error(EGL_BAD_PARAMETER, + "Provided buffer is not a IDirect3DTexture9 or ID3D11Texture2D."); + } +} + +} // anonymous namespace + +D3DTextureSurfaceWGL::D3DTextureSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLClientBuffer clientBuffer, + DisplayWGL *display, + HGLRC wglContext, + HDC deviceContext, + const FunctionsGL *functionsGL, + const FunctionsWGL *functionsWGL) + : SurfaceGL(state, renderer), + mClientBuffer(clientBuffer), + mRenderer(renderer), + mDisplay(display), + mStateManager(renderer->getStateManager()), + mWorkarounds(renderer->getWorkarounds()), + mFunctionsGL(functionsGL), + mFunctionsWGL(functionsWGL), + mWGLContext(wglContext), + mDeviceContext(deviceContext), + mWidth(0), + mHeight(0), + mDeviceHandle(nullptr), + mObject(nullptr), + mBoundObjectTextureHandle(nullptr), + mBoundObjectRenderbufferHandle(nullptr), + mRenderbufferID(0), + mFramebufferID(0) +{ +} + +D3DTextureSurfaceWGL::~D3DTextureSurfaceWGL() +{ + ASSERT(mBoundObjectTextureHandle == nullptr); + + SafeRelease(mObject); + + if (mDeviceHandle) + { + if (mBoundObjectRenderbufferHandle) + { + mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectRenderbufferHandle); + mBoundObjectRenderbufferHandle = nullptr; + } + mStateManager->deleteRenderbuffer(mRenderbufferID); + + if (mBoundObjectTextureHandle) + { + mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle); + mBoundObjectTextureHandle = nullptr; + } + + // GL framebuffer is deleted by the default framebuffer object + mFramebufferID = 0; + + mDisplay->releaseD3DDevice(mDeviceHandle); + mDeviceHandle = nullptr; + } +} + +egl::Error D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(EGLClientBuffer clientBuffer) +{ + return GetD3DTextureInfo(clientBuffer, nullptr, nullptr, nullptr, nullptr); +} + +egl::Error D3DTextureSurfaceWGL::initialize() +{ + IUnknown *device = nullptr; + ANGLE_TRY(GetD3DTextureInfo(mClientBuffer, &mWidth, &mHeight, &mObject, &device)); + + ASSERT(device != nullptr); + egl::Error error = mDisplay->registerD3DDevice(device, &mDeviceHandle); + SafeRelease(device); + if (error.isError()) + { + return error; + } + + mFunctionsGL->genRenderbuffers(1, &mRenderbufferID); + mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID); + mBoundObjectRenderbufferHandle = mFunctionsWGL->dxRegisterObjectNV( + mDeviceHandle, mObject, mRenderbufferID, GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV); + if (mBoundObjectRenderbufferHandle == nullptr) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to register D3D object, error: 0x%08x.", + HRESULT_CODE(GetLastError())); + } + + mFunctionsGL->genFramebuffers(1, &mFramebufferID); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + mRenderbufferID); + + return egl::Error(EGL_SUCCESS); +} + +egl::Error D3DTextureSurfaceWGL::makeCurrent() +{ + if (!mFunctionsWGL->makeCurrent(mDeviceContext, mWGLContext)) + { + // TODO(geofflang): What error type here? + return egl::Error(EGL_CONTEXT_LOST, "Failed to make the WGL context current."); + } + + if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle)) + { + 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 D3DTextureSurfaceWGL::unMakeCurrent() +{ + if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle)) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to unlock object, error: 0x%08x.", + HRESULT_CODE(error)); + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error D3DTextureSurfaceWGL::swap() +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error D3DTextureSurfaceWGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error D3DTextureSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error D3DTextureSurfaceWGL::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + ASSERT(mBoundObjectTextureHandle == nullptr); + + const TextureGL *textureGL = GetImplAs<TextureGL>(texture); + GLuint textureID = textureGL->getTextureID(); + + mBoundObjectTextureHandle = mFunctionsWGL->dxRegisterObjectNV( + mDeviceHandle, mObject, textureID, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV); + if (mBoundObjectTextureHandle == 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, &mBoundObjectTextureHandle)) + { + 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 D3DTextureSurfaceWGL::releaseTexImage(EGLint buffer) +{ + ASSERT(mBoundObjectTextureHandle != nullptr); + if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle)) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to unlock object, error: 0x%08x.", + HRESULT_CODE(error)); + } + + if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle)) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to unregister D3D object, error: 0x%08x.", + HRESULT_CODE(error)); + } + mBoundObjectTextureHandle = nullptr; + + return egl::Error(EGL_SUCCESS); +} + +void D3DTextureSurfaceWGL::setSwapInterval(EGLint interval) +{ + UNIMPLEMENTED(); +} + +EGLint D3DTextureSurfaceWGL::getWidth() const +{ + return static_cast<EGLint>(mWidth); +} + +EGLint D3DTextureSurfaceWGL::getHeight() const +{ + return static_cast<EGLint>(mHeight); +} + +EGLint D3DTextureSurfaceWGL::isPostSubBufferSupported() const +{ + return EGL_FALSE; +} + +EGLint D3DTextureSurfaceWGL::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} + +FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::FramebufferState &data) +{ + return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, + mRenderer->getBlitter(), mStateManager); +} +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h new file mode 100644 index 000000000..8fb1d4003 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h @@ -0,0 +1,86 @@ + +// 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. +// + +// D3DTextureSurfaceWGL.h: WGL implementation of egl::Surface for D3D texture interop. + +#ifndef LIBANGLE_RENDERER_GL_WGL_D3DTEXTIRESURFACEWGL_H_ +#define LIBANGLE_RENDERER_GL_WGL_D3DTEXTIRESURFACEWGL_H_ + +#include "libANGLE/renderer/gl/SurfaceGL.h" + +#include <GL/wglext.h> + +namespace rx +{ + +class FunctionsGL; +class FunctionsWGL; +class DisplayWGL; +class StateManagerGL; +struct WorkaroundsGL; + +class D3DTextureSurfaceWGL : public SurfaceGL +{ + public: + D3DTextureSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLClientBuffer clientBuffer, + DisplayWGL *display, + HGLRC wglContext, + HDC deviceContext, + const FunctionsGL *functionsGL, + const FunctionsWGL *functionsWGL); + ~D3DTextureSurfaceWGL() override; + + static egl::Error ValidateD3DTextureClientBuffer(EGLClientBuffer clientBuffer); + + egl::Error initialize() override; + egl::Error makeCurrent() override; + egl::Error unMakeCurrent() 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::FramebufferState &data) override; + + private: + EGLClientBuffer mClientBuffer; + + RendererGL *mRenderer; + + DisplayWGL *mDisplay; + StateManagerGL *mStateManager; + const WorkaroundsGL &mWorkarounds; + const FunctionsGL *mFunctionsGL; + const FunctionsWGL *mFunctionsWGL; + + HGLRC mWGLContext; + HDC mDeviceContext; + + size_t mWidth; + size_t mHeight; + + HANDLE mDeviceHandle; + IUnknown *mObject; + HANDLE mBoundObjectTextureHandle; + HANDLE mBoundObjectRenderbufferHandle; + + GLuint mRenderbufferID; + GLuint mFramebufferID; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_WGL_D3DTEXTIRESURFACEWGL_H_ 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 diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h new file mode 100755 index 000000000..f516239c9 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h @@ -0,0 +1,106 @@ +// +// 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(const egl::SurfaceState &state, + 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::FramebufferState &data) override; + + private: + egl::Error setObjectsLocked(bool locked); + egl::Error checkForResize(); + + egl::Error createSwapChain(); + + EGLNativeWindowType mWindow; + + StateManagerGL *mStateManager; + const WorkaroundsGL &mWorkarounds; + RendererGL *mRenderer; + 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_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp new file mode 100755 index 000000000..188321115 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp @@ -0,0 +1,741 @@ +// +// 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. +// + +// DisplayWGL.h: WGL implementation of egl::Display + +#include "libANGLE/renderer/gl/wgl/DisplayWGL.h" + +#include "common/debug.h" +#include "libANGLE/Config.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/gl/RendererGL.h" +#include "libANGLE/renderer/gl/renderergl_utils.h" +#include "libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h" +#include "libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h" +#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" +#include "libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h" +#include "libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h" +#include "libANGLE/renderer/gl/wgl/wgl_utils.h" + +#include "platform/Platform.h" + +#include <EGL/eglext.h> +#include <string> +#include <sstream> + +namespace rx +{ + +class FunctionsGLWindows : public FunctionsGL +{ + public: + FunctionsGLWindows(HMODULE openGLModule, PFNWGLGETPROCADDRESSPROC getProcAddressWGL) + : mOpenGLModule(openGLModule), + mGetProcAddressWGL(getProcAddressWGL) + { + ASSERT(mOpenGLModule); + ASSERT(mGetProcAddressWGL); + } + + ~FunctionsGLWindows() override {} + + private: + void *loadProcAddress(const std::string &function) override + { + void *proc = reinterpret_cast<void*>(mGetProcAddressWGL(function.c_str())); + if (!proc) + { + proc = reinterpret_cast<void*>(GetProcAddress(mOpenGLModule, function.c_str())); + } + return proc; + } + + HMODULE mOpenGLModule; + PFNWGLGETPROCADDRESSPROC mGetProcAddressWGL; +}; + +DisplayWGL::DisplayWGL() + : DisplayGL(), + mOpenGLModule(nullptr), + mFunctionsWGL(nullptr), + mFunctionsGL(nullptr), + mHasRobustness(false), + mWindowClass(0), + mWindow(nullptr), + mDeviceContext(nullptr), + mPixelFormat(0), + mWGLContext(nullptr), + mUseDXGISwapChains(false), + mDxgiModule(nullptr), + mD3d11Module(nullptr), + mD3D11DeviceHandle(nullptr), + mD3D11Device(nullptr), + mDisplay(nullptr) +{ +} + +DisplayWGL::~DisplayWGL() +{ +} + +egl::Error DisplayWGL::initialize(egl::Display *display) +{ + mDisplay = display; + + mOpenGLModule = LoadLibraryA("opengl32.dll"); + if (!mOpenGLModule) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to load OpenGL library."); + } + + mFunctionsWGL = new FunctionsWGL(); + mFunctionsWGL->initialize(mOpenGLModule, nullptr); + + // WGL can't grab extensions until it creates a context because it needs to load the driver's DLLs first. + // Create a dummy context to load the driver and determine which GL versions are available. + + // Work around compile error from not defining "UNICODE" while Chromium does + const LPSTR idcArrow = MAKEINTRESOURCEA(32512); + + std::string className = FormatString("ANGLE DisplayWGL 0x%0.8p Intermediate Window Class", mDisplay); + + WNDCLASSA intermediateClassDesc = { 0 }; + intermediateClassDesc.style = CS_OWNDC; + intermediateClassDesc.lpfnWndProc = DefWindowProc; + intermediateClassDesc.cbClsExtra = 0; + intermediateClassDesc.cbWndExtra = 0; + intermediateClassDesc.hInstance = GetModuleHandle(nullptr); + intermediateClassDesc.hIcon = nullptr; + intermediateClassDesc.hCursor = LoadCursorA(nullptr, idcArrow); + intermediateClassDesc.hbrBackground = 0; + intermediateClassDesc.lpszMenuName = nullptr; + intermediateClassDesc.lpszClassName = className.c_str(); + mWindowClass = RegisterClassA(&intermediateClassDesc); + if (!mWindowClass) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to register intermediate OpenGL window class."); + } + + HWND dummyWindow = CreateWindowExA(0, + reinterpret_cast<const char *>(mWindowClass), + "ANGLE Dummy Window", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + nullptr, + nullptr, + nullptr, + nullptr); + if (!dummyWindow) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to create dummy OpenGL window."); + } + + HDC dummyDeviceContext = GetDC(dummyWindow); + if (!dummyDeviceContext) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to get the device context of the dummy OpenGL window."); + } + + const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = wgl::GetDefaultPixelFormatDescriptor(); + + int dummyPixelFormat = ChoosePixelFormat(dummyDeviceContext, &pixelFormatDescriptor); + if (dummyPixelFormat == 0) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not find a compatible pixel format for the dummy OpenGL window."); + } + + if (!SetPixelFormat(dummyDeviceContext, dummyPixelFormat, &pixelFormatDescriptor)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to set the pixel format on the intermediate OpenGL window."); + } + + HGLRC dummyWGLContext = mFunctionsWGL->createContext(dummyDeviceContext); + if (!dummyDeviceContext) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to create a WGL context for the dummy OpenGL window."); + } + + if (!mFunctionsWGL->makeCurrent(dummyDeviceContext, dummyWGLContext)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to make the dummy WGL context current."); + } + + // Grab the GL version from this context and use it as the maximum version available. + typedef const GLubyte* (GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); + PFNGLGETSTRINGPROC getString = reinterpret_cast<PFNGLGETSTRINGPROC>(GetProcAddress(mOpenGLModule, "glGetString")); + if (!getString) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to get glGetString pointer."); + } + + // Reinitialize the wgl functions to grab the extensions + mFunctionsWGL->initialize(mOpenGLModule, dummyDeviceContext); + + bool hasWGLCreateContextRobustness = + mFunctionsWGL->hasExtension("WGL_ARB_create_context_robustness"); + + // Destroy the dummy window and context + mFunctionsWGL->makeCurrent(dummyDeviceContext, nullptr); + mFunctionsWGL->deleteContext(dummyWGLContext); + ReleaseDC(dummyWindow, dummyDeviceContext); + DestroyWindow(dummyWindow); + + const egl::AttributeMap &displayAttributes = display->getAttributeMap(); + EGLint requestedDisplayType = static_cast<EGLint>(displayAttributes.get( + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)); + if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE && + !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es2_profile") && + !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es_profile")) + { + return egl::Error(EGL_NOT_INITIALIZED, + "Cannot create an OpenGL ES platform on Windows without " + "the WGL_EXT_create_context_es(2)_profile extension."); + } + + // Create the real intermediate context and windows + mWindow = CreateWindowExA(0, + reinterpret_cast<const char *>(mWindowClass), + "ANGLE Intermediate Window", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + nullptr, + nullptr, + nullptr, + nullptr); + if (!mWindow) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to create intermediate OpenGL window."); + } + + mDeviceContext = GetDC(mWindow); + if (!mDeviceContext) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to get the device context of the intermediate OpenGL window."); + } + + if (mFunctionsWGL->choosePixelFormatARB) + { + std::vector<int> attribs = wgl::GetDefaultPixelFormatAttributes(false); + + UINT matchingFormats = 0; + mFunctionsWGL->choosePixelFormatARB(mDeviceContext, &attribs[0], nullptr, 1u, &mPixelFormat, + &matchingFormats); + } + + if (mPixelFormat == 0) + { + mPixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor); + } + + if (mPixelFormat == 0) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not find a compatible pixel format for the intermediate OpenGL window."); + } + + if (!SetPixelFormat(mDeviceContext, mPixelFormat, &pixelFormatDescriptor)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to set the pixel format on the intermediate OpenGL window."); + } + + if (mFunctionsWGL->createContextAttribsARB) + { + int flags = 0; + // TODO: allow debug contexts + // TODO: handle robustness + + int mask = 0; + + if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) + { + mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; + } + else + { + // Request core profile + mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + } + + std::vector<int> contextCreationAttributes; + + if (hasWGLCreateContextRobustness) + { + contextCreationAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + contextCreationAttributes.push_back(WGL_LOSE_CONTEXT_ON_RESET_ARB); + } + + // Don't request a specific version unless the user wants one. WGL will return the highest version + // that the driver supports if no version is requested. + EGLint requestedMajorVersion = static_cast<EGLint>( + displayAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)); + EGLint requestedMinorVersion = static_cast<EGLint>( + displayAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)); + if (requestedMajorVersion != EGL_DONT_CARE && requestedMinorVersion != EGL_DONT_CARE) + { + contextCreationAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); + contextCreationAttributes.push_back(requestedMajorVersion); + + contextCreationAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); + contextCreationAttributes.push_back(requestedMinorVersion); + } + else + { + // the ES profile will give us ES version 1.1 unless a higher version is requested. + // Requesting version 2.0 will give us the highest compatible version available (2.0, + // 3.0, 3.1, etc). + if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) + { + contextCreationAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); + contextCreationAttributes.push_back(2); + + contextCreationAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); + contextCreationAttributes.push_back(0); + } + } + + // Set the flag attributes + if (flags != 0) + { + contextCreationAttributes.push_back(WGL_CONTEXT_FLAGS_ARB); + contextCreationAttributes.push_back(flags); + } + + // Set the mask attribute + if (mask != 0) + { + contextCreationAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB); + contextCreationAttributes.push_back(mask); + } + + // Signal the end of the attributes + contextCreationAttributes.push_back(0); + contextCreationAttributes.push_back(0); + + mWGLContext = mFunctionsWGL->createContextAttribsARB(mDeviceContext, NULL, &contextCreationAttributes[0]); + } + + // If wglCreateContextAttribsARB is unavailable or failed, try the standard wglCreateContext + if (!mWGLContext) + { + // Don't have control over GL versions + mWGLContext = mFunctionsWGL->createContext(mDeviceContext); + } + + if (!mWGLContext) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to create a WGL context for the intermediate OpenGL window."); + } + + if (!mFunctionsWGL->makeCurrent(mDeviceContext, mWGLContext)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to make the intermediate WGL context current."); + } + + mFunctionsGL = new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress); + mFunctionsGL->initialize(); + + mHasRobustness = mFunctionsGL->getGraphicsResetStatus != nullptr; + if (hasWGLCreateContextRobustness != mHasRobustness) + { + ANGLEPlatformCurrent()->logWarning( + "WGL_ARB_create_context_robustness exists but unable to OpenGL context with " + "robustness."); + } + + // Intel OpenGL ES drivers are not currently supported due to bugs in the driver and ANGLE + VendorID vendor = GetVendorID(mFunctionsGL); + if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE && IsIntel(vendor)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Intel OpenGL ES drivers are not supported."); + } + + // 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); + + // AMD drivers advertise the WGL_NV_DX_interop and WGL_NV_DX_interop2 extensions but fail + mUseDXGISwapChains = !IsAMD(vendor) && (currentProcessId != windowProcessId); + } + else + { + mUseDXGISwapChains = false; + } + + if (mUseDXGISwapChains) + { + egl::Error error = initializeD3DDevice(); + if (error.isError()) + { + return error; + } + } + + return DisplayGL::initialize(display); +} + +void DisplayWGL::terminate() +{ + DisplayGL::terminate(); + + releaseD3DDevice(mD3D11DeviceHandle); + + mFunctionsWGL->makeCurrent(mDeviceContext, NULL); + mFunctionsWGL->deleteContext(mWGLContext); + mWGLContext = NULL; + + ReleaseDC(mWindow, mDeviceContext); + mDeviceContext = NULL; + + DestroyWindow(mWindow); + mWindow = NULL; + + UnregisterClassA(reinterpret_cast<const char*>(mWindowClass), NULL); + mWindowClass = NULL; + + SafeDelete(mFunctionsWGL); + SafeDelete(mFunctionsGL); + + FreeLibrary(mOpenGLModule); + mOpenGLModule = nullptr; + + SafeRelease(mD3D11Device); + + if (mDxgiModule) + { + FreeLibrary(mDxgiModule); + mDxgiModule = nullptr; + } + + if (mD3d11Module) + { + FreeLibrary(mD3d11Module); + mD3d11Module = nullptr; + } + + ASSERT(mRegisteredD3DDevices.empty()); +} + +SurfaceImpl *DisplayWGL::createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) +{ + EGLint orientation = static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); + if (mUseDXGISwapChains) + { + return new DXGISwapChainWindowSurfaceWGL(state, getRenderer(), window, mD3D11Device, + mD3D11DeviceHandle, mWGLContext, mDeviceContext, + mFunctionsGL, mFunctionsWGL, orientation); + } + else + { + return new WindowSurfaceWGL(state, getRenderer(), window, mPixelFormat, mWGLContext, + mFunctionsWGL, orientation); + } +} + +SurfaceImpl *DisplayWGL::createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) +{ + EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0)); + EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0)); + bool largest = (attribs.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); + EGLenum textureFormat = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE)); + EGLenum textureTarget = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); + + return new PbufferSurfaceWGL(state, getRenderer(), width, height, textureFormat, textureTarget, + largest, mPixelFormat, mDeviceContext, mWGLContext, mFunctionsWGL); +} + +SurfaceImpl *DisplayWGL::createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) +{ + ASSERT(buftype == EGL_D3D_TEXTURE_ANGLE); + return new D3DTextureSurfaceWGL(state, getRenderer(), clientBuffer, this, mWGLContext, + mDeviceContext, mFunctionsGL, mFunctionsWGL); +} + +SurfaceImpl *DisplayWGL::createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +egl::Error DisplayWGL::getDevice(DeviceImpl **device) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_DISPLAY); +} + +egl::ConfigSet DisplayWGL::generateConfigs() +{ + egl::ConfigSet configs; + + int minSwapInterval = 1; + int maxSwapInterval = 1; + if (mFunctionsWGL->swapIntervalEXT) + { + // No defined maximum swap interval in WGL_EXT_swap_control, use a reasonable number + minSwapInterval = 0; + maxSwapInterval = 8; + } + + const gl::Version &maxVersion = getMaxSupportedESVersion(); + ASSERT(maxVersion >= gl::Version(2, 0)); + bool supportsES3 = maxVersion >= gl::Version(3, 0); + + PIXELFORMATDESCRIPTOR pixelFormatDescriptor; + DescribePixelFormat(mDeviceContext, mPixelFormat, sizeof(pixelFormatDescriptor), &pixelFormatDescriptor); + + auto getAttrib = [this](int attrib) + { + return wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, attrib, mFunctionsWGL); + }; + + const EGLint optimalSurfaceOrientation = + mUseDXGISwapChains ? EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE : 0; + + egl::Config config; + 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.bufferSize = pixelFormatDescriptor.cColorBits; + config.redSize = pixelFormatDescriptor.cRedBits; + config.greenSize = pixelFormatDescriptor.cGreenBits; + config.blueSize = pixelFormatDescriptor.cBlueBits; + config.luminanceSize = 0; + config.alphaSize = pixelFormatDescriptor.cAlphaBits; + config.alphaMaskSize = 0; + config.bindToTextureRGB = (getAttrib(WGL_BIND_TO_TEXTURE_RGB_ARB) == TRUE); + config.bindToTextureRGBA = (getAttrib(WGL_BIND_TO_TEXTURE_RGBA_ARB) == TRUE); + config.colorBufferType = EGL_RGB_BUFFER; + config.configCaveat = EGL_NONE; + config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); + config.depthSize = pixelFormatDescriptor.cDepthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; + config.maxPBufferWidth = getAttrib(WGL_MAX_PBUFFER_WIDTH_ARB); + config.maxPBufferHeight = getAttrib(WGL_MAX_PBUFFER_HEIGHT_ARB); + config.maxPBufferPixels = getAttrib(WGL_MAX_PBUFFER_PIXELS_ARB); + config.maxSwapInterval = maxSwapInterval; + config.minSwapInterval = minSwapInterval; + config.nativeRenderable = EGL_TRUE; // Direct rendering + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + config.renderableType = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); + config.sampleBuffers = 0; // FIXME: enumerate multi-sampling + config.samples = 0; + config.stencilSize = pixelFormatDescriptor.cStencilBits; + config.surfaceType = + ((pixelFormatDescriptor.dwFlags & PFD_DRAW_TO_WINDOW) ? EGL_WINDOW_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 + : 0); + config.optimalOrientation = optimalSurfaceOrientation; + + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + + configs.add(config); + + return configs; +} + +bool DisplayWGL::testDeviceLost() +{ + if (mHasRobustness) + { + return getRenderer()->getResetStatus() != GL_NO_ERROR; + } + + return false; +} + +egl::Error DisplayWGL::restoreLostDevice() +{ + return egl::Error(EGL_BAD_DISPLAY); +} + +bool DisplayWGL::isValidNativeWindow(EGLNativeWindowType window) const +{ + return (IsWindow(window) == TRUE); +} + +egl::Error DisplayWGL::validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + switch (buftype) + { + case EGL_D3D_TEXTURE_ANGLE: + return D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(clientBuffer); + + default: + return DisplayGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs); + } +} + +std::string DisplayWGL::getVendorString() const +{ + //UNIMPLEMENTED(); + return ""; +} + +const FunctionsGL *DisplayWGL::getFunctionsGL() const +{ + 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 +{ + // 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; + + outExtensions->createContextRobustness = mHasRobustness; + + outExtensions->d3dTextureClientBuffer = mFunctionsWGL->hasExtension("WGL_NV_DX_interop2"); +} + +void DisplayWGL::generateCaps(egl::Caps *outCaps) const +{ + outCaps->textureNPOT = true; +} + +egl::Error DisplayWGL::waitClient() const +{ + // Unimplemented as this is not needed for WGL + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayWGL::waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const +{ + // Unimplemented as this is not needed for WGL + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayWGL::getDriverVersion(std::string *version) const +{ + *version = ""; + 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; + } + } + } +} +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.h new file mode 100755 index 000000000..509ea9b39 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.h @@ -0,0 +1,112 @@ +// +// 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. +// + +// DisplayWGL.h: WGL implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_ +#define LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_ + +#include "libANGLE/renderer/gl/DisplayGL.h" + +#include <GL/wglext.h> + +namespace rx +{ + +class FunctionsWGL; + +class DisplayWGL : public DisplayGL +{ + public: + DisplayWGL(); + ~DisplayWGL() override; + + egl::Error initialize(egl::Display *display) override; + void terminate() override; + + // Surface creation + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) override; + + egl::ConfigSet generateConfigs() override; + + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + egl::Error validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const override; + + egl::Error getDevice(DeviceImpl **device) override; + + std::string getVendorString() const override; + + egl::Error waitClient() const override; + egl::Error waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const override; + + egl::Error getDriverVersion(std::string *version) const override; + + egl::Error registerD3DDevice(IUnknown *device, HANDLE *outHandle); + void releaseD3DDevice(HANDLE handle); + + private: + const FunctionsGL *getFunctionsGL() const override; + + egl::Error initializeD3DDevice(); + + void generateExtensions(egl::DisplayExtensions *outExtensions) const override; + void generateCaps(egl::Caps *outCaps) const override; + + HMODULE mOpenGLModule; + + FunctionsWGL *mFunctionsWGL; + FunctionsGL *mFunctionsGL; + + bool mHasRobustness; + + ATOM mWindowClass; + HWND mWindow; + HDC mDeviceContext; + int mPixelFormat; + 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; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.cpp new file mode 100755 index 000000000..2cfe6e9eb --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.cpp @@ -0,0 +1,181 @@ +// +// 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. +// + +// FunctionsWGL.h: Implements the FuntionsWGL class. + +#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" + +#include <algorithm> + +#include "common/string_utils.h" + +namespace rx +{ + +template <typename T> +static void GetWGLProcAddress(HMODULE glModule, PFNWGLGETPROCADDRESSPROC getProcAddressWGL, + const std::string &procName, T *outProcAddress) +{ + T proc = nullptr; + if (getProcAddressWGL) + { + proc = reinterpret_cast<T>(getProcAddressWGL(procName.c_str())); + } + + if (!proc) + { + proc = reinterpret_cast<T>(GetProcAddress(glModule, procName.c_str())); + } + + *outProcAddress = proc; +} + +template <typename T> +static void GetWGLExtensionProcAddress(HMODULE glModule, + PFNWGLGETPROCADDRESSPROC getProcAddressWGL, + const std::vector<std::string> &extensions, + const std::string &extensionName, + const std::string &procName, + T *outProcAddress) +{ + T proc = nullptr; + if (std::find(extensions.begin(), extensions.end(), extensionName) != extensions.end()) + { + GetWGLProcAddress(glModule, getProcAddressWGL, procName, &proc); + } + + *outProcAddress = proc; +} + +FunctionsWGL::FunctionsWGL() + : copyContext(nullptr), + createContext(nullptr), + createLayerContext(nullptr), + deleteContext(nullptr), + getCurrentContext(nullptr), + getCurrentDC(nullptr), + getProcAddress(nullptr), + makeCurrent(nullptr), + shareLists(nullptr), + useFontBitmapsA(nullptr), + useFontBitmapsW(nullptr), + swapBuffers(nullptr), + useFontOutlinesA(nullptr), + useFontOutlinesW(nullptr), + describeLayerPlane(nullptr), + setLayerPaletteEntries(nullptr), + getLayerPaletteEntries(nullptr), + realizeLayerPalette(nullptr), + swapLayerBuffers(nullptr), + swapMultipleBuffers(nullptr), + getExtensionStringEXT(nullptr), + getExtensionStringARB(nullptr), + createContextAttribsARB(nullptr), + getPixelFormatAttribivARB(nullptr), + getPixelFormatAttribfvARB(nullptr), + choosePixelFormatARB(nullptr), + swapIntervalEXT(nullptr), + createPbufferARB(nullptr), + getPbufferDCARB(nullptr), + releasePbufferDCARB(nullptr), + destroyPbufferARB(nullptr), + queryPbufferARB(nullptr), + bindTexImageARB(nullptr), + releaseTexImageARB(nullptr), + setPbufferAttribARB(nullptr), + dxSetResourceShareHandleNV(nullptr), + dxOpenDeviceNV(nullptr), + dxCloseDeviceNV(nullptr), + dxRegisterObjectNV(nullptr), + dxUnregisterObjectNV(nullptr), + dxObjectAccessNV(nullptr), + dxLockObjectsNV(nullptr), + dxUnlockObjectsNV(nullptr) +{ +} + +void FunctionsWGL::initialize(HMODULE glModule, HDC context) +{ + // First grab the wglGetProcAddress function from the gl module + GetWGLProcAddress(glModule, nullptr, "wglGetProcAddress", &getProcAddress); + + // Load the core wgl functions + GetWGLProcAddress(glModule, getProcAddress, "wglCopyContext", ©Context); + GetWGLProcAddress(glModule, getProcAddress, "wglCreateContext", &createContext); + GetWGLProcAddress(glModule, getProcAddress, "wglCreateLayerContext", &createLayerContext); + GetWGLProcAddress(glModule, getProcAddress, "wglDeleteContext", &deleteContext); + GetWGLProcAddress(glModule, getProcAddress, "wglGetCurrentContext", &getCurrentContext); + GetWGLProcAddress(glModule, getProcAddress, "wglGetCurrentDC", &getCurrentDC); + GetWGLProcAddress(glModule, getProcAddress, "wglMakeCurrent", &makeCurrent); + GetWGLProcAddress(glModule, getProcAddress, "wglShareLists", &shareLists); + GetWGLProcAddress(glModule, getProcAddress, "wglUseFontBitmapsA", &useFontBitmapsA); + GetWGLProcAddress(glModule, getProcAddress, "wglUseFontBitmapsW", &useFontBitmapsW); + swapBuffers = SwapBuffers; // SwapBuffers is statically linked from GDI + GetWGLProcAddress(glModule, getProcAddress, "wglUseFontOutlinesA", &useFontOutlinesA); + GetWGLProcAddress(glModule, getProcAddress, "wglUseFontOutlinesW", &useFontOutlinesW); + GetWGLProcAddress(glModule, getProcAddress, "wglDescribeLayerPlane", &describeLayerPlane); + GetWGLProcAddress(glModule, getProcAddress, "wglSetLayerPaletteEntries", &setLayerPaletteEntries); + GetWGLProcAddress(glModule, getProcAddress, "wglGetLayerPaletteEntries", &getLayerPaletteEntries); + GetWGLProcAddress(glModule, getProcAddress, "wglRealizeLayerPalette", &realizeLayerPalette); + GetWGLProcAddress(glModule, getProcAddress, "wglSwapLayerBuffers", &swapLayerBuffers); + GetWGLProcAddress(glModule, getProcAddress, "wglSwapMultipleBuffers", &swapMultipleBuffers); + + // Load extension string getter functions + GetWGLProcAddress(glModule, getProcAddress, "wglGetExtensionsStringEXT", &getExtensionStringEXT); + GetWGLProcAddress(glModule, getProcAddress, "wglGetExtensionsStringARB", &getExtensionStringARB); + + std::string extensionString = ""; + if (getExtensionStringEXT) + { + extensionString = getExtensionStringEXT(); + } + else if (getExtensionStringARB && context) + { + extensionString = getExtensionStringARB(context); + } + angle::SplitStringAlongWhitespace(extensionString, &extensions); + + // Load the wgl extension functions by checking if the context supports the extension first + + // WGL_ARB_create_context + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_create_context", "wglCreateContextAttribsARB", &createContextAttribsARB); + + // WGL_ARB_pixel_format + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pixel_format", "wglGetPixelFormatAttribivARB", &getPixelFormatAttribivARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pixel_format", "wglGetPixelFormatAttribfvARB", &getPixelFormatAttribfvARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pixel_format", "wglChoosePixelFormatARB", &choosePixelFormatARB); + + // WGL_EXT_swap_control + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_EXT_swap_control", "wglSwapIntervalEXT", &swapIntervalEXT); + + // WGL_ARB_pbuffer + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pbuffer", "wglCreatePbufferARB", &createPbufferARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pbuffer", "wglGetPbufferDCARB", &getPbufferDCARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pbuffer", "wglReleasePbufferDCARB", &releasePbufferDCARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pbuffer", "wglDestroyPbufferARB", &destroyPbufferARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_pbuffer", "wglQueryPbufferARB", &queryPbufferARB); + + // WGL_ARB_render_texture + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_render_texture", "wglBindTexImageARB", &bindTexImageARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_render_texture", "wglReleaseTexImageARB", &releaseTexImageARB); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_ARB_render_texture", "wglSetPbufferAttribARB", &setPbufferAttribARB); + + // WGL_NV_DX_interop + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXSetResourceShareHandleNV", &dxSetResourceShareHandleNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXOpenDeviceNV", &dxOpenDeviceNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXCloseDeviceNV", &dxCloseDeviceNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXRegisterObjectNV", &dxRegisterObjectNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXUnregisterObjectNV", &dxUnregisterObjectNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXObjectAccessNV", &dxObjectAccessNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXLockObjectsNV", &dxLockObjectsNV); + GetWGLExtensionProcAddress(glModule, getProcAddress, extensions, "WGL_NV_DX_interop", "wglDXUnlockObjectsNV", &dxUnlockObjectsNV); +} + +bool FunctionsWGL::hasExtension(const std::string &ext) const +{ + return std::find(extensions.begin(), extensions.end(), ext) != extensions.end(); +} +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.h new file mode 100755 index 000000000..30cf9ebc0 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.h @@ -0,0 +1,94 @@ +// +// 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. +// + +// FunctionsWGL.h: Defines the FuntionsWGL class to contain loaded WGL functions + +#ifndef LIBANGLE_RENDERER_GL_WGL_FUNCTIONS_WGL +#define LIBANGLE_RENDERER_GL_WGL_FUNCTIONS_WGL + +#include "common/angleutils.h" +#include "libANGLE/renderer/gl/wgl/functionswgl_typedefs.h" + +namespace rx +{ + +class FunctionsWGL : angle::NonCopyable +{ + public: + FunctionsWGL(); + + // Loads all available wgl functions, may be called multiple times + void initialize(HMODULE glModule, HDC context); + + // Extension information + std::vector<std::string> extensions; + bool hasExtension(const std::string &ext) const; + + // Base WGL functions + PFNWGLCOPYCONTEXTPROC copyContext; + PFNWGLCREATECONTEXTPROC createContext; + PFNWGLCREATELAYERCONTEXTPROC createLayerContext; + PFNWGLDELETECONTEXTPROC deleteContext; + PFNWGLGETCURRENTCONTEXTPROC getCurrentContext; + PFNWGLGETCURRENTDCPROC getCurrentDC; + PFNWGLGETPROCADDRESSPROC getProcAddress; + PFNWGLMAKECURRENTPROC makeCurrent; + PFNWGLSHARELISTSPROC shareLists; + PFNWGLUSEFONTBITMAPSAPROC useFontBitmapsA; + PFNWGLUSEFONTBITMAPSWPROC useFontBitmapsW; + PFNSWAPBUFFERSPROC swapBuffers; + PFNWGLUSEFONTOUTLINESAPROC useFontOutlinesA; + PFNWGLUSEFONTOUTLINESWPROC useFontOutlinesW; + PFNWGLDESCRIBELAYERPLANEPROC describeLayerPlane; + PFNWGLSETLAYERPALETTEENTRIESPROC setLayerPaletteEntries; + PFNWGLGETLAYERPALETTEENTRIESPROC getLayerPaletteEntries; + PFNWGLREALIZELAYERPALETTEPROC realizeLayerPalette; + PFNWGLSWAPLAYERBUFFERSPROC swapLayerBuffers; + PFNWGLSWAPMULTIPLEBUFFERSPROC swapMultipleBuffers; + + // WGL_EXT_extensions_string + PFNWGLGETEXTENSIONSSTRINGEXTPROC getExtensionStringEXT; + + // WGL_ARB_extensions_string + PFNWGLGETEXTENSIONSSTRINGARBPROC getExtensionStringARB; + + // WGL_ARB_create_context + PFNWGLCREATECONTEXTATTRIBSARBPROC createContextAttribsARB; + + // WGL_ARB_pixel_format + PFNWGLGETPIXELFORMATATTRIBIVARBPROC getPixelFormatAttribivARB; + PFNWGLGETPIXELFORMATATTRIBFVARBPROC getPixelFormatAttribfvARB; + PFNWGLCHOOSEPIXELFORMATARBPROC choosePixelFormatARB; + + // WGL_EXT_swap_control + PFNWGLSWAPINTERVALEXTPROC swapIntervalEXT; + + // WGL_ARB_pbuffer + PFNWGLCREATEPBUFFERARBPROC createPbufferARB; + PFNWGLGETPBUFFERDCARBPROC getPbufferDCARB; + PFNWGLRELEASEPBUFFERDCARBPROC releasePbufferDCARB; + PFNWGLDESTROYPBUFFERARBPROC destroyPbufferARB; + PFNWGLQUERYPBUFFERARBPROC queryPbufferARB; + + // WGL_ARB_render_texture + PFNWGLBINDTEXIMAGEARBPROC bindTexImageARB; + PFNWGLRELEASETEXIMAGEARBPROC releaseTexImageARB; + PFNWGLSETPBUFFERATTRIBARBPROC setPbufferAttribARB; + + // WGL_NV_DX_interop + PFNWGLDXSETRESOURCESHAREHANDLENVPROC dxSetResourceShareHandleNV; + PFNWGLDXOPENDEVICENVPROC dxOpenDeviceNV; + PFNWGLDXCLOSEDEVICENVPROC dxCloseDeviceNV; + PFNWGLDXREGISTEROBJECTNVPROC dxRegisterObjectNV; + PFNWGLDXUNREGISTEROBJECTNVPROC dxUnregisterObjectNV; + PFNWGLDXOBJECTACCESSNVPROC dxObjectAccessNV; + PFNWGLDXLOCKOBJECTSNVPROC dxLockObjectsNV; + PFNWGLDXUNLOCKOBJECTSNVPROC dxUnlockObjectsNV; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_FUNCTIONS_WGL diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.cpp new file mode 100755 index 000000000..f2c503616 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.cpp @@ -0,0 +1,196 @@ +// +// 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. +// + +// SurfaceWGL.cpp: WGL implementation of egl::Surface + +#include "libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h" + +#include "common/debug.h" +#include "libANGLE/renderer/gl/RendererGL.h" +#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" +#include "libANGLE/renderer/gl/wgl/wgl_utils.h" + +namespace rx +{ + +PbufferSurfaceWGL::PbufferSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLint width, + EGLint height, + EGLenum textureFormat, + EGLenum textureTarget, + bool largest, + int pixelFormat, + HDC deviceContext, + HGLRC wglContext, + const FunctionsWGL *functions) + : SurfaceGL(state, renderer), + mWidth(width), + mHeight(height), + mLargest(largest), + mTextureFormat(textureFormat), + mTextureTarget(textureTarget), + mPixelFormat(pixelFormat), + mShareWGLContext(wglContext), + mParentDeviceContext(deviceContext), + mPbuffer(nullptr), + mPbufferDeviceContext(nullptr), + mFunctionsWGL(functions) +{ +} + +PbufferSurfaceWGL::~PbufferSurfaceWGL() +{ + mFunctionsWGL->releasePbufferDCARB(mPbuffer, mPbufferDeviceContext); + mPbufferDeviceContext = nullptr; + + mFunctionsWGL->destroyPbufferARB(mPbuffer); + mPbuffer = nullptr; +} + +static int GetWGLTextureType(EGLenum eglTextureType) +{ + switch (eglTextureType) + { + case EGL_NO_TEXTURE: return WGL_NO_TEXTURE_ARB; + case EGL_TEXTURE_RGB: return WGL_TEXTURE_RGB_ARB; + case EGL_TEXTURE_RGBA: return WGL_TEXTURE_RGBA_ARB; + default: UNREACHABLE(); return 0; + } +} + +static int GetWGLTextureTarget(EGLenum eglTextureTarget) +{ + switch (eglTextureTarget) + { + case EGL_NO_TEXTURE: return WGL_NO_TEXTURE_ARB; + case EGL_TEXTURE_2D: return WGL_TEXTURE_2D_ARB; + default: UNREACHABLE(); return 0; + } +} + +egl::Error PbufferSurfaceWGL::initialize() +{ + const int pbufferCreationAttributes[] = + { + WGL_PBUFFER_LARGEST_ARB, mLargest ? 1 : 0, + WGL_TEXTURE_FORMAT_ARB, GetWGLTextureType(mTextureFormat), + WGL_TEXTURE_TARGET_ARB, GetWGLTextureTarget(mTextureTarget), + 0, 0, + }; + + mPbuffer = mFunctionsWGL->createPbufferARB(mParentDeviceContext, mPixelFormat, mWidth, mHeight, + pbufferCreationAttributes); + if (mPbuffer == nullptr) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to create a native WGL pbuffer, error: 0x%08x.", HRESULT_CODE(error)); + } + + // The returned pbuffer may not be as large as requested, update the size members. + if (mFunctionsWGL->queryPbufferARB(mPbuffer, WGL_PBUFFER_WIDTH_ARB, &mWidth) != TRUE || + mFunctionsWGL->queryPbufferARB(mPbuffer, WGL_PBUFFER_HEIGHT_ARB, &mHeight) != TRUE) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to query the WGL pbuffer's dimensions, error: 0x%08x.", HRESULT_CODE(error)); + } + + mPbufferDeviceContext = mFunctionsWGL->getPbufferDCARB(mPbuffer); + if (mPbufferDeviceContext == nullptr) + { + mFunctionsWGL->destroyPbufferARB(mPbuffer); + mPbuffer = nullptr; + + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_ALLOC, "Failed to get the WGL pbuffer handle, error: 0x%08x.", HRESULT_CODE(error)); + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceWGL::makeCurrent() +{ + if (!mFunctionsWGL->makeCurrent(mPbufferDeviceContext, mShareWGLContext)) + { + // 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 PbufferSurfaceWGL::swap() +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceWGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +static int GetWGLBufferBindTarget(EGLint buffer) +{ + switch (buffer) + { + case EGL_BACK_BUFFER: return WGL_BACK_LEFT_ARB; + default: UNREACHABLE(); return 0; + } +} + +egl::Error PbufferSurfaceWGL::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + if (!mFunctionsWGL->bindTexImageARB(mPbuffer, GetWGLBufferBindTarget(buffer))) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_SURFACE, "Failed to bind native wgl pbuffer, error: 0x%08x.", HRESULT_CODE(error)); + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceWGL::releaseTexImage(EGLint buffer) +{ + if (!mFunctionsWGL->releaseTexImageARB(mPbuffer, GetWGLBufferBindTarget(buffer))) + { + DWORD error = GetLastError(); + return egl::Error(EGL_BAD_SURFACE, "Failed to unbind native wgl pbuffer, error: 0x%08x.", HRESULT_CODE(error)); + } + + return egl::Error(EGL_SUCCESS); +} + +void PbufferSurfaceWGL::setSwapInterval(EGLint interval) +{ +} + +EGLint PbufferSurfaceWGL::getWidth() const +{ + return mWidth; +} + +EGLint PbufferSurfaceWGL::getHeight() const +{ + return mHeight; +} + +EGLint PbufferSurfaceWGL::isPostSubBufferSupported() const +{ + return EGL_FALSE; +} + +EGLint PbufferSurfaceWGL::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} + +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h new file mode 100755 index 000000000..56235293a --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h @@ -0,0 +1,74 @@ +// +// 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. +// + +// PBufferSurfaceWGL.h: WGL implementation of egl::Surface for PBuffers + +#ifndef LIBANGLE_RENDERER_GL_WGL_PBUFFERSURFACEWGL_H_ +#define LIBANGLE_RENDERER_GL_WGL_PBUFFERSURFACEWGL_H_ + +#include "libANGLE/renderer/gl/SurfaceGL.h" + +#include <GL/wglext.h> + +namespace rx +{ + +class FunctionsWGL; + +class PbufferSurfaceWGL : public SurfaceGL +{ + public: + PbufferSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLint width, + EGLint height, + EGLenum textureFormat, + EGLenum textureTarget, + bool largest, + int pixelFormat, + HDC deviceContext, + HGLRC wglContext, + const FunctionsWGL *functions); + ~PbufferSurfaceWGL() 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; + + private: + EGLint mWidth; + EGLint mHeight; + bool mLargest; + EGLenum mTextureFormat; + EGLenum mTextureTarget; + + int mPixelFormat; + + HGLRC mShareWGLContext; + + HDC mParentDeviceContext; + + HPBUFFERARB mPbuffer; + HDC mPbufferDeviceContext; + + const FunctionsWGL *mFunctionsWGL; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_PBUFFERSURFACEWGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.cpp new file mode 100755 index 000000000..f22943acb --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.cpp @@ -0,0 +1,178 @@ +// +// 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. +// + +// WindowSurfaceWGL.cpp: WGL implementation of egl::Surface for windows + +#include "libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h" + +#include "common/debug.h" +#include "libANGLE/renderer/gl/RendererGL.h" +#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" +#include "libANGLE/renderer/gl/wgl/wgl_utils.h" + +namespace rx +{ + +WindowSurfaceWGL::WindowSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLNativeWindowType window, + int pixelFormat, + HGLRC wglContext, + const FunctionsWGL *functions, + EGLint orientation) + : SurfaceGL(state, renderer), + mPixelFormat(pixelFormat), + mWGLContext(wglContext), + mWindow(window), + mDeviceContext(nullptr), + mFunctionsWGL(functions), + mSwapBehavior(0) +{ + // EGL_ANGLE_surface_orientation is not supported for regular WGL window surfaces + ASSERT(orientation == 0); +} + +WindowSurfaceWGL::~WindowSurfaceWGL() +{ + ReleaseDC(mWindow, mDeviceContext); + mDeviceContext = nullptr; +} + +egl::Error WindowSurfaceWGL::initialize() +{ + mDeviceContext = GetDC(mWindow); + if (!mDeviceContext) + { + return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to get the device context from the native window, " + "error: 0x%X.", GetLastError()); + } + + // Require that the pixel format for this window has not been set yet or is equal to the Display's pixel format. + int windowPixelFormat = GetPixelFormat(mDeviceContext); + if (windowPixelFormat == 0) + { + PIXELFORMATDESCRIPTOR pixelFormatDescriptor = { 0 }; + if (!DescribePixelFormat(mDeviceContext, mPixelFormat, sizeof(pixelFormatDescriptor), &pixelFormatDescriptor)) + { + return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to DescribePixelFormat, error: 0x%X.", GetLastError()); + } + + if (!SetPixelFormat(mDeviceContext, mPixelFormat, &pixelFormatDescriptor)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to set the pixel format on the device context, " + "error: 0x%X.", GetLastError()); + } + } + else if (windowPixelFormat != mPixelFormat) + { + return egl::Error(EGL_NOT_INITIALIZED, "Pixel format of the NativeWindow and NativeDisplayType must match."); + } + + // Check for the swap behavior of this pixel format + switch ( + wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, WGL_SWAP_METHOD_ARB, mFunctionsWGL)) + { + case WGL_SWAP_COPY_ARB: + mSwapBehavior = EGL_BUFFER_PRESERVED; + break; + + case WGL_SWAP_EXCHANGE_ARB: + case WGL_SWAP_UNDEFINED_ARB: + default: + mSwapBehavior = EGL_BUFFER_DESTROYED; + break; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceWGL::makeCurrent() +{ + if (!mFunctionsWGL->makeCurrent(mDeviceContext, 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 WindowSurfaceWGL::swap() +{ + if (!mFunctionsWGL->swapBuffers(mDeviceContext)) + { + // TODO: What error type here? + return egl::Error(EGL_CONTEXT_LOST, "Failed to swap buffers on the child window."); + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceWGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceWGL::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceWGL::releaseTexImage(EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +void WindowSurfaceWGL::setSwapInterval(EGLint interval) +{ + if (mFunctionsWGL->swapIntervalEXT) + { + mFunctionsWGL->swapIntervalEXT(interval); + } +} + +EGLint WindowSurfaceWGL::getWidth() const +{ + RECT rect; + if (!GetClientRect(mWindow, &rect)) + { + return 0; + } + return rect.right - rect.left; +} + +EGLint WindowSurfaceWGL::getHeight() const +{ + RECT rect; + if (!GetClientRect(mWindow, &rect)) + { + return 0; + } + return rect.bottom - rect.top; +} + +EGLint WindowSurfaceWGL::isPostSubBufferSupported() const +{ + // PostSubBuffer extension not exposed on WGL. + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLint WindowSurfaceWGL::getSwapBehavior() const +{ + return mSwapBehavior; +} + +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h new file mode 100755 index 000000000..eb95e4dc2 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h @@ -0,0 +1,64 @@ +// +// 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. +// + +// WindowSurfaceWGL.h: WGL implementation of egl::Surface for windows + +#ifndef LIBANGLE_RENDERER_GL_WGL_WINDOWSURFACEWGL_H_ +#define LIBANGLE_RENDERER_GL_WGL_WINDOWSURFACEWGL_H_ + +#include "libANGLE/renderer/gl/SurfaceGL.h" + +#include <GL/wglext.h> + +namespace rx +{ + +class FunctionsWGL; + +class WindowSurfaceWGL : public SurfaceGL +{ + public: + WindowSurfaceWGL(const egl::SurfaceState &state, + RendererGL *renderer, + EGLNativeWindowType window, + int pixelFormat, + HGLRC wglContext, + const FunctionsWGL *functions, + EGLint orientation); + ~WindowSurfaceWGL() 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; + + private: + int mPixelFormat; + + HGLRC mWGLContext; + + HWND mWindow; + HDC mDeviceContext; + + const FunctionsWGL *mFunctionsWGL; + + EGLint mSwapBehavior; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_WINDOWSURFACEWGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/functionswgl_typedefs.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/functionswgl_typedefs.h new file mode 100755 index 000000000..c4b79ee02 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/functionswgl_typedefs.h @@ -0,0 +1,43 @@ +// +// 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. +// + +// functionswgl_typedefs.h: Typedefs of WGL functions. + +#ifndef LIBANGLE_RENDERER_GL_WGL_FUNCTIONSWGLTYPEDEFS_H_ +#define LIBANGLE_RENDERER_GL_WGL_FUNCTIONSWGLTYPEDEFS_H_ + +#include "common/platform.h" + +#include <angle_gl.h> +#include <GL/wglext.h> + +namespace rx +{ + +typedef BOOL(WINAPI *PFNWGLCOPYCONTEXTPROC)(HGLRC, HGLRC, UINT); +typedef HGLRC(WINAPI *PFNWGLCREATECONTEXTPROC)(HDC); +typedef HGLRC(WINAPI *PFNWGLCREATELAYERCONTEXTPROC)(HDC, int); +typedef BOOL(WINAPI *PFNWGLDELETECONTEXTPROC)(HGLRC); +typedef HGLRC(WINAPI *PFNWGLGETCURRENTCONTEXTPROC)(VOID); +typedef HDC(WINAPI *PFNWGLGETCURRENTDCPROC)(VOID); +typedef PROC(WINAPI *PFNWGLGETPROCADDRESSPROC)(LPCSTR); +typedef BOOL(WINAPI *PFNWGLMAKECURRENTPROC)(HDC, HGLRC); +typedef BOOL(WINAPI *PFNWGLSHARELISTSPROC)(HGLRC, HGLRC); +typedef BOOL(WINAPI *PFNWGLUSEFONTBITMAPSAPROC)(HDC, DWORD, DWORD, DWORD); +typedef BOOL(WINAPI *PFNWGLUSEFONTBITMAPSWPROC)(HDC, DWORD, DWORD, DWORD); +typedef BOOL(WINAPI *PFNSWAPBUFFERSPROC)(HDC); +typedef BOOL(WINAPI *PFNWGLUSEFONTOUTLINESAPROC)(HDC, DWORD, DWORD, DWORD, FLOAT, FLOAT, int, LPGLYPHMETRICSFLOAT); +typedef BOOL(WINAPI *PFNWGLUSEFONTOUTLINESWPROC)(HDC, DWORD, DWORD, DWORD, FLOAT, FLOAT, int, LPGLYPHMETRICSFLOAT); +typedef BOOL(WINAPI *PFNWGLDESCRIBELAYERPLANEPROC)(HDC, int, int, UINT, LPLAYERPLANEDESCRIPTOR); +typedef int(WINAPI *PFNWGLSETLAYERPALETTEENTRIESPROC)(HDC, int, int, int, CONST COLORREF *); +typedef int(WINAPI *PFNWGLGETLAYERPALETTEENTRIESPROC)(HDC, int, int, int, COLORREF *); +typedef BOOL(WINAPI *PFNWGLREALIZELAYERPALETTEPROC)(HDC, int, BOOL); +typedef BOOL(WINAPI *PFNWGLSWAPLAYERBUFFERSPROC)(HDC, UINT); +typedef DWORD(WINAPI *PFNWGLSWAPMULTIPLEBUFFERSPROC)(UINT, CONST WGLSWAP *); + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_FUNCTIONSWGLTYPEDEFS_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.cpp b/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.cpp new file mode 100755 index 000000000..641c3fbc4 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.cpp @@ -0,0 +1,85 @@ +// +// 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. +// + +// wgl_utils.cpp: Utility routines specific to the WGL->EGL implementation. + +#include "libANGLE/renderer/gl/wgl/wgl_utils.h" + +#include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" + +namespace rx +{ + +namespace wgl +{ + +PIXELFORMATDESCRIPTOR GetDefaultPixelFormatDescriptor() +{ + PIXELFORMATDESCRIPTOR pixelFormatDescriptor = { 0 }; + pixelFormatDescriptor.nSize = sizeof(pixelFormatDescriptor); + pixelFormatDescriptor.nVersion = 1; + pixelFormatDescriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pixelFormatDescriptor.iPixelType = PFD_TYPE_RGBA; + pixelFormatDescriptor.cColorBits = 24; + pixelFormatDescriptor.cAlphaBits = 8; + pixelFormatDescriptor.cDepthBits = 24; + pixelFormatDescriptor.cStencilBits = 8; + pixelFormatDescriptor.iLayerType = PFD_MAIN_PLANE; + + return pixelFormatDescriptor; +} + +std::vector<int> GetDefaultPixelFormatAttributes(bool preservedSwap) +{ + std::vector<int> attribs; + attribs.push_back(WGL_DRAW_TO_WINDOW_ARB); + attribs.push_back(TRUE); + + attribs.push_back(WGL_ACCELERATION_ARB); + attribs.push_back(WGL_FULL_ACCELERATION_ARB); + + attribs.push_back(WGL_SUPPORT_OPENGL_ARB); + attribs.push_back(TRUE); + + attribs.push_back(WGL_DOUBLE_BUFFER_ARB); + attribs.push_back(TRUE); + + attribs.push_back(WGL_PIXEL_TYPE_ARB); + attribs.push_back(WGL_TYPE_RGBA_ARB); + + attribs.push_back(WGL_COLOR_BITS_ARB); + attribs.push_back(24); + + attribs.push_back(WGL_ALPHA_BITS_ARB); + attribs.push_back(8); + + attribs.push_back(WGL_DEPTH_BITS_ARB); + attribs.push_back(24); + + attribs.push_back(WGL_STENCIL_BITS_ARB); + attribs.push_back(8); + + attribs.push_back(WGL_SWAP_METHOD_ARB); + attribs.push_back(preservedSwap ? WGL_SWAP_COPY_ARB : WGL_SWAP_UNDEFINED_ARB); + + attribs.push_back(0); + + return attribs; +} + +int QueryWGLFormatAttrib(HDC dc, int format, int attribName, const FunctionsWGL *functions) +{ + int result = 0; + if (functions->getPixelFormatAttribivARB == nullptr || + !functions->getPixelFormatAttribivARB(dc, format, 0, 1, &attribName, &result)) + { + return 0; + } + return result; +} +} + +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.h b/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.h new file mode 100755 index 000000000..d4914b5d3 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.h @@ -0,0 +1,32 @@ +// +// 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. +// + +// wgl_utils.h: Utility routines specific to the WGL->EGL implementation. + +#ifndef LIBANGLE_RENDERER_GL_WGL_WGLUTILS_H_ +#define LIBANGLE_RENDERER_GL_WGL_WGLUTILS_H_ + +#include <vector> + +#include "common/platform.h" + +namespace rx +{ + +class FunctionsWGL; + +namespace wgl +{ + +PIXELFORMATDESCRIPTOR GetDefaultPixelFormatDescriptor(); +std::vector<int> GetDefaultPixelFormatAttributes(bool preservedSwap); + +int QueryWGLFormatAttrib(HDC dc, int format, int attribName, const FunctionsWGL *functions); +} + +} + +#endif // LIBANGLE_RENDERER_GL_WGL_WGLUTILS_H_ |