tor-browser

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

SwapChain11.cpp (40858B)


      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 // SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain.
      8 
      9 #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
     10 
     11 #include <EGL/eglext.h>
     12 
     13 #include "libANGLE/features.h"
     14 #include "libANGLE/renderer/d3d/DisplayD3D.h"
     15 #include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h"
     16 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
     17 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
     18 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
     19 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
     20 #include "libANGLE/trace.h"
     21 
     22 // Precompiled shaders
     23 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h"
     24 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h"
     25 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h"
     26 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvecolor2dps.h"
     27 
     28 #ifdef ANGLE_ENABLE_KEYEDMUTEX
     29 #    define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
     30 #else
     31 #    define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED
     32 #endif
     33 
     34 namespace rx
     35 {
     36 
     37 namespace
     38 {
     39 // To avoid overflow in QPC to Microseconds calculations, since we multiply
     40 // by kMicrosecondsPerSecond, then the QPC value should not exceed
     41 // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
     42 static constexpr int64_t kQPCOverflowThreshold  = 0x8637BD05AF7;
     43 static constexpr int64_t kMicrosecondsPerSecond = 1000000;
     44 
     45 bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow11 *nativeWindow, EGLint orientation)
     46 {
     47    // We don't need an offscreen texture if either orientation = INVERT_Y,
     48    // or present path fast is enabled and we're not rendering onto an offscreen surface.
     49    return orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE &&
     50           !(renderer->presentPathFastEnabled() && nativeWindow->getNativeWindow());
     51 }
     52 }  // anonymous namespace
     53 
     54 SwapChain11::SwapChain11(Renderer11 *renderer,
     55                         NativeWindow11 *nativeWindow,
     56                         HANDLE shareHandle,
     57                         IUnknown *d3dTexture,
     58                         GLenum backBufferFormat,
     59                         GLenum depthBufferFormat,
     60                         EGLint orientation,
     61                         EGLint samples)
     62    : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat),
     63      mRenderer(renderer),
     64      mWidth(-1),
     65      mHeight(-1),
     66      mOrientation(orientation),
     67      mAppCreatedShareHandle(mShareHandle != nullptr),
     68      mSwapInterval(0),
     69      mPassThroughResourcesInit(false),
     70      mNativeWindow(nativeWindow),
     71      mFirstSwap(true),
     72      mSwapChain(nullptr),
     73      mSwapChain1(nullptr),
     74      mKeyedMutex(nullptr),
     75      mBackBufferTexture(),
     76      mBackBufferRTView(),
     77      mBackBufferSRView(),
     78      mNeedsOffscreenTexture(NeedsOffscreenTexture(renderer, nativeWindow, orientation)),
     79      mOffscreenTexture(),
     80      mOffscreenRTView(),
     81      mOffscreenSRView(),
     82      mNeedsOffscreenTextureCopy(false),
     83      mOffscreenTextureCopyForSRV(),
     84      mDepthStencilTexture(),
     85      mDepthStencilDSView(),
     86      mDepthStencilSRView(),
     87      mQuadVB(),
     88      mPassThroughSampler(),
     89      mPassThroughIL(),
     90      mPassThroughVS(),
     91      mPassThroughOrResolvePS(),
     92      mPassThroughRS(),
     93      mColorRenderTarget(this, renderer, false),
     94      mDepthStencilRenderTarget(this, renderer, true),
     95      mEGLSamples(samples)
     96 {
     97    // Check that if present path fast is active then we're using the default orientation
     98    ASSERT(!mRenderer->presentPathFastEnabled() || orientation == 0);
     99 
    100    // Get the performance counter
    101    LARGE_INTEGER counterFreqency = {};
    102    BOOL success                  = QueryPerformanceFrequency(&counterFreqency);
    103    ASSERT(success);
    104 
    105    mQPCFrequency = counterFreqency.QuadPart;
    106 }
    107 
    108 SwapChain11::~SwapChain11()
    109 {
    110    release();
    111 }
    112 
    113 void SwapChain11::release()
    114 {
    115    // TODO(jmadill): Should probably signal that the RenderTarget is dirty.
    116 
    117    SafeRelease(mSwapChain1);
    118    SafeRelease(mSwapChain);
    119    SafeRelease(mKeyedMutex);
    120    mBackBufferTexture.reset();
    121    mBackBufferRTView.reset();
    122    mBackBufferSRView.reset();
    123    mOffscreenTexture.reset();
    124    mOffscreenRTView.reset();
    125    mOffscreenSRView.reset();
    126    mDepthStencilTexture.reset();
    127    mDepthStencilDSView.reset();
    128    mDepthStencilSRView.reset();
    129    mQuadVB.reset();
    130    mPassThroughSampler.reset();
    131    mPassThroughIL.reset();
    132    mPassThroughVS.reset();
    133    mPassThroughOrResolvePS.reset();
    134    mPassThroughRS.reset();
    135 
    136    if (!mAppCreatedShareHandle)
    137    {
    138        mShareHandle = nullptr;
    139    }
    140 }
    141 
    142 void SwapChain11::releaseOffscreenColorBuffer()
    143 {
    144    mOffscreenTexture.reset();
    145    mOffscreenRTView.reset();
    146    mOffscreenSRView.reset();
    147    mNeedsOffscreenTextureCopy = false;
    148    mOffscreenTextureCopyForSRV.reset();
    149 }
    150 
    151 void SwapChain11::releaseOffscreenDepthBuffer()
    152 {
    153    mDepthStencilTexture.reset();
    154    mDepthStencilDSView.reset();
    155    mDepthStencilSRView.reset();
    156 }
    157 
    158 EGLint SwapChain11::resetOffscreenBuffers(DisplayD3D *displayD3D,
    159                                          int backbufferWidth,
    160                                          int backbufferHeight)
    161 {
    162    if (mNeedsOffscreenTexture)
    163    {
    164        EGLint result = resetOffscreenColorBuffer(displayD3D, backbufferWidth, backbufferHeight);
    165        if (result != EGL_SUCCESS)
    166        {
    167            return result;
    168        }
    169    }
    170 
    171    EGLint result = resetOffscreenDepthBuffer(displayD3D, backbufferWidth, backbufferHeight);
    172    if (result != EGL_SUCCESS)
    173    {
    174        return result;
    175    }
    176 
    177    mWidth  = backbufferWidth;
    178    mHeight = backbufferHeight;
    179 
    180    return EGL_SUCCESS;
    181 }
    182 
    183 EGLint SwapChain11::resetOffscreenColorBuffer(DisplayD3D *displayD3D,
    184                                              int backbufferWidth,
    185                                              int backbufferHeight)
    186 {
    187    ASSERT(mNeedsOffscreenTexture);
    188 
    189    ANGLE_TRACE_EVENT0("gpu.angle", "SwapChain11::resetOffscreenTexture");
    190    ID3D11Device *device = mRenderer->getDevice();
    191 
    192    ASSERT(device != nullptr);
    193 
    194    // D3D11 does not allow zero size textures
    195    ASSERT(backbufferWidth >= 1);
    196    ASSERT(backbufferHeight >= 1);
    197 
    198    // Preserve the render target content
    199    TextureHelper11 previousOffscreenTexture(std::move(mOffscreenTexture));
    200    const int previousWidth  = mWidth;
    201    const int previousHeight = mHeight;
    202 
    203    releaseOffscreenColorBuffer();
    204 
    205    const d3d11::Format &backbufferFormatInfo =
    206        d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
    207    D3D11_TEXTURE2D_DESC offscreenTextureDesc = {};
    208 
    209    // If the app passed in a share handle or D3D texture, open the resource
    210    // See EGL_ANGLE_d3d_share_handle_client_buffer and EGL_ANGLE_d3d_texture_client_buffer
    211    if (mAppCreatedShareHandle || mD3DTexture != nullptr)
    212    {
    213        if (mAppCreatedShareHandle)
    214        {
    215            ID3D11Resource *tempResource11;
    216            HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource),
    217                                                        (void **)&tempResource11);
    218            if (FAILED(result) && mRenderer->getDevice1())
    219            {
    220                result = mRenderer->getDevice1()->OpenSharedResource1(
    221                    mShareHandle, __uuidof(ID3D11Resource), (void **)&tempResource11);
    222            }
    223 
    224            if (FAILED(result))
    225            {
    226                ERR() << "Could not open shared handle. " << gl::FmtHR(result);
    227                release();
    228                return EGL_BAD_SURFACE;
    229            }
    230 
    231            mOffscreenTexture.set(d3d11::DynamicCastComObject<ID3D11Texture2D>(tempResource11),
    232                                  backbufferFormatInfo);
    233            SafeRelease(tempResource11);
    234        }
    235        else if (mD3DTexture != nullptr)
    236        {
    237            mOffscreenTexture.set(d3d11::DynamicCastComObject<ID3D11Texture2D>(mD3DTexture),
    238                                  backbufferFormatInfo);
    239        }
    240        else
    241        {
    242            UNREACHABLE();
    243        }
    244        ASSERT(mOffscreenTexture.valid());
    245        mOffscreenTexture.getDesc(&offscreenTextureDesc);
    246 
    247        // Fail if the offscreen texture is not renderable.
    248        if ((offscreenTextureDesc.BindFlags & D3D11_BIND_RENDER_TARGET) == 0)
    249        {
    250            ERR() << "Could not use provided offscreen texture, texture not renderable.";
    251            release();
    252            return EGL_BAD_SURFACE;
    253        }
    254    }
    255    else
    256    {
    257        const bool useSharedResource =
    258            !mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport();
    259 
    260        offscreenTextureDesc.Width              = backbufferWidth;
    261        offscreenTextureDesc.Height             = backbufferHeight;
    262        offscreenTextureDesc.Format             = backbufferFormatInfo.texFormat;
    263        offscreenTextureDesc.MipLevels          = 1;
    264        offscreenTextureDesc.ArraySize          = 1;
    265        offscreenTextureDesc.SampleDesc.Count   = getD3DSamples();
    266        offscreenTextureDesc.SampleDesc.Quality = 0;
    267        offscreenTextureDesc.Usage              = D3D11_USAGE_DEFAULT;
    268        offscreenTextureDesc.BindFlags      = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    269        offscreenTextureDesc.CPUAccessFlags = 0;
    270        offscreenTextureDesc.MiscFlags      = useSharedResource ? ANGLE_RESOURCE_SHARE_TYPE : 0;
    271 
    272        angle::Result result = mRenderer->allocateTexture(displayD3D, offscreenTextureDesc,
    273                                                          backbufferFormatInfo, &mOffscreenTexture);
    274        if (result == angle::Result::Stop)
    275        {
    276            ERR() << "Could not create offscreen texture, " << displayD3D->getStoredErrorString();
    277            release();
    278            return EGL_BAD_ALLOC;
    279        }
    280 
    281        mOffscreenTexture.setInternalName("OffscreenBackBufferTexture");
    282 
    283        // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for
    284        // the client
    285        if (useSharedResource)
    286        {
    287            IDXGIResource *offscreenTextureResource = nullptr;
    288            HRESULT hr                              = mOffscreenTexture.get()->QueryInterface(
    289                                             __uuidof(IDXGIResource), (void **)&offscreenTextureResource);
    290 
    291            // Fall back to no share handle on failure
    292            if (FAILED(hr))
    293            {
    294                ERR() << "Could not query offscreen texture resource, " << gl::FmtHR(hr);
    295            }
    296            else
    297            {
    298                hr = offscreenTextureResource->GetSharedHandle(&mShareHandle);
    299                SafeRelease(offscreenTextureResource);
    300 
    301                if (FAILED(hr))
    302                {
    303                    mShareHandle = nullptr;
    304                    ERR() << "Could not get offscreen texture shared handle, " << gl::FmtHR(hr);
    305                }
    306            }
    307        }
    308    }
    309 
    310    // This may return null if the original texture was created without a keyed mutex.
    311    mKeyedMutex = d3d11::DynamicCastComObject<IDXGIKeyedMutex>(mOffscreenTexture.get());
    312 
    313    D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
    314    offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat;
    315    offscreenRTVDesc.ViewDimension =
    316        (mEGLSamples <= 1) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS;
    317    offscreenRTVDesc.Texture2D.MipSlice = 0;
    318 
    319    angle::Result result = mRenderer->allocateResource(displayD3D, offscreenRTVDesc,
    320                                                       mOffscreenTexture.get(), &mOffscreenRTView);
    321    if (result == angle::Result::Stop)
    322    {
    323        ERR() << "Could not create offscreen back buffer render target, "
    324              << displayD3D->getStoredErrorString();
    325        release();
    326        return EGL_BAD_ALLOC;
    327    }
    328    mOffscreenRTView.setInternalName("OffscreenBackBufferRenderTarget");
    329 
    330    D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc;
    331    offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat;
    332    offscreenSRVDesc.ViewDimension =
    333        (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS;
    334    offscreenSRVDesc.Texture2D.MostDetailedMip = 0;
    335    offscreenSRVDesc.Texture2D.MipLevels       = static_cast<UINT>(-1);
    336 
    337    if (offscreenTextureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
    338    {
    339        result = mRenderer->allocateResource(displayD3D, offscreenSRVDesc, mOffscreenTexture.get(),
    340                                             &mOffscreenSRView);
    341        if (result == angle::Result::Stop)
    342        {
    343            ERR() << "Could not create offscreen back buffer shader resource, "
    344                  << displayD3D->getStoredErrorString();
    345            release();
    346            return EGL_BAD_ALLOC;
    347        }
    348        mOffscreenSRView.setInternalName("OffscreenBackBufferShaderResource");
    349    }
    350    else
    351    {
    352        // Special case for external textures that cannot support sampling. Since internally we
    353        // assume our SwapChain is always readable, we make a copy texture that is compatible.
    354        mNeedsOffscreenTextureCopy = true;
    355    }
    356 
    357    if (previousOffscreenTexture.valid())
    358    {
    359        D3D11_BOX sourceBox = {};
    360        sourceBox.left      = 0;
    361        sourceBox.right     = std::min(previousWidth, backbufferWidth);
    362        sourceBox.top       = std::max(previousHeight - backbufferHeight, 0);
    363        sourceBox.bottom    = previousHeight;
    364        sourceBox.front     = 0;
    365        sourceBox.back      = 1;
    366 
    367        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    368        const int yoffset                  = std::max(backbufferHeight - previousHeight, 0);
    369        deviceContext->CopySubresourceRegion(mOffscreenTexture.get(), 0, 0, yoffset, 0,
    370                                             previousOffscreenTexture.get(), 0, &sourceBox);
    371 
    372        if (mSwapChain)
    373        {
    374            swapRect(displayD3D, 0, 0, backbufferWidth, backbufferHeight);
    375        }
    376    }
    377 
    378    return EGL_SUCCESS;
    379 }
    380 
    381 EGLint SwapChain11::resetOffscreenDepthBuffer(DisplayD3D *displayD3D,
    382                                              int backbufferWidth,
    383                                              int backbufferHeight)
    384 {
    385    releaseOffscreenDepthBuffer();
    386 
    387    if (mDepthBufferFormat != GL_NONE)
    388    {
    389        const d3d11::Format &depthBufferFormatInfo =
    390            d3d11::Format::Get(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps());
    391 
    392        D3D11_TEXTURE2D_DESC depthStencilTextureDesc;
    393        depthStencilTextureDesc.Width            = backbufferWidth;
    394        depthStencilTextureDesc.Height           = backbufferHeight;
    395        depthStencilTextureDesc.Format           = depthBufferFormatInfo.texFormat;
    396        depthStencilTextureDesc.MipLevels        = 1;
    397        depthStencilTextureDesc.ArraySize        = 1;
    398        depthStencilTextureDesc.SampleDesc.Count = getD3DSamples();
    399        depthStencilTextureDesc.Usage            = D3D11_USAGE_DEFAULT;
    400        depthStencilTextureDesc.BindFlags        = D3D11_BIND_DEPTH_STENCIL;
    401 
    402        // If there is a multisampled offscreen color texture, the offscreen depth-stencil texture
    403        // must also have the same quality value.
    404        if (mOffscreenTexture.valid() && getD3DSamples() > 1)
    405        {
    406            D3D11_TEXTURE2D_DESC offscreenTextureDesc = {};
    407            mOffscreenTexture.getDesc(&offscreenTextureDesc);
    408            depthStencilTextureDesc.SampleDesc.Quality = offscreenTextureDesc.SampleDesc.Quality;
    409        }
    410        else
    411        {
    412            depthStencilTextureDesc.SampleDesc.Quality = 0;
    413        }
    414 
    415        // Only create an SRV if it is supported
    416        bool depthStencilSRV =
    417            depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN &&
    418            (mRenderer->getRenderer11DeviceCaps().supportsMultisampledDepthStencilSRVs ||
    419             depthStencilTextureDesc.SampleDesc.Count <= 1);
    420        if (depthStencilSRV)
    421        {
    422            depthStencilTextureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
    423        }
    424 
    425        depthStencilTextureDesc.CPUAccessFlags = 0;
    426        depthStencilTextureDesc.MiscFlags      = 0;
    427 
    428        angle::Result result = mRenderer->allocateTexture(
    429            displayD3D, depthStencilTextureDesc, depthBufferFormatInfo, &mDepthStencilTexture);
    430        if (result == angle::Result::Stop)
    431        {
    432            ERR() << "Could not create depthstencil surface for new swap chain, "
    433                  << displayD3D->getStoredErrorString();
    434            release();
    435            return EGL_BAD_ALLOC;
    436        }
    437        mDepthStencilTexture.setInternalName("OffscreenDepthStencilTexture");
    438 
    439        D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc;
    440        depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat;
    441        depthStencilDesc.ViewDimension =
    442            (mEGLSamples <= 1) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS;
    443        depthStencilDesc.Flags              = 0;
    444        depthStencilDesc.Texture2D.MipSlice = 0;
    445 
    446        result = mRenderer->allocateResource(displayD3D, depthStencilDesc,
    447                                             mDepthStencilTexture.get(), &mDepthStencilDSView);
    448        ASSERT(result != angle::Result::Stop);
    449        mDepthStencilDSView.setInternalName("OffscreenDSV");
    450 
    451        if (depthStencilSRV)
    452        {
    453            D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc;
    454            depthStencilSRVDesc.Format                    = depthBufferFormatInfo.srvFormat;
    455            depthStencilSRVDesc.ViewDimension             = (mEGLSamples <= 1)
    456                                                                ? D3D11_SRV_DIMENSION_TEXTURE2D
    457                                                                : D3D11_SRV_DIMENSION_TEXTURE2DMS;
    458            depthStencilSRVDesc.Texture2D.MostDetailedMip = 0;
    459            depthStencilSRVDesc.Texture2D.MipLevels       = static_cast<UINT>(-1);
    460 
    461            result = mRenderer->allocateResource(displayD3D, depthStencilSRVDesc,
    462                                                 mDepthStencilTexture.get(), &mDepthStencilSRView);
    463            ASSERT(result != angle::Result::Stop);
    464            mDepthStencilSRView.setInternalName("OffscreenDepthStencilSRV");
    465        }
    466    }
    467 
    468    return EGL_SUCCESS;
    469 }
    470 
    471 EGLint SwapChain11::resize(DisplayD3D *displayD3D, EGLint backbufferWidth, EGLint backbufferHeight)
    472 {
    473    ANGLE_TRACE_EVENT0("gpu.angle", "SwapChain11::resize");
    474    ID3D11Device *device = mRenderer->getDevice();
    475 
    476    if (device == nullptr)
    477    {
    478        return EGL_BAD_ACCESS;
    479    }
    480 
    481    // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains
    482    if (backbufferWidth < 1 || backbufferHeight < 1)
    483    {
    484        return EGL_SUCCESS;
    485    }
    486 
    487    // Don't resize unnecessarily
    488    if (mWidth == backbufferWidth && mHeight == backbufferHeight)
    489    {
    490        return EGL_SUCCESS;
    491    }
    492 
    493    // Can only call resize if we have already created our swap buffer and resources
    494    ASSERT(mSwapChain && mBackBufferTexture.valid() && mBackBufferRTView.valid() &&
    495           mBackBufferSRView.valid());
    496 
    497    mBackBufferTexture.reset();
    498    mBackBufferRTView.reset();
    499    mBackBufferSRView.reset();
    500 
    501    // Resize swap chain
    502    DXGI_SWAP_CHAIN_DESC desc;
    503    HRESULT hr = mSwapChain->GetDesc(&desc);
    504    if (FAILED(hr))
    505    {
    506        ERR() << "Error reading swap chain description, " << gl::FmtHR(hr);
    507        release();
    508        return EGL_BAD_ALLOC;
    509    }
    510 
    511    hr = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight,
    512                                   getSwapChainNativeFormat(), 0);
    513 
    514    if (FAILED(hr))
    515    {
    516        ERR() << "Error resizing swap chain buffers, " << gl::FmtHR(hr);
    517        release();
    518 
    519        if (d3d11::isDeviceLostError(hr))
    520        {
    521            HRESULT reason = device->GetDeviceRemovedReason();
    522            ERR() << "Device lost in SwapChain11::resize " << gl::FmtHR(hr)
    523                  << ", reason: " << gl::FmtHR(reason);
    524            return EGL_CONTEXT_LOST;
    525        }
    526        else
    527        {
    528            return EGL_BAD_ALLOC;
    529        }
    530    }
    531 
    532    ID3D11Texture2D *backbufferTexture = nullptr;
    533    hr                                 = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
    534                                                               reinterpret_cast<void **>(&backbufferTexture));
    535    ASSERT(SUCCEEDED(hr));
    536    if (SUCCEEDED(hr))
    537    {
    538        const auto &format =
    539            d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
    540        mBackBufferTexture.set(backbufferTexture, format);
    541        mBackBufferTexture.setInternalName("BackBufferTexture");
    542 
    543        angle::Result result = mRenderer->allocateResourceNoDesc(
    544            displayD3D, mBackBufferTexture.get(), &mBackBufferRTView);
    545        ASSERT(result != angle::Result::Stop);
    546        mBackBufferRTView.setInternalName("BackBufferRTV");
    547 
    548        result = mRenderer->allocateResourceNoDesc(displayD3D, mBackBufferTexture.get(),
    549                                                   &mBackBufferSRView);
    550        ASSERT(result != angle::Result::Stop);
    551        mBackBufferSRView.setInternalName("BackBufferSRV");
    552    }
    553 
    554    mFirstSwap = true;
    555 
    556    return resetOffscreenBuffers(displayD3D, backbufferWidth, backbufferHeight);
    557 }
    558 
    559 DXGI_FORMAT SwapChain11::getSwapChainNativeFormat() const
    560 {
    561    // Return a render target format for offscreen rendering is supported by IDXGISwapChain.
    562    // MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064(v=vs.85).aspx
    563    switch (mOffscreenRenderTargetFormat)
    564    {
    565        case GL_RGBA8:
    566        case GL_RGBA4:
    567        case GL_RGB5_A1:
    568        case GL_RGB8:
    569        case GL_RGB565:
    570            return DXGI_FORMAT_R8G8B8A8_UNORM;
    571 
    572        case GL_BGRA8_EXT:
    573            return DXGI_FORMAT_B8G8R8A8_UNORM;
    574 
    575        case GL_RGB10_A2:
    576            return DXGI_FORMAT_R10G10B10A2_UNORM;
    577 
    578        case GL_RGBA16F:
    579            return DXGI_FORMAT_R16G16B16A16_FLOAT;
    580 
    581        default:
    582            UNREACHABLE();
    583            return DXGI_FORMAT_UNKNOWN;
    584    }
    585 }
    586 
    587 EGLint SwapChain11::reset(DisplayD3D *displayD3D,
    588                          EGLint backbufferWidth,
    589                          EGLint backbufferHeight,
    590                          EGLint swapInterval)
    591 {
    592    mSwapInterval = static_cast<unsigned int>(swapInterval);
    593    if (mSwapInterval > 4)
    594    {
    595        // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4]
    596        // range
    597        return EGL_BAD_PARAMETER;
    598    }
    599 
    600    // If the swap chain already exists, just resize
    601    if (mSwapChain != nullptr)
    602    {
    603        return resize(displayD3D, backbufferWidth, backbufferHeight);
    604    }
    605 
    606    ANGLE_TRACE_EVENT0("gpu.angle", "SwapChain11::reset");
    607    ID3D11Device *device = mRenderer->getDevice();
    608 
    609    if (device == nullptr)
    610    {
    611        return EGL_BAD_ACCESS;
    612    }
    613 
    614    // Release specific resources to free up memory for the new render target, while the
    615    // old render target still exists for the purpose of preserving its contents.
    616    SafeRelease(mSwapChain1);
    617    SafeRelease(mSwapChain);
    618    mBackBufferTexture.reset();
    619    mBackBufferRTView.reset();
    620 
    621    // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains
    622    if (backbufferWidth < 1 || backbufferHeight < 1)
    623    {
    624        releaseOffscreenColorBuffer();
    625        return EGL_SUCCESS;
    626    }
    627 
    628    if (mNativeWindow->getNativeWindow())
    629    {
    630        HRESULT hr = mNativeWindow->createSwapChain(
    631            device, mRenderer->getDxgiFactory(), getSwapChainNativeFormat(), backbufferWidth,
    632            backbufferHeight, mNeedsOffscreenTexture ? 1 : getD3DSamples(), &mSwapChain);
    633 
    634        if (FAILED(hr))
    635        {
    636            ERR() << "Could not create additional swap chains or offscreen surfaces, "
    637                  << gl::FmtHR(hr);
    638            release();
    639 
    640            if (d3d11::isDeviceLostError(hr))
    641            {
    642                HRESULT reason = device->GetDeviceRemovedReason();
    643                ERR() << "Device lost in SwapChain11::reset " << gl::FmtHR(hr)
    644                      << ", reason: " << gl::FmtHR(reason);
    645                return EGL_CONTEXT_LOST;
    646            }
    647            else
    648            {
    649                return EGL_BAD_ALLOC;
    650            }
    651        }
    652 
    653        if (mRenderer->getRenderer11DeviceCaps().supportsDXGI1_2)
    654        {
    655            mSwapChain1 = d3d11::DynamicCastComObject<IDXGISwapChain1>(mSwapChain);
    656        }
    657 
    658        ID3D11Texture2D *backbufferTex = nullptr;
    659        hr                             = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
    660                                                               reinterpret_cast<LPVOID *>(&backbufferTex));
    661        ASSERT(SUCCEEDED(hr));
    662        const auto &format =
    663            d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
    664        mBackBufferTexture.set(backbufferTex, format);
    665        mBackBufferTexture.setInternalName("BackBufferTexture");
    666 
    667        angle::Result result = mRenderer->allocateResourceNoDesc(
    668            displayD3D, mBackBufferTexture.get(), &mBackBufferRTView);
    669        ASSERT(result != angle::Result::Stop);
    670        mBackBufferRTView.setInternalName("BackBufferRTV");
    671 
    672        result = mRenderer->allocateResourceNoDesc(displayD3D, mBackBufferTexture.get(),
    673                                                   &mBackBufferSRView);
    674        ASSERT(result != angle::Result::Stop);
    675        mBackBufferSRView.setInternalName("BackBufferSRV");
    676    }
    677 
    678    mFirstSwap = true;
    679 
    680    return resetOffscreenBuffers(displayD3D, backbufferWidth, backbufferHeight);
    681 }
    682 
    683 angle::Result SwapChain11::initPassThroughResources(DisplayD3D *displayD3D)
    684 {
    685    if (mPassThroughResourcesInit)
    686    {
    687        return angle::Result::Continue;
    688    }
    689 
    690    ANGLE_TRACE_EVENT0("gpu.angle", "SwapChain11::initPassThroughResources");
    691    ID3D11Device *device = mRenderer->getDevice();
    692 
    693    ASSERT(device != nullptr);
    694 
    695    // Make sure our resources are all not allocated, when we create
    696    ASSERT(!mQuadVB.valid() && !mPassThroughSampler.valid());
    697    ASSERT(!mPassThroughIL.valid() && !mPassThroughVS.valid() && !mPassThroughOrResolvePS.valid());
    698 
    699    D3D11_BUFFER_DESC vbDesc;
    700    vbDesc.ByteWidth           = sizeof(d3d11::PositionTexCoordVertex) * 4;
    701    vbDesc.Usage               = D3D11_USAGE_DYNAMIC;
    702    vbDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
    703    vbDesc.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
    704    vbDesc.MiscFlags           = 0;
    705    vbDesc.StructureByteStride = 0;
    706 
    707    ANGLE_TRY(mRenderer->allocateResource(displayD3D, vbDesc, &mQuadVB));
    708    mQuadVB.setInternalName("SwapChainQuadVB");
    709 
    710    D3D11_SAMPLER_DESC samplerDesc;
    711    samplerDesc.Filter         = D3D11_FILTER_MIN_MAG_MIP_POINT;
    712    samplerDesc.AddressU       = D3D11_TEXTURE_ADDRESS_CLAMP;
    713    samplerDesc.AddressV       = D3D11_TEXTURE_ADDRESS_CLAMP;
    714    samplerDesc.AddressW       = D3D11_TEXTURE_ADDRESS_CLAMP;
    715    samplerDesc.MipLODBias     = 0.0f;
    716    samplerDesc.MaxAnisotropy  = 0;
    717    samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    718    samplerDesc.BorderColor[0] = 0.0f;
    719    samplerDesc.BorderColor[1] = 0.0f;
    720    samplerDesc.BorderColor[2] = 0.0f;
    721    samplerDesc.BorderColor[3] = 0.0f;
    722    samplerDesc.MinLOD         = 0;
    723    samplerDesc.MaxLOD         = D3D11_FLOAT32_MAX;
    724 
    725    ANGLE_TRY(mRenderer->allocateResource(displayD3D, samplerDesc, &mPassThroughSampler));
    726    mPassThroughSampler.setInternalName("SwapChainPassThroughSampler");
    727 
    728    D3D11_INPUT_ELEMENT_DESC quadLayout[] = {
    729        {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    730        {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
    731    };
    732 
    733    InputElementArray quadElements(quadLayout);
    734    ShaderData vertexShaderData(g_VS_Passthrough2D);
    735 
    736    ANGLE_TRY(
    737        mRenderer->allocateResource(displayD3D, quadElements, &vertexShaderData, &mPassThroughIL));
    738    mPassThroughIL.setInternalName("SwapChainPassThroughIL");
    739 
    740    ANGLE_TRY(mRenderer->allocateResource(displayD3D, vertexShaderData, &mPassThroughVS));
    741    mPassThroughVS.setInternalName("SwapChainPassThroughVS");
    742 
    743    if (mEGLSamples <= 1)
    744    {
    745        ShaderData pixelShaderData(g_PS_PassthroughRGBA2D);
    746        ANGLE_TRY(
    747            mRenderer->allocateResource(displayD3D, pixelShaderData, &mPassThroughOrResolvePS));
    748    }
    749    else
    750    {
    751        if (mNativeWindow->getNativeWindow() && mNeedsOffscreenTexture)
    752        {
    753            ShaderData pixelShaderData(g_PS_ResolveColor2D);
    754            ANGLE_TRY(
    755                mRenderer->allocateResource(displayD3D, pixelShaderData, &mPassThroughOrResolvePS));
    756        }
    757        else
    758        {
    759            ShaderData pixelShaderData(g_PS_PassthroughRGBA2DMS);
    760            ANGLE_TRY(
    761                mRenderer->allocateResource(displayD3D, pixelShaderData, &mPassThroughOrResolvePS));
    762        }
    763    }
    764 
    765    mPassThroughOrResolvePS.setInternalName("SwapChainPassThroughPS");
    766 
    767    // Use the default rasterizer state but without culling
    768    D3D11_RASTERIZER_DESC rasterizerDesc;
    769    rasterizerDesc.FillMode              = D3D11_FILL_SOLID;
    770    rasterizerDesc.CullMode              = D3D11_CULL_NONE;
    771    rasterizerDesc.FrontCounterClockwise = FALSE;
    772    rasterizerDesc.DepthBias             = 0;
    773    rasterizerDesc.SlopeScaledDepthBias  = 0.0f;
    774    rasterizerDesc.DepthBiasClamp        = 0.0f;
    775    rasterizerDesc.DepthClipEnable       = TRUE;
    776    rasterizerDesc.ScissorEnable         = FALSE;
    777    rasterizerDesc.MultisampleEnable     = FALSE;
    778    rasterizerDesc.AntialiasedLineEnable = FALSE;
    779 
    780    ANGLE_TRY(mRenderer->allocateResource(displayD3D, rasterizerDesc, &mPassThroughRS));
    781    mPassThroughRS.setInternalName("SwapChainPassThroughRasterizerState");
    782 
    783    mPassThroughResourcesInit = true;
    784    return angle::Result::Continue;
    785 }
    786 
    787 // parameters should be validated/clamped by caller
    788 EGLint SwapChain11::swapRect(DisplayD3D *displayD3D,
    789                             EGLint x,
    790                             EGLint y,
    791                             EGLint width,
    792                             EGLint height)
    793 {
    794    if (mNeedsOffscreenTexture)
    795    {
    796        EGLint result = copyOffscreenToBackbuffer(displayD3D, x, y, width, height);
    797        if (result != EGL_SUCCESS)
    798        {
    799            return result;
    800        }
    801    }
    802 
    803    EGLint result = present(displayD3D, x, y, width, height);
    804    if (result != EGL_SUCCESS)
    805    {
    806        return result;
    807    }
    808 
    809    mRenderer->onSwap();
    810 
    811    return EGL_SUCCESS;
    812 }
    813 
    814 EGLint SwapChain11::copyOffscreenToBackbuffer(DisplayD3D *displayD3D,
    815                                              EGLint x,
    816                                              EGLint y,
    817                                              EGLint width,
    818                                              EGLint height)
    819 {
    820    if (!mSwapChain)
    821    {
    822        return EGL_SUCCESS;
    823    }
    824 
    825    if (initPassThroughResources(displayD3D) == angle::Result::Stop)
    826    {
    827        return EGL_BAD_ALLOC;
    828    }
    829 
    830    ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    831 
    832    // Set vertices
    833    D3D11_MAPPED_SUBRESOURCE mappedResource;
    834    HRESULT result =
    835        deviceContext->Map(mQuadVB.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    836    if (FAILED(result))
    837    {
    838        return EGL_BAD_ACCESS;
    839    }
    840 
    841    d3d11::PositionTexCoordVertex *vertices =
    842        static_cast<d3d11::PositionTexCoordVertex *>(mappedResource.pData);
    843 
    844    // Create a quad in homogeneous coordinates
    845    float x1 = (x / float(mWidth)) * 2.0f - 1.0f;
    846    float y1 = (y / float(mHeight)) * 2.0f - 1.0f;
    847    float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f;
    848    float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f;
    849 
    850    float u1 = x / float(mWidth);
    851    float v1 = y / float(mHeight);
    852    float u2 = (x + width) / float(mWidth);
    853    float v2 = (y + height) / float(mHeight);
    854 
    855    // Invert the quad vertices depending on the surface orientation.
    856    if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE) != 0)
    857    {
    858        std::swap(x1, x2);
    859    }
    860    if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE) != 0)
    861    {
    862        std::swap(y1, y2);
    863    }
    864 
    865    d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1);
    866    d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2);
    867    d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1);
    868    d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2);
    869 
    870    deviceContext->Unmap(mQuadVB.get(), 0);
    871 
    872    StateManager11 *stateManager = mRenderer->getStateManager();
    873 
    874    constexpr UINT stride = sizeof(d3d11::PositionTexCoordVertex);
    875    stateManager->setSingleVertexBuffer(&mQuadVB, stride, 0);
    876 
    877    // Apply state
    878    stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF);
    879    stateManager->setSimpleBlendState(nullptr);
    880    stateManager->setRasterizerState(&mPassThroughRS);
    881 
    882    // Apply shaders
    883    stateManager->setInputLayout(&mPassThroughIL);
    884    stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    885    stateManager->setDrawShaders(&mPassThroughVS, nullptr, &mPassThroughOrResolvePS);
    886 
    887    // Apply render targets. Use the proxy context in display.
    888    stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr);
    889 
    890    // Set the viewport
    891    stateManager->setSimpleViewport(mWidth, mHeight);
    892 
    893    // Apply textures
    894    stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler);
    895 
    896    // Draw
    897    deviceContext->Draw(4, 0);
    898 
    899    return EGL_SUCCESS;
    900 }
    901 
    902 EGLint SwapChain11::present(DisplayD3D *displayD3D, EGLint x, EGLint y, EGLint width, EGLint height)
    903 {
    904    if (!mSwapChain)
    905    {
    906        return EGL_SUCCESS;
    907    }
    908 
    909    UINT swapInterval = mSwapInterval;
    910 #if ANGLE_VSYNC == ANGLE_DISABLED
    911    swapInterval = 0;
    912 #endif
    913 
    914    HRESULT result = S_OK;
    915 
    916    // Use IDXGISwapChain1::Present1 with a dirty rect if DXGI 1.2 is available.
    917    // Dirty rect present is not supported with a multisampled swapchain.
    918    if (mSwapChain1 != nullptr && mEGLSamples <= 1)
    919    {
    920        if (mFirstSwap)
    921        {
    922            // Can't swap with a dirty rect if this swap chain has never swapped before
    923            DXGI_PRESENT_PARAMETERS params = {0, nullptr, nullptr, nullptr};
    924            result                         = mSwapChain1->Present1(swapInterval, 0, &params);
    925        }
    926        else
    927        {
    928            RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
    929                         static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
    930            DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr};
    931            result                         = mSwapChain1->Present1(swapInterval, 0, &params);
    932        }
    933    }
    934    else
    935    {
    936        result = mSwapChain->Present(swapInterval, 0);
    937    }
    938 
    939    mFirstSwap = false;
    940 
    941    // Some swapping mechanisms such as DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL unbind the current render
    942    // target. Mark it dirty. Use the proxy context in display since there is none available.
    943    mRenderer->getStateManager()->invalidateRenderTarget();
    944 
    945    if (result == DXGI_ERROR_DEVICE_REMOVED)
    946    {
    947        ERR() << "Present failed: the D3D11 device was removed, "
    948              << gl::FmtHR(mRenderer->getDevice()->GetDeviceRemovedReason());
    949        return EGL_CONTEXT_LOST;
    950    }
    951    else if (result == DXGI_ERROR_DEVICE_RESET)
    952    {
    953        ERR() << "Present failed: the D3D11 device was reset from a bad command.";
    954        return EGL_CONTEXT_LOST;
    955    }
    956    else if (FAILED(result))
    957    {
    958        ERR() << "Present failed with " << gl::FmtHR(result);
    959    }
    960 
    961    mNativeWindow->commitChange();
    962 
    963    return EGL_SUCCESS;
    964 }
    965 
    966 const TextureHelper11 &SwapChain11::getOffscreenTexture()
    967 {
    968    return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture;
    969 }
    970 
    971 const d3d11::RenderTargetView &SwapChain11::getRenderTarget()
    972 {
    973    return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView;
    974 }
    975 
    976 angle::Result SwapChain11::getRenderTargetShaderResource(d3d::Context *context,
    977                                                         const d3d11::SharedSRV **outSRV)
    978 {
    979    *outSRV = nullptr;
    980 
    981    if (!mNeedsOffscreenTexture)
    982    {
    983        ASSERT(mBackBufferSRView.valid());
    984        *outSRV = &mBackBufferSRView;
    985        return angle::Result::Continue;
    986    }
    987 
    988    if (!mNeedsOffscreenTextureCopy)
    989    {
    990        ASSERT(mOffscreenSRView.valid());
    991        *outSRV = &mOffscreenSRView;
    992        return angle::Result::Continue;
    993    }
    994 
    995    if (!mOffscreenTextureCopyForSRV.valid())
    996    {
    997        const d3d11::Format &backbufferFormatInfo =
    998            d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
    999 
   1000        D3D11_TEXTURE2D_DESC offscreenCopyDesc;
   1001        mOffscreenTexture.getDesc(&offscreenCopyDesc);
   1002 
   1003        offscreenCopyDesc.BindFlags      = D3D11_BIND_SHADER_RESOURCE;
   1004        offscreenCopyDesc.MiscFlags      = 0;
   1005        offscreenCopyDesc.CPUAccessFlags = 0;
   1006        TextureHelper11 offscreenTextureCopyForSRV;
   1007        ANGLE_TRY(mRenderer->allocateTexture(context, offscreenCopyDesc, backbufferFormatInfo,
   1008                                             &offscreenTextureCopyForSRV));
   1009        offscreenTextureCopyForSRV.setInternalName("OffscreenBackBufferCopyForSRV");
   1010 
   1011        D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc;
   1012        offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat;
   1013        offscreenSRVDesc.ViewDimension =
   1014            (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS;
   1015        offscreenSRVDesc.Texture2D.MostDetailedMip = 0;
   1016        offscreenSRVDesc.Texture2D.MipLevels       = static_cast<UINT>(-1);
   1017 
   1018        d3d11::SharedSRV offscreenSRView;
   1019        ANGLE_TRY(mRenderer->allocateResource(context, offscreenSRVDesc,
   1020                                              offscreenTextureCopyForSRV.get(), &offscreenSRView));
   1021        offscreenSRView.setInternalName("OffscreenBackBufferSRV");
   1022 
   1023        // Commit created objects in one step so we don't end up with half baked member variables.
   1024        mOffscreenTextureCopyForSRV = std::move(offscreenTextureCopyForSRV);
   1025        mOffscreenSRView            = std::move(offscreenSRView);
   1026    }
   1027 
   1028    // Need to copy the offscreen texture into the shader-readable copy, since it's external and
   1029    // we don't know if the copy is up-to-date. This works around the problem we have when the app
   1030    // passes in a texture that isn't shader-readable.
   1031    mRenderer->getDeviceContext()->CopyResource(mOffscreenTextureCopyForSRV.get(),
   1032                                                mOffscreenTexture.get());
   1033    *outSRV = &mOffscreenSRView;
   1034    return angle::Result::Continue;
   1035 }
   1036 
   1037 const d3d11::DepthStencilView &SwapChain11::getDepthStencil()
   1038 {
   1039    return mDepthStencilDSView;
   1040 }
   1041 
   1042 const d3d11::SharedSRV &SwapChain11::getDepthStencilShaderResource()
   1043 {
   1044    return mDepthStencilSRView;
   1045 }
   1046 
   1047 const TextureHelper11 &SwapChain11::getDepthStencilTexture()
   1048 {
   1049    return mDepthStencilTexture;
   1050 }
   1051 
   1052 void *SwapChain11::getKeyedMutex()
   1053 {
   1054    return mKeyedMutex;
   1055 }
   1056 
   1057 void SwapChain11::recreate()
   1058 {
   1059    // possibly should use this method instead of reset
   1060 }
   1061 
   1062 RenderTargetD3D *SwapChain11::getColorRenderTarget()
   1063 {
   1064    return &mColorRenderTarget;
   1065 }
   1066 
   1067 RenderTargetD3D *SwapChain11::getDepthStencilRenderTarget()
   1068 {
   1069    return &mDepthStencilRenderTarget;
   1070 }
   1071 
   1072 egl::Error SwapChain11::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
   1073 {
   1074    if (!mSwapChain)
   1075    {
   1076        return egl::EglNotInitialized() << "Swap chain uninitialized";
   1077    }
   1078 
   1079    DXGI_FRAME_STATISTICS stats = {};
   1080    HRESULT result              = mSwapChain->GetFrameStatistics(&stats);
   1081 
   1082    if (FAILED(result))
   1083    {
   1084        return egl::EglBadAlloc() << "Failed to get frame statistics, " << gl::FmtHR(result);
   1085    }
   1086 
   1087    // Conversion from DXGI_FRAME_STATISTICS to the output values:
   1088    // stats.SyncRefreshCount -> msc
   1089    // stats.PresentCount -> sbc
   1090    // stats.SyncQPCTime -> ust with conversion to microseconds via QueryPerformanceFrequency
   1091    *msc = stats.SyncRefreshCount;
   1092    *sbc = stats.PresentCount;
   1093 
   1094    LONGLONG syncQPCValue = stats.SyncQPCTime.QuadPart;
   1095    // If the QPC Value is below the overflow threshold, we proceed with
   1096    // simple multiply and divide.
   1097    if (syncQPCValue < kQPCOverflowThreshold)
   1098    {
   1099        *ust = syncQPCValue * kMicrosecondsPerSecond / mQPCFrequency;
   1100    }
   1101    else
   1102    {
   1103        // Otherwise, calculate microseconds in a round about manner to avoid
   1104        // overflow and precision issues.
   1105        int64_t wholeSeconds  = syncQPCValue / mQPCFrequency;
   1106        int64_t leftoverTicks = syncQPCValue - (wholeSeconds * mQPCFrequency);
   1107        *ust                  = wholeSeconds * kMicrosecondsPerSecond +
   1108               leftoverTicks * kMicrosecondsPerSecond / mQPCFrequency;
   1109    }
   1110 
   1111    return egl::NoError();
   1112 }
   1113 
   1114 UINT SwapChain11::getD3DSamples() const
   1115 {
   1116    return (mEGLSamples == 0) ? 1 : mEGLSamples;
   1117 }
   1118 
   1119 }  // namespace rx