| // |
| // Copyright 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/Surface.h" |
| #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" |
| #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" |
| #include "libANGLE/renderer/gl/FramebufferGL.h" |
| #include "libANGLE/renderer/gl/RendererGL.h" |
| #include "libANGLE/renderer/gl/StateManagerGL.h" |
| #include "libANGLE/renderer/gl/TextureGL.h" |
| #include "libANGLE/renderer/gl/wgl/DisplayWGL.h" |
| #include "libANGLE/renderer/gl/wgl/FunctionsWGL.h" |
| |
| namespace rx |
| { |
| |
| namespace |
| { |
| |
| egl::Error GetD3D11TextureInfo(EGLenum buftype, |
| ID3D11Texture2D *texture11, |
| size_t *width, |
| size_t *height, |
| const angle::Format **angleFormat, |
| IUnknown **object, |
| IUnknown **device) |
| { |
| D3D11_TEXTURE2D_DESC textureDesc; |
| texture11->GetDesc(&textureDesc); |
| |
| if (buftype == EGL_D3D_TEXTURE_ANGLE) |
| { |
| // 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::EglBadParameter() |
| << "Unknown client buffer texture format: " << textureDesc.Format; |
| } |
| } |
| |
| ID3D11Device *d3d11Device = nullptr; |
| texture11->GetDevice(&d3d11Device); |
| if (d3d11Device == nullptr) |
| { |
| SafeRelease(texture11); |
| return egl::EglBadParameter() << "Could not query the D3D11 device from the client buffer."; |
| } |
| |
| if (angleFormat) |
| { |
| *angleFormat = &d3d11_angle::GetFormat(textureDesc.Format); |
| } |
| |
| 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::NoError(); |
| } |
| |
| egl::Error GetD3D9TextureInfo(EGLenum buftype, |
| IDirect3DTexture9 *texture9, |
| size_t *width, |
| size_t *height, |
| const angle::Format **angleFormat, |
| IUnknown **object, |
| IUnknown **device) |
| { |
| D3DSURFACE_DESC surfaceDesc; |
| if (FAILED(texture9->GetLevelDesc(0, &surfaceDesc))) |
| { |
| SafeRelease(texture9); |
| return egl::EglBadParameter() << "Could not query description of the D3D9 surface."; |
| } |
| |
| if (buftype == EGL_D3D_TEXTURE_ANGLE) |
| { |
| // 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::EglBadParameter() |
| << "Unknown client buffer texture format: " << surfaceDesc.Format; |
| } |
| } |
| |
| if (angleFormat) |
| { |
| const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(surfaceDesc.Format); |
| ASSERT(d3dFormatInfo.info().id != angle::FormatID::NONE); |
| *angleFormat = &d3dFormatInfo.info(); |
| } |
| |
| 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::EglBadParameter() << "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::NoError(); |
| } |
| |
| egl::Error GetD3DTextureInfo(EGLenum buftype, |
| EGLClientBuffer clientBuffer, |
| ID3D11Device *d3d11Device, |
| size_t *width, |
| size_t *height, |
| const angle::Format **angleFormat, |
| IUnknown **object, |
| IUnknown **device) |
| { |
| if (buftype == EGL_D3D_TEXTURE_ANGLE) |
| { |
| IUnknown *buffer = static_cast<IUnknown *>(clientBuffer); |
| ID3D11Texture2D *texture11 = nullptr; |
| IDirect3DTexture9 *texture9 = nullptr; |
| if (SUCCEEDED(buffer->QueryInterface<ID3D11Texture2D>(&texture11))) |
| { |
| return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object, |
| device); |
| } |
| else if (SUCCEEDED(buffer->QueryInterface<IDirect3DTexture9>(&texture9))) |
| { |
| return GetD3D9TextureInfo(buftype, texture9, width, height, angleFormat, object, |
| device); |
| } |
| else |
| { |
| return egl::EglBadParameter() |
| << "Provided buffer is not a IDirect3DTexture9 or ID3D11Texture2D."; |
| } |
| } |
| else if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) |
| { |
| ASSERT(d3d11Device); |
| HANDLE shareHandle = static_cast<HANDLE>(clientBuffer); |
| ID3D11Texture2D *texture11 = nullptr; |
| HRESULT result = d3d11Device->OpenSharedResource(shareHandle, __uuidof(ID3D11Texture2D), |
| reinterpret_cast<void **>(&texture11)); |
| if (FAILED(result)) |
| { |
| return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); |
| } |
| |
| return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object, device); |
| } |
| else |
| { |
| UNREACHABLE(); |
| return egl::EglBadDisplay() << "Unknown buftype for D3DTextureSurfaceWGL."; |
| } |
| } |
| |
| } // anonymous namespace |
| |
| D3DTextureSurfaceWGL::D3DTextureSurfaceWGL(const egl::SurfaceState &state, |
| StateManagerGL *stateManager, |
| EGLenum buftype, |
| EGLClientBuffer clientBuffer, |
| DisplayWGL *display, |
| HDC deviceContext, |
| ID3D11Device *displayD3D11Device, |
| const FunctionsGL *functionsGL, |
| const FunctionsWGL *functionsWGL) |
| : SurfaceWGL(state), |
| mBuftype(buftype), |
| mClientBuffer(clientBuffer), |
| mDisplayD3D11Device(displayD3D11Device), |
| mDisplay(display), |
| mStateManager(stateManager), |
| mFunctionsGL(functionsGL), |
| mFunctionsWGL(functionsWGL), |
| mDeviceContext(deviceContext), |
| mWidth(0), |
| mHeight(0), |
| mColorFormat(nullptr), |
| mDeviceHandle(nullptr), |
| mObject(nullptr), |
| mKeyedMutex(nullptr), |
| mBoundObjectTextureHandle(nullptr), |
| mBoundObjectRenderbufferHandle(nullptr), |
| mColorRenderbufferID(0), |
| mDepthStencilRenderbufferID(0) |
| {} |
| |
| D3DTextureSurfaceWGL::~D3DTextureSurfaceWGL() |
| { |
| ASSERT(mBoundObjectTextureHandle == nullptr); |
| |
| SafeRelease(mObject); |
| SafeRelease(mKeyedMutex); |
| |
| if (mDeviceHandle) |
| { |
| if (mBoundObjectRenderbufferHandle) |
| { |
| mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectRenderbufferHandle); |
| mBoundObjectRenderbufferHandle = nullptr; |
| } |
| mStateManager->deleteRenderbuffer(mColorRenderbufferID); |
| mStateManager->deleteRenderbuffer(mDepthStencilRenderbufferID); |
| |
| if (mBoundObjectTextureHandle) |
| { |
| mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle); |
| mBoundObjectTextureHandle = nullptr; |
| } |
| |
| mDisplay->releaseD3DDevice(mDeviceHandle); |
| mDeviceHandle = nullptr; |
| } |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(EGLenum buftype, |
| EGLClientBuffer clientBuffer, |
| ID3D11Device *d3d11Device) |
| { |
| return GetD3DTextureInfo(buftype, clientBuffer, d3d11Device, nullptr, nullptr, nullptr, nullptr, |
| nullptr); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::initialize(const egl::Display *display) |
| { |
| IUnknown *device = nullptr; |
| ANGLE_TRY(GetD3DTextureInfo(mBuftype, mClientBuffer, mDisplayD3D11Device, &mWidth, &mHeight, |
| &mColorFormat, &mObject, &device)); |
| |
| if (mColorFormat) |
| { |
| if (mState.attributes.contains(EGL_GL_COLORSPACE)) |
| { |
| if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS && |
| mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS) |
| { |
| return egl::EglBadMatch() |
| << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures"; |
| } |
| } |
| } |
| |
| // Grab the keyed mutex, if one exists |
| mObject->QueryInterface(&mKeyedMutex); |
| |
| ASSERT(device != nullptr); |
| egl::Error error = mDisplay->registerD3DDevice(device, &mDeviceHandle); |
| SafeRelease(device); |
| if (error.isError()) |
| { |
| return error; |
| } |
| |
| mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID); |
| mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID); |
| mBoundObjectRenderbufferHandle = mFunctionsWGL->dxRegisterObjectNV( |
| mDeviceHandle, mObject, mColorRenderbufferID, GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV); |
| if (mBoundObjectRenderbufferHandle == nullptr) |
| { |
| return egl::EglBadAlloc() << "Failed to register D3D object, " |
| << gl::FmtErr(HRESULT_CODE(GetLastError())); |
| } |
| |
| const egl::Config *config = mState.config; |
| if (config->depthStencilFormat != GL_NONE) |
| { |
| mFunctionsGL->genRenderbuffers(1, &mDepthStencilRenderbufferID); |
| mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthStencilRenderbufferID); |
| mFunctionsGL->renderbufferStorage(GL_RENDERBUFFER, config->depthStencilFormat, |
| static_cast<GLsizei>(mWidth), |
| static_cast<GLsizei>(mHeight)); |
| } |
| |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::makeCurrent(const gl::Context *context) |
| { |
| if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle)) |
| { |
| DWORD error = GetLastError(); |
| return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::unMakeCurrent(const gl::Context *context) |
| { |
| if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle)) |
| { |
| DWORD error = GetLastError(); |
| return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::swap(const gl::Context *context) |
| { |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::postSubBuffer(const gl::Context *context, |
| EGLint x, |
| EGLint y, |
| EGLint width, |
| EGLint height) |
| { |
| UNIMPLEMENTED(); |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value) |
| { |
| switch (attribute) |
| { |
| case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: |
| *value = (mBuftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) ? mClientBuffer : nullptr; |
| break; |
| |
| case EGL_DXGI_KEYED_MUTEX_ANGLE: |
| *value = mKeyedMutex; |
| break; |
| |
| default: |
| UNREACHABLE(); |
| } |
| |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::bindTexImage(const gl::Context *context, |
| 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::EglBadAlloc() << "Failed to register D3D object, " |
| << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| |
| if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle)) |
| { |
| DWORD error = GetLastError(); |
| return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| |
| return egl::NoError(); |
| } |
| |
| egl::Error D3DTextureSurfaceWGL::releaseTexImage(const gl::Context *context, EGLint buffer) |
| { |
| ASSERT(mBoundObjectTextureHandle != nullptr); |
| if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle)) |
| { |
| DWORD error = GetLastError(); |
| return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| |
| if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle)) |
| { |
| DWORD error = GetLastError(); |
| return egl::EglBadAlloc() << "Failed to unregister D3D object, " |
| << gl::FmtErr(HRESULT_CODE(error)); |
| } |
| mBoundObjectTextureHandle = nullptr; |
| |
| return egl::NoError(); |
| } |
| |
| 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::Context *context, |
| const gl::FramebufferState &data) |
| { |
| const FunctionsGL *functions = GetFunctionsGL(context); |
| StateManagerGL *stateManager = GetStateManagerGL(context); |
| |
| GLuint framebufferID = 0; |
| functions->genFramebuffers(1, &framebufferID); |
| stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferID); |
| functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| mColorRenderbufferID); |
| if (mState.config->depthSize > 0) |
| { |
| functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| mDepthStencilRenderbufferID); |
| } |
| if (mState.config->stencilSize > 0) |
| { |
| functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| mDepthStencilRenderbufferID); |
| } |
| |
| return new FramebufferGL(data, framebufferID, true, false); |
| } |
| |
| HDC D3DTextureSurfaceWGL::getDC() const |
| { |
| return mDeviceContext; |
| } |
| |
| const angle::Format *D3DTextureSurfaceWGL::getD3DTextureColorFormat() const |
| { |
| return mColorFormat; |
| } |
| |
| } // namespace rx |