diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/SurfaceD3D.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/SurfaceD3D.cpp new file mode 100644 index 0000000000..256808637f --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -0,0 +1,517 @@ +// +// Copyright 2014 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. +// + +// SurfaceD3D.cpp: D3D implementation of an EGL surface + +#include "libANGLE/renderer/d3d/SurfaceD3D.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/d3d/DisplayD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" + +#include <EGL/eglext.h> +#include <tchar.h> +#include <algorithm> + +namespace rx +{ + +SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceImpl(state), + mRenderer(renderer), + mDisplay(display), + mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE), + mFixedWidth(0), + mFixedHeight(0), + mOrientation(static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))), + mRenderTargetFormat(state.config->renderTargetFormat), + mDepthStencilFormat(state.config->depthStencilFormat), + mColorFormat(nullptr), + mSwapChain(nullptr), + mSwapIntervalDirty(true), + mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)), + mWidth(static_cast<EGLint>(attribs.get(EGL_WIDTH, 0))), + mHeight(static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0))), + mSwapInterval(1), + mShareHandle(0), + mD3DTexture(nullptr), + mBuftype(buftype) +{ + if (window != nullptr && !mFixedSize) + { + mWidth = -1; + mHeight = -1; + } + + if (mFixedSize) + { + mFixedWidth = mWidth; + mFixedHeight = mHeight; + } + + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + mShareHandle = static_cast<HANDLE>(clientBuffer); + break; + + case EGL_D3D_TEXTURE_ANGLE: + mD3DTexture = static_cast<IUnknown *>(clientBuffer); + ASSERT(mD3DTexture != nullptr); + mD3DTexture->AddRef(); + break; + + default: + break; + } +} + +SurfaceD3D::~SurfaceD3D() +{ + releaseSwapChain(); + SafeDelete(mNativeWindow); + SafeRelease(mD3DTexture); +} + +void SurfaceD3D::releaseSwapChain() +{ + SafeDelete(mSwapChain); +} + +egl::Error SurfaceD3D::initialize(const egl::Display *display) +{ + if (mNativeWindow->getNativeWindow()) + { + if (!mNativeWindow->initialize()) + { + return egl::EglBadSurface(); + } + } + + if (mBuftype == EGL_D3D_TEXTURE_ANGLE) + { + ANGLE_TRY(mRenderer->getD3DTextureInfo(mState.config, mD3DTexture, mState.attributes, + &mFixedWidth, &mFixedHeight, nullptr, nullptr, + &mColorFormat, nullptr)); + 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"; + } + } + if (mColorFormat->id == angle::FormatID::R8G8B8A8_TYPELESS) + { + EGLAttrib colorspace = + mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR); + if (colorspace == EGL_GL_COLORSPACE_SRGB) + { + mColorFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_TYPELESS_SRGB); + } + } + if (mColorFormat->id == angle::FormatID::B8G8R8A8_TYPELESS) + { + EGLAttrib colorspace = + mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR); + if (colorspace == EGL_GL_COLORSPACE_SRGB) + { + mColorFormat = &angle::Format::Get(angle::FormatID::B8G8R8A8_TYPELESS_SRGB); + } + } + mRenderTargetFormat = mColorFormat->fboImplementationInternalFormat; + } + + ANGLE_TRY(resetSwapChain(display)); + return egl::NoError(); +} + +egl::Error SurfaceD3D::bindTexImage(const gl::Context *, gl::Texture *, EGLint) +{ + return egl::NoError(); +} + +egl::Error SurfaceD3D::releaseTexImage(const gl::Context *, EGLint) +{ + return egl::NoError(); +} + +egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + if (!mState.directComposition) + { + return egl::EglBadSurface() + << "getSyncValues: surface requires Direct Composition to be enabled"; + } + + return mSwapChain->getSyncValues(ust, msc, sbc); +} + +egl::Error SurfaceD3D::getMscRate(EGLint *numerator, EGLint *denominator) +{ + UNIMPLEMENTED(); + return egl::EglBadAccess(); +} + +egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display) +{ + ASSERT(!mSwapChain); + + int width; + int height; + + if (!mFixedSize) + { + RECT windowRect; + if (!mNativeWindow->getClientRect(&windowRect)) + { + ASSERT(false); + + return egl::EglBadSurface() << "Could not retrieve the window dimensions"; + } + + width = windowRect.right - windowRect.left; + height = windowRect.bottom - windowRect.top; + } + else + { + // non-window surface - size is determined at creation + width = mFixedWidth; + height = mFixedHeight; + } + + mSwapChain = + mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat, + mDepthStencilFormat, mOrientation, mState.config->samples); + if (!mSwapChain) + { + return egl::EglBadAlloc(); + } + + // This is a bit risky to pass the proxy context here, but it can happen at almost any time. + DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(display); + egl::Error error = resetSwapChain(displayD3D, width, height); + if (error.isError()) + { + SafeDelete(mSwapChain); + return error; + } + + return egl::NoError(); +} + +egl::Error SurfaceD3D::resizeSwapChain(DisplayD3D *displayD3D, + int backbufferWidth, + int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = + mSwapChain->resize(displayD3D, std::max(1, backbufferWidth), std::max(1, backbufferHeight)); + + if (status == EGL_CONTEXT_LOST) + { + mDisplay->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + return egl::NoError(); +} + +egl::Error SurfaceD3D::resetSwapChain(DisplayD3D *displayD3D, + int backbufferWidth, + int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = mSwapChain->reset(displayD3D, std::max(1, backbufferWidth), + std::max(1, backbufferHeight), mSwapInterval); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapIntervalDirty = false; + + return egl::NoError(); +} + +egl::Error SurfaceD3D::swapRect(DisplayD3D *displayD3D, + EGLint x, + EGLint y, + EGLint width, + EGLint height) +{ + if (!mSwapChain) + { + return egl::NoError(); + } + + if (x + width > mWidth) + { + width = mWidth - x; + } + + if (y + height > mHeight) + { + height = mHeight - y; + } + + if (width != 0 && height != 0) + { + EGLint status = mSwapChain->swapRect(displayD3D, x, y, width, height); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + } + + ANGLE_TRY(checkForOutOfDateSwapChain(displayD3D)); + + return egl::NoError(); +} + +egl::Error SurfaceD3D::checkForOutOfDateSwapChain(DisplayD3D *displayD3D) +{ + RECT client; + int clientWidth = getWidth(); + int clientHeight = getHeight(); + bool sizeDirty = false; + if (!mFixedSize && !mNativeWindow->isIconic()) + { + // The window is automatically resized to 150x22 when it's minimized, but the swapchain + // shouldn't be resized because that's not a useful size to render to. + if (!mNativeWindow->getClientRect(&client)) + { + UNREACHABLE(); + return egl::NoError(); + } + + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing + // information. + clientWidth = client.right - client.left; + clientHeight = client.bottom - client.top; + sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + } + else if (mFixedSize) + { + clientWidth = mFixedWidth; + clientHeight = mFixedHeight; + sizeDirty = mFixedWidth != getWidth() || mFixedHeight != getHeight(); + } + + if (mSwapIntervalDirty) + { + ANGLE_TRY(resetSwapChain(displayD3D, clientWidth, clientHeight)); + } + else if (sizeDirty) + { + ANGLE_TRY(resizeSwapChain(displayD3D, clientWidth, clientHeight)); + } + + return egl::NoError(); +} + +egl::Error SurfaceD3D::swap(const gl::Context *context) +{ + DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay()); + return swapRect(displayD3D, 0, 0, mWidth, mHeight); +} + +egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) +{ + DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay()); + return swapRect(displayD3D, x, y, width, height); +} + +rx::SwapChainD3D *SurfaceD3D::getSwapChain() const +{ + return mSwapChain; +} + +void SurfaceD3D::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapIntervalDirty = true; +} + +void SurfaceD3D::setFixedWidth(EGLint width) +{ + mFixedWidth = width; +} + +void SurfaceD3D::setFixedHeight(EGLint height) +{ + mFixedHeight = height; +} + +EGLint SurfaceD3D::getWidth() const +{ + return mWidth; +} + +EGLint SurfaceD3D::getHeight() const +{ + return mHeight; +} + +EGLint SurfaceD3D::isPostSubBufferSupported() const +{ + // post sub buffer is always possible on D3D surfaces + return EGL_TRUE; +} + +EGLint SurfaceD3D::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} + +egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) + { + *value = mSwapChain->getShareHandle(); + } + else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE) + { + *value = mSwapChain->getKeyedMutex(); + } + else + UNREACHABLE(); + + return egl::NoError(); +} + +const angle::Format *SurfaceD3D::getD3DTextureColorFormat() const +{ + return mColorFormat; +} + +egl::Error SurfaceD3D::attachToFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer) +{ + return egl::NoError(); +} + +egl::Error SurfaceD3D::detachFromFramebuffer(const gl::Context *context, + gl::Framebuffer *framebuffer) +{ + return egl::NoError(); +} + +angle::Result SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, + GLsizei samples, + FramebufferAttachmentRenderTarget **rtOut) +{ + if (binding == GL_BACK) + { + *rtOut = mSwapChain->getColorRenderTarget(); + } + else + { + *rtOut = mSwapChain->getDepthStencilRenderTarget(); + } + return angle::Result::Continue; +} + +angle::Result SurfaceD3D::initializeContents(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex) +{ + switch (binding) + { + case GL_BACK: + ASSERT(mState.config->renderTargetFormat != GL_NONE); + ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getColorRenderTarget())); + break; + + case GL_DEPTH: + case GL_STENCIL: + ASSERT(mState.config->depthStencilFormat != GL_NONE); + ANGLE_TRY( + mRenderer->initRenderTarget(context, mSwapChain->getDepthStencilRenderTarget())); + break; + + default: + UNREACHABLE(); + break; + } + return angle::Result::Continue; +} + +WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, renderer, display, window, 0, static_cast<EGLClientBuffer>(0), attribs) +{} + +WindowSurfaceD3D::~WindowSurfaceD3D() {} + +PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, + renderer, + display, + static_cast<EGLNativeWindowType>(0), + buftype, + clientBuffer, + attribs) +{} + +PbufferSurfaceD3D::~PbufferSurfaceD3D() {} + +} // namespace rx |