tor-browser

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

SwapChain9.cpp (15101B)


      1 //
      2 // Copyright 2012 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 // SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.
      8 
      9 #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
     10 
     11 #include "libANGLE/features.h"
     12 #include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h"
     13 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
     14 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
     15 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
     16 
     17 namespace rx
     18 {
     19 
     20 SwapChain9::SwapChain9(Renderer9 *renderer,
     21                       NativeWindow9 *nativeWindow,
     22                       HANDLE shareHandle,
     23                       IUnknown *d3dTexture,
     24                       GLenum backBufferFormat,
     25                       GLenum depthBufferFormat,
     26                       EGLint orientation)
     27    : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat),
     28      mRenderer(renderer),
     29      mWidth(-1),
     30      mHeight(-1),
     31      mSwapInterval(-1),
     32      mNativeWindow(nativeWindow),
     33      mSwapChain(nullptr),
     34      mBackBuffer(nullptr),
     35      mRenderTarget(nullptr),
     36      mDepthStencil(nullptr),
     37      mOffscreenTexture(nullptr),
     38      mColorRenderTarget(this, false),
     39      mDepthStencilRenderTarget(this, true)
     40 {
     41    ASSERT(orientation == 0);
     42 }
     43 
     44 SwapChain9::~SwapChain9()
     45 {
     46    release();
     47 }
     48 
     49 void SwapChain9::release()
     50 {
     51    SafeRelease(mSwapChain);
     52    SafeRelease(mBackBuffer);
     53    SafeRelease(mDepthStencil);
     54    SafeRelease(mRenderTarget);
     55    SafeRelease(mOffscreenTexture);
     56 
     57    if (mNativeWindow->getNativeWindow())
     58    {
     59        mShareHandle = nullptr;
     60    }
     61 }
     62 
     63 static DWORD convertInterval(EGLint interval)
     64 {
     65 #if ANGLE_VSYNC == ANGLE_DISABLED
     66    return D3DPRESENT_INTERVAL_IMMEDIATE;
     67 #else
     68    switch (interval)
     69    {
     70        case 0:
     71            return D3DPRESENT_INTERVAL_IMMEDIATE;
     72        case 1:
     73            return D3DPRESENT_INTERVAL_ONE;
     74        case 2:
     75            return D3DPRESENT_INTERVAL_TWO;
     76        case 3:
     77            return D3DPRESENT_INTERVAL_THREE;
     78        case 4:
     79            return D3DPRESENT_INTERVAL_FOUR;
     80        default:
     81            UNREACHABLE();
     82    }
     83 
     84    return D3DPRESENT_INTERVAL_DEFAULT;
     85 #endif
     86 }
     87 
     88 EGLint SwapChain9::resize(DisplayD3D *displayD3D, int backbufferWidth, int backbufferHeight)
     89 {
     90    // D3D9 does not support resizing swap chains without recreating them
     91    return reset(displayD3D, backbufferWidth, backbufferHeight, mSwapInterval);
     92 }
     93 
     94 EGLint SwapChain9::reset(DisplayD3D *displayD3D,
     95                         int backbufferWidth,
     96                         int backbufferHeight,
     97                         EGLint swapInterval)
     98 {
     99    IDirect3DDevice9 *device = mRenderer->getDevice();
    100 
    101    if (device == nullptr)
    102    {
    103        return EGL_BAD_ACCESS;
    104    }
    105 
    106    // Evict all non-render target textures to system memory and release all resources
    107    // before reallocating them to free up as much video memory as possible.
    108    device->EvictManagedResources();
    109 
    110    HRESULT result;
    111 
    112    // Release specific resources to free up memory for the new render target, while the
    113    // old render target still exists for the purpose of preserving its contents.
    114    SafeRelease(mSwapChain);
    115    SafeRelease(mBackBuffer);
    116    SafeRelease(mOffscreenTexture);
    117    SafeRelease(mDepthStencil);
    118 
    119    const d3d9::TextureFormat &backBufferd3dFormatInfo =
    120        d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat);
    121    if (mD3DTexture != nullptr)
    122    {
    123        result = mD3DTexture->QueryInterface(&mOffscreenTexture);
    124        ASSERT(SUCCEEDED(result));
    125    }
    126    else
    127    {
    128        HANDLE *pShareHandle = nullptr;
    129        if (!mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport())
    130        {
    131            pShareHandle = &mShareHandle;
    132        }
    133 
    134        result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
    135                                       backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT,
    136                                       &mOffscreenTexture, pShareHandle);
    137        if (FAILED(result))
    138        {
    139            ERR() << "Could not create offscreen texture, " << gl::FmtHR(result);
    140            release();
    141 
    142            if (d3d9::isDeviceLostError(result))
    143            {
    144                return EGL_CONTEXT_LOST;
    145            }
    146            else
    147            {
    148                return EGL_BAD_ALLOC;
    149            }
    150        }
    151    }
    152 
    153    IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
    154 
    155    result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
    156    ASSERT(SUCCEEDED(result));
    157 
    158    if (oldRenderTarget)
    159    {
    160        RECT rect = {0, 0, mWidth, mHeight};
    161 
    162        if (rect.right > static_cast<LONG>(backbufferWidth))
    163        {
    164            rect.right = backbufferWidth;
    165        }
    166 
    167        if (rect.bottom > static_cast<LONG>(backbufferHeight))
    168        {
    169            rect.bottom = backbufferHeight;
    170        }
    171 
    172        mRenderer->endScene();
    173 
    174        result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
    175        ASSERT(SUCCEEDED(result));
    176 
    177        SafeRelease(oldRenderTarget);
    178    }
    179 
    180    const d3d9::TextureFormat &depthBufferd3dFormatInfo =
    181        d3d9::GetTextureFormatInfo(mDepthBufferFormat);
    182 
    183    // Don't create a swapchain for NULLREF devices
    184    D3DDEVTYPE deviceType      = mRenderer->getD3D9DeviceType();
    185    EGLNativeWindowType window = mNativeWindow->getNativeWindow();
    186    if (window && deviceType != D3DDEVTYPE_NULLREF)
    187    {
    188        D3DPRESENT_PARAMETERS presentParameters  = {};
    189        presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat;
    190        presentParameters.BackBufferCount        = 1;
    191        presentParameters.BackBufferFormat       = backBufferd3dFormatInfo.renderFormat;
    192        presentParameters.EnableAutoDepthStencil = FALSE;
    193        presentParameters.Flags                  = 0;
    194        presentParameters.hDeviceWindow          = window;
    195        presentParameters.MultiSampleQuality     = 0;                    // FIXME: Unimplemented
    196        presentParameters.MultiSampleType        = D3DMULTISAMPLE_NONE;  // FIXME: Unimplemented
    197        presentParameters.PresentationInterval   = convertInterval(swapInterval);
    198        presentParameters.SwapEffect             = D3DSWAPEFFECT_DISCARD;
    199        presentParameters.Windowed               = TRUE;
    200        presentParameters.BackBufferWidth        = backbufferWidth;
    201        presentParameters.BackBufferHeight       = backbufferHeight;
    202 
    203        // http://crbug.com/140239
    204        // http://crbug.com/143434
    205        //
    206        // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a
    207        // multiple of 64 pixels in width when using the integrated Intel. This rounds the width up
    208        // rather than down.
    209        //
    210        // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present.
    211        // Therefore, when the vendor ID is not Intel, the back buffer width must be exactly the
    212        // same width as the window or horizontal scaling will occur.
    213        if (IsIntel(mRenderer->getVendorId()))
    214        {
    215            presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
    216        }
    217 
    218        result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
    219 
    220        if (FAILED(result))
    221        {
    222            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY ||
    223                   result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
    224 
    225            ERR() << "Could not create additional swap chains or offscreen surfaces, "
    226                  << gl::FmtHR(result);
    227            release();
    228 
    229            if (d3d9::isDeviceLostError(result))
    230            {
    231                return EGL_CONTEXT_LOST;
    232            }
    233            else
    234            {
    235                return EGL_BAD_ALLOC;
    236            }
    237        }
    238 
    239        result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
    240        ASSERT(SUCCEEDED(result));
    241        InvalidateRect(window, nullptr, FALSE);
    242    }
    243 
    244    if (mDepthBufferFormat != GL_NONE)
    245    {
    246        result = device->CreateDepthStencilSurface(
    247            backbufferWidth, backbufferHeight, depthBufferd3dFormatInfo.renderFormat,
    248            D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, nullptr);
    249 
    250        if (FAILED(result))
    251        {
    252            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY ||
    253                   result == D3DERR_INVALIDCALL);
    254 
    255            ERR() << "Could not create depthstencil surface for new swap chain, "
    256                  << gl::FmtHR(result);
    257            release();
    258 
    259            if (d3d9::isDeviceLostError(result))
    260            {
    261                return EGL_CONTEXT_LOST;
    262            }
    263            else
    264            {
    265                return EGL_BAD_ALLOC;
    266            }
    267        }
    268    }
    269 
    270    mWidth        = backbufferWidth;
    271    mHeight       = backbufferHeight;
    272    mSwapInterval = swapInterval;
    273 
    274    return EGL_SUCCESS;
    275 }
    276 
    277 // parameters should be validated/clamped by caller
    278 EGLint SwapChain9::swapRect(DisplayD3D *displayD3D, EGLint x, EGLint y, EGLint width, EGLint height)
    279 {
    280    if (!mSwapChain)
    281    {
    282        return EGL_SUCCESS;
    283    }
    284 
    285    IDirect3DDevice9 *device = mRenderer->getDevice();
    286 
    287    // Disable all pipeline operations
    288    device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    289    device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
    290    device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
    291    device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    292    device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    293    device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    294    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
    295    device->SetRenderState(D3DRS_COLORWRITEENABLE,
    296                           D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE |
    297                               D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
    298    device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
    299    device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    300    device->SetPixelShader(nullptr);
    301    device->SetVertexShader(nullptr);
    302 
    303    device->SetRenderTarget(0, mBackBuffer);
    304    device->SetDepthStencilSurface(nullptr);
    305 
    306    device->SetTexture(0, mOffscreenTexture);
    307    device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
    308    device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    309    device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
    310    device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
    311    device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
    312    device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
    313    device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
    314    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
    315 
    316    for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++)
    317    {
    318        device->SetStreamSourceFreq(streamIndex, 1);
    319    }
    320 
    321    D3DVIEWPORT9 viewport = {0,    0,   static_cast<DWORD>(mWidth), static_cast<DWORD>(mHeight),
    322                             0.0f, 1.0f};
    323    device->SetViewport(&viewport);
    324 
    325    float x1 = x - 0.5f;
    326    float y1 = (mHeight - y - height) - 0.5f;
    327    float x2 = (x + width) - 0.5f;
    328    float y2 = (mHeight - y) - 0.5f;
    329 
    330    float u1 = x / float(mWidth);
    331    float v1 = y / float(mHeight);
    332    float u2 = (x + width) / float(mWidth);
    333    float v2 = (y + height) / float(mHeight);
    334 
    335    float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
    336                        {x2, y1, 0.0f, 1.0f, u2, v2},
    337                        {x2, y2, 0.0f, 1.0f, u2, v1},
    338                        {x1, y2, 0.0f, 1.0f, u1, v1}};  // x, y, z, rhw, u, v
    339 
    340    mRenderer->startScene();
    341    device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
    342    mRenderer->endScene();
    343 
    344    device->SetTexture(0, nullptr);
    345 
    346    RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
    347                 static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
    348 
    349    HRESULT result = mSwapChain->Present(&rect, &rect, nullptr, nullptr, 0);
    350 
    351    mRenderer->markAllStateDirty();
    352 
    353    if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY ||
    354        result == D3DERR_DRIVERINTERNALERROR)
    355    {
    356        return EGL_BAD_ALLOC;
    357    }
    358 
    359    // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the
    360    // windows is in the process of entering/exiting fullscreen. This code doesn't seem to have any
    361    // documentation.  The device appears to be ok after emitting this error so simply return a
    362    // failure to swap.
    363    if (result == static_cast<HRESULT>(0x88760873) || result == static_cast<HRESULT>(0x88760872))
    364    {
    365        return EGL_BAD_MATCH;
    366    }
    367 
    368    // http://crbug.com/313210
    369    // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific
    370    // device removed bug with lost contexts when reinstalling drivers.
    371    if (FAILED(result))
    372    {
    373        mRenderer->notifyDeviceLost();
    374        return EGL_CONTEXT_LOST;
    375    }
    376 
    377    return EGL_SUCCESS;
    378 }
    379 
    380 // Increments refcount on surface.
    381 // caller must Release() the returned surface
    382 // TODO: remove the AddRef to match SwapChain11
    383 IDirect3DSurface9 *SwapChain9::getRenderTarget()
    384 {
    385    if (mRenderTarget)
    386    {
    387        mRenderTarget->AddRef();
    388    }
    389 
    390    return mRenderTarget;
    391 }
    392 
    393 // Increments refcount on surface.
    394 // caller must Release() the returned surface
    395 // TODO: remove the AddRef to match SwapChain11
    396 IDirect3DSurface9 *SwapChain9::getDepthStencil()
    397 {
    398    if (mDepthStencil)
    399    {
    400        mDepthStencil->AddRef();
    401    }
    402 
    403    return mDepthStencil;
    404 }
    405 
    406 // Increments refcount on texture.
    407 // caller must Release() the returned texture
    408 // TODO: remove the AddRef to match SwapChain11
    409 IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
    410 {
    411    if (mOffscreenTexture)
    412    {
    413        mOffscreenTexture->AddRef();
    414    }
    415 
    416    return mOffscreenTexture;
    417 }
    418 
    419 void *SwapChain9::getKeyedMutex()
    420 {
    421    UNREACHABLE();
    422    return nullptr;
    423 }
    424 
    425 egl::Error SwapChain9::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
    426 {
    427    UNREACHABLE();
    428    return egl::EglBadSurface();
    429 }
    430 
    431 void SwapChain9::recreate()
    432 {
    433    if (!mSwapChain)
    434    {
    435        return;
    436    }
    437 
    438    IDirect3DDevice9 *device = mRenderer->getDevice();
    439    if (device == nullptr)
    440    {
    441        return;
    442    }
    443 
    444    D3DPRESENT_PARAMETERS presentParameters;
    445    HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
    446    ASSERT(SUCCEEDED(result));
    447 
    448    IDirect3DSwapChain9 *newSwapChain = nullptr;
    449    result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
    450    if (FAILED(result))
    451    {
    452        return;
    453    }
    454 
    455    SafeRelease(mSwapChain);
    456    mSwapChain = newSwapChain;
    457 
    458    SafeRelease(mBackBuffer);
    459    result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
    460    ASSERT(SUCCEEDED(result));
    461 }
    462 
    463 RenderTargetD3D *SwapChain9::getColorRenderTarget()
    464 {
    465    return &mColorRenderTarget;
    466 }
    467 
    468 RenderTargetD3D *SwapChain9::getDepthStencilRenderTarget()
    469 {
    470    return &mDepthStencilRenderTarget;
    471 }
    472 }  // namespace rx