tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SurfaceD3D.cpp (14769B)


      1 //
      2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // SurfaceD3D.cpp: D3D implementation of an EGL surface
      8 
      9 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
     10 
     11 #include "libANGLE/Context.h"
     12 #include "libANGLE/Display.h"
     13 #include "libANGLE/Surface.h"
     14 #include "libANGLE/renderer/Format.h"
     15 #include "libANGLE/renderer/d3d/DisplayD3D.h"
     16 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
     17 #include "libANGLE/renderer/d3d/RendererD3D.h"
     18 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
     19 
     20 #include <EGL/eglext.h>
     21 #include <tchar.h>
     22 #include <algorithm>
     23 
     24 namespace rx
     25 {
     26 
     27 SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state,
     28                       RendererD3D *renderer,
     29                       egl::Display *display,
     30                       EGLNativeWindowType window,
     31                       EGLenum buftype,
     32                       EGLClientBuffer clientBuffer,
     33                       const egl::AttributeMap &attribs)
     34    : SurfaceImpl(state),
     35      mRenderer(renderer),
     36      mDisplay(display),
     37      mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE),
     38      mFixedWidth(0),
     39      mFixedHeight(0),
     40      mOrientation(static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))),
     41      mRenderTargetFormat(state.config->renderTargetFormat),
     42      mDepthStencilFormat(state.config->depthStencilFormat),
     43      mColorFormat(nullptr),
     44      mSwapChain(nullptr),
     45      mSwapIntervalDirty(true),
     46      mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)),
     47      mWidth(static_cast<EGLint>(attribs.get(EGL_WIDTH, 0))),
     48      mHeight(static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0))),
     49      mSwapInterval(1),
     50      mShareHandle(0),
     51      mD3DTexture(nullptr),
     52      mBuftype(buftype)
     53 {
     54    if (window != nullptr && !mFixedSize)
     55    {
     56        mWidth  = -1;
     57        mHeight = -1;
     58    }
     59 
     60    if (mFixedSize)
     61    {
     62        mFixedWidth  = mWidth;
     63        mFixedHeight = mHeight;
     64    }
     65 
     66    switch (buftype)
     67    {
     68        case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
     69            mShareHandle = static_cast<HANDLE>(clientBuffer);
     70            break;
     71 
     72        case EGL_D3D_TEXTURE_ANGLE:
     73            mD3DTexture = static_cast<IUnknown *>(clientBuffer);
     74            ASSERT(mD3DTexture != nullptr);
     75            mD3DTexture->AddRef();
     76            break;
     77 
     78        default:
     79            break;
     80    }
     81 }
     82 
     83 SurfaceD3D::~SurfaceD3D()
     84 {
     85    releaseSwapChain();
     86    SafeDelete(mNativeWindow);
     87    SafeRelease(mD3DTexture);
     88 }
     89 
     90 void SurfaceD3D::releaseSwapChain()
     91 {
     92    SafeDelete(mSwapChain);
     93 }
     94 
     95 egl::Error SurfaceD3D::initialize(const egl::Display *display)
     96 {
     97    if (mNativeWindow->getNativeWindow())
     98    {
     99        if (!mNativeWindow->initialize())
    100        {
    101            return egl::EglBadSurface();
    102        }
    103    }
    104 
    105    if (mBuftype == EGL_D3D_TEXTURE_ANGLE)
    106    {
    107        ANGLE_TRY(mRenderer->getD3DTextureInfo(mState.config, mD3DTexture, mState.attributes,
    108                                               &mFixedWidth, &mFixedHeight, nullptr, nullptr,
    109                                               &mColorFormat, nullptr));
    110        if (mState.attributes.contains(EGL_GL_COLORSPACE))
    111        {
    112            if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS &&
    113                mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS)
    114            {
    115                return egl::EglBadMatch()
    116                       << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures";
    117            }
    118        }
    119        if (mColorFormat->id == angle::FormatID::R8G8B8A8_TYPELESS)
    120        {
    121            EGLAttrib colorspace =
    122                mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
    123            if (colorspace == EGL_GL_COLORSPACE_SRGB)
    124            {
    125                mColorFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_TYPELESS_SRGB);
    126            }
    127        }
    128        if (mColorFormat->id == angle::FormatID::B8G8R8A8_TYPELESS)
    129        {
    130            EGLAttrib colorspace =
    131                mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
    132            if (colorspace == EGL_GL_COLORSPACE_SRGB)
    133            {
    134                mColorFormat = &angle::Format::Get(angle::FormatID::B8G8R8A8_TYPELESS_SRGB);
    135            }
    136        }
    137        mRenderTargetFormat = mColorFormat->fboImplementationInternalFormat;
    138    }
    139 
    140    ANGLE_TRY(resetSwapChain(display));
    141    return egl::NoError();
    142 }
    143 
    144 egl::Error SurfaceD3D::bindTexImage(const gl::Context *, gl::Texture *, EGLint)
    145 {
    146    return egl::NoError();
    147 }
    148 
    149 egl::Error SurfaceD3D::releaseTexImage(const gl::Context *, EGLint)
    150 {
    151    return egl::NoError();
    152 }
    153 
    154 egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
    155 {
    156    if (!mState.directComposition)
    157    {
    158        return egl::EglBadSurface()
    159               << "getSyncValues: surface requires Direct Composition to be enabled";
    160    }
    161 
    162    return mSwapChain->getSyncValues(ust, msc, sbc);
    163 }
    164 
    165 egl::Error SurfaceD3D::getMscRate(EGLint *numerator, EGLint *denominator)
    166 {
    167    UNIMPLEMENTED();
    168    return egl::EglBadAccess();
    169 }
    170 
    171 egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display)
    172 {
    173    ASSERT(!mSwapChain);
    174 
    175    int width;
    176    int height;
    177 
    178    if (!mFixedSize)
    179    {
    180        RECT windowRect;
    181        if (!mNativeWindow->getClientRect(&windowRect))
    182        {
    183            ASSERT(false);
    184 
    185            return egl::EglBadSurface() << "Could not retrieve the window dimensions";
    186        }
    187 
    188        width  = windowRect.right - windowRect.left;
    189        height = windowRect.bottom - windowRect.top;
    190    }
    191    else
    192    {
    193        // non-window surface - size is determined at creation
    194        width  = mFixedWidth;
    195        height = mFixedHeight;
    196    }
    197 
    198    mSwapChain =
    199        mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat,
    200                                   mDepthStencilFormat, mOrientation, mState.config->samples);
    201    if (!mSwapChain)
    202    {
    203        return egl::EglBadAlloc();
    204    }
    205 
    206    // This is a bit risky to pass the proxy context here, but it can happen at almost any time.
    207    DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(display);
    208    egl::Error error       = resetSwapChain(displayD3D, width, height);
    209    if (error.isError())
    210    {
    211        SafeDelete(mSwapChain);
    212        return error;
    213    }
    214 
    215    return egl::NoError();
    216 }
    217 
    218 egl::Error SurfaceD3D::resizeSwapChain(DisplayD3D *displayD3D,
    219                                       int backbufferWidth,
    220                                       int backbufferHeight)
    221 {
    222    ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
    223    ASSERT(mSwapChain);
    224 
    225    EGLint status =
    226        mSwapChain->resize(displayD3D, std::max(1, backbufferWidth), std::max(1, backbufferHeight));
    227 
    228    if (status == EGL_CONTEXT_LOST)
    229    {
    230        mDisplay->notifyDeviceLost();
    231        return egl::Error(status);
    232    }
    233    else if (status != EGL_SUCCESS)
    234    {
    235        return egl::Error(status);
    236    }
    237 
    238    mWidth  = backbufferWidth;
    239    mHeight = backbufferHeight;
    240 
    241    return egl::NoError();
    242 }
    243 
    244 egl::Error SurfaceD3D::resetSwapChain(DisplayD3D *displayD3D,
    245                                      int backbufferWidth,
    246                                      int backbufferHeight)
    247 {
    248    ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
    249    ASSERT(mSwapChain);
    250 
    251    EGLint status = mSwapChain->reset(displayD3D, std::max(1, backbufferWidth),
    252                                      std::max(1, backbufferHeight), mSwapInterval);
    253 
    254    if (status == EGL_CONTEXT_LOST)
    255    {
    256        mRenderer->notifyDeviceLost();
    257        return egl::Error(status);
    258    }
    259    else if (status != EGL_SUCCESS)
    260    {
    261        return egl::Error(status);
    262    }
    263 
    264    mWidth             = backbufferWidth;
    265    mHeight            = backbufferHeight;
    266    mSwapIntervalDirty = false;
    267 
    268    return egl::NoError();
    269 }
    270 
    271 egl::Error SurfaceD3D::swapRect(DisplayD3D *displayD3D,
    272                                EGLint x,
    273                                EGLint y,
    274                                EGLint width,
    275                                EGLint height)
    276 {
    277    if (!mSwapChain)
    278    {
    279        return egl::NoError();
    280    }
    281 
    282    if (x + width > mWidth)
    283    {
    284        width = mWidth - x;
    285    }
    286 
    287    if (y + height > mHeight)
    288    {
    289        height = mHeight - y;
    290    }
    291 
    292    if (width != 0 && height != 0)
    293    {
    294        EGLint status = mSwapChain->swapRect(displayD3D, x, y, width, height);
    295 
    296        if (status == EGL_CONTEXT_LOST)
    297        {
    298            mRenderer->notifyDeviceLost();
    299            return egl::Error(status);
    300        }
    301        else if (status != EGL_SUCCESS)
    302        {
    303            return egl::Error(status);
    304        }
    305    }
    306 
    307    ANGLE_TRY(checkForOutOfDateSwapChain(displayD3D));
    308 
    309    return egl::NoError();
    310 }
    311 
    312 egl::Error SurfaceD3D::checkForOutOfDateSwapChain(DisplayD3D *displayD3D)
    313 {
    314    RECT client;
    315    int clientWidth  = getWidth();
    316    int clientHeight = getHeight();
    317    bool sizeDirty   = false;
    318    if (!mFixedSize && !mNativeWindow->isIconic())
    319    {
    320        // The window is automatically resized to 150x22 when it's minimized, but the swapchain
    321        // shouldn't be resized because that's not a useful size to render to.
    322        if (!mNativeWindow->getClientRect(&client))
    323        {
    324            UNREACHABLE();
    325            return egl::NoError();
    326        }
    327 
    328        // Grow the buffer now, if the window has grown. We need to grow now to avoid losing
    329        // information.
    330        clientWidth  = client.right - client.left;
    331        clientHeight = client.bottom - client.top;
    332        sizeDirty    = clientWidth != getWidth() || clientHeight != getHeight();
    333    }
    334    else if (mFixedSize)
    335    {
    336        clientWidth  = mFixedWidth;
    337        clientHeight = mFixedHeight;
    338        sizeDirty    = mFixedWidth != getWidth() || mFixedHeight != getHeight();
    339    }
    340 
    341    if (mSwapIntervalDirty)
    342    {
    343        ANGLE_TRY(resetSwapChain(displayD3D, clientWidth, clientHeight));
    344    }
    345    else if (sizeDirty)
    346    {
    347        ANGLE_TRY(resizeSwapChain(displayD3D, clientWidth, clientHeight));
    348    }
    349 
    350    return egl::NoError();
    351 }
    352 
    353 egl::Error SurfaceD3D::swap(const gl::Context *context)
    354 {
    355    DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
    356    return swapRect(displayD3D, 0, 0, mWidth, mHeight);
    357 }
    358 
    359 egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context,
    360                                     EGLint x,
    361                                     EGLint y,
    362                                     EGLint width,
    363                                     EGLint height)
    364 {
    365    DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
    366    return swapRect(displayD3D, x, y, width, height);
    367 }
    368 
    369 rx::SwapChainD3D *SurfaceD3D::getSwapChain() const
    370 {
    371    return mSwapChain;
    372 }
    373 
    374 void SurfaceD3D::setSwapInterval(EGLint interval)
    375 {
    376    if (mSwapInterval == interval)
    377    {
    378        return;
    379    }
    380 
    381    mSwapInterval      = interval;
    382    mSwapIntervalDirty = true;
    383 }
    384 
    385 void SurfaceD3D::setFixedWidth(EGLint width)
    386 {
    387    mFixedWidth = width;
    388 }
    389 
    390 void SurfaceD3D::setFixedHeight(EGLint height)
    391 {
    392    mFixedHeight = height;
    393 }
    394 
    395 EGLint SurfaceD3D::getWidth() const
    396 {
    397    return mWidth;
    398 }
    399 
    400 EGLint SurfaceD3D::getHeight() const
    401 {
    402    return mHeight;
    403 }
    404 
    405 EGLint SurfaceD3D::isPostSubBufferSupported() const
    406 {
    407    // post sub buffer is always possible on D3D surfaces
    408    return EGL_TRUE;
    409 }
    410 
    411 EGLint SurfaceD3D::getSwapBehavior() const
    412 {
    413    return EGL_BUFFER_PRESERVED;
    414 }
    415 
    416 egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value)
    417 {
    418    if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
    419    {
    420        *value = mSwapChain->getShareHandle();
    421    }
    422    else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE)
    423    {
    424        *value = mSwapChain->getKeyedMutex();
    425    }
    426    else
    427        UNREACHABLE();
    428 
    429    return egl::NoError();
    430 }
    431 
    432 const angle::Format *SurfaceD3D::getD3DTextureColorFormat() const
    433 {
    434    return mColorFormat;
    435 }
    436 
    437 egl::Error SurfaceD3D::attachToFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer)
    438 {
    439    return egl::NoError();
    440 }
    441 
    442 egl::Error SurfaceD3D::detachFromFramebuffer(const gl::Context *context,
    443                                             gl::Framebuffer *framebuffer)
    444 {
    445    return egl::NoError();
    446 }
    447 
    448 angle::Result SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context,
    449                                                    GLenum binding,
    450                                                    const gl::ImageIndex &imageIndex,
    451                                                    GLsizei samples,
    452                                                    FramebufferAttachmentRenderTarget **rtOut)
    453 {
    454    if (binding == GL_BACK)
    455    {
    456        *rtOut = mSwapChain->getColorRenderTarget();
    457    }
    458    else
    459    {
    460        *rtOut = mSwapChain->getDepthStencilRenderTarget();
    461    }
    462    return angle::Result::Continue;
    463 }
    464 
    465 angle::Result SurfaceD3D::initializeContents(const gl::Context *context,
    466                                             GLenum binding,
    467                                             const gl::ImageIndex &imageIndex)
    468 {
    469    switch (binding)
    470    {
    471        case GL_BACK:
    472            ASSERT(mState.config->renderTargetFormat != GL_NONE);
    473            ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getColorRenderTarget()));
    474            break;
    475 
    476        case GL_DEPTH:
    477        case GL_STENCIL:
    478            ASSERT(mState.config->depthStencilFormat != GL_NONE);
    479            ANGLE_TRY(
    480                mRenderer->initRenderTarget(context, mSwapChain->getDepthStencilRenderTarget()));
    481            break;
    482 
    483        default:
    484            UNREACHABLE();
    485            break;
    486    }
    487    return angle::Result::Continue;
    488 }
    489 
    490 WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state,
    491                                   RendererD3D *renderer,
    492                                   egl::Display *display,
    493                                   EGLNativeWindowType window,
    494                                   const egl::AttributeMap &attribs)
    495    : SurfaceD3D(state, renderer, display, window, 0, static_cast<EGLClientBuffer>(0), attribs)
    496 {}
    497 
    498 WindowSurfaceD3D::~WindowSurfaceD3D() {}
    499 
    500 PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state,
    501                                     RendererD3D *renderer,
    502                                     egl::Display *display,
    503                                     EGLenum buftype,
    504                                     EGLClientBuffer clientBuffer,
    505                                     const egl::AttributeMap &attribs)
    506    : SurfaceD3D(state,
    507                 renderer,
    508                 display,
    509                 static_cast<EGLNativeWindowType>(0),
    510                 buftype,
    511                 clientBuffer,
    512                 attribs)
    513 {}
    514 
    515 PbufferSurfaceD3D::~PbufferSurfaceD3D() {}
    516 
    517 }  // namespace rx