xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
NeedsOffscreenTexture(Renderer11 * renderer,NativeWindow11 * nativeWindow,EGLint orientation)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 
SwapChain11(Renderer11 * renderer,NativeWindow11 * nativeWindow,HANDLE shareHandle,IUnknown * d3dTexture,GLenum backBufferFormat,GLenum depthBufferFormat,EGLint orientation,EGLint samples)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 
~SwapChain11()108 SwapChain11::~SwapChain11()
109 {
110     release();
111 }
112 
release()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 
releaseOffscreenColorBuffer()142 void SwapChain11::releaseOffscreenColorBuffer()
143 {
144     mOffscreenTexture.reset();
145     mOffscreenRTView.reset();
146     mOffscreenSRView.reset();
147     mNeedsOffscreenTextureCopy = false;
148     mOffscreenTextureCopyForSRV.reset();
149 }
150 
releaseOffscreenDepthBuffer()151 void SwapChain11::releaseOffscreenDepthBuffer()
152 {
153     mDepthStencilTexture.reset();
154     mDepthStencilDSView.reset();
155     mDepthStencilSRView.reset();
156 }
157 
resetOffscreenBuffers(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)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 
resetOffscreenColorBuffer(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)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 
resetOffscreenDepthBuffer(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)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 
resize(DisplayD3D * displayD3D,EGLint backbufferWidth,EGLint backbufferHeight)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 
getSwapChainNativeFormat() const559 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 
reset(DisplayD3D * displayD3D,EGLint backbufferWidth,EGLint backbufferHeight,EGLint swapInterval)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 
initPassThroughResources(DisplayD3D * displayD3D)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
swapRect(DisplayD3D * displayD3D,EGLint x,EGLint y,EGLint width,EGLint height)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 
copyOffscreenToBackbuffer(DisplayD3D * displayD3D,EGLint x,EGLint y,EGLint width,EGLint height)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 
present(DisplayD3D * displayD3D,EGLint x,EGLint y,EGLint width,EGLint height)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
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 
getOffscreenTexture()966 const TextureHelper11 &SwapChain11::getOffscreenTexture()
967 {
968     return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture;
969 }
970 
getRenderTarget()971 const d3d11::RenderTargetView &SwapChain11::getRenderTarget()
972 {
973     return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView;
974 }
975 
getRenderTargetShaderResource(d3d::Context * context,const d3d11::SharedSRV ** outSRV)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 
getDepthStencil()1037 const d3d11::DepthStencilView &SwapChain11::getDepthStencil()
1038 {
1039     return mDepthStencilDSView;
1040 }
1041 
getDepthStencilShaderResource()1042 const d3d11::SharedSRV &SwapChain11::getDepthStencilShaderResource()
1043 {
1044     return mDepthStencilSRView;
1045 }
1046 
getDepthStencilTexture()1047 const TextureHelper11 &SwapChain11::getDepthStencilTexture()
1048 {
1049     return mDepthStencilTexture;
1050 }
1051 
getKeyedMutex()1052 void *SwapChain11::getKeyedMutex()
1053 {
1054     return mKeyedMutex;
1055 }
1056 
recreate()1057 void SwapChain11::recreate()
1058 {
1059     // possibly should use this method instead of reset
1060 }
1061 
getColorRenderTarget()1062 RenderTargetD3D *SwapChain11::getColorRenderTarget()
1063 {
1064     return &mColorRenderTarget;
1065 }
1066 
getDepthStencilRenderTarget()1067 RenderTargetD3D *SwapChain11::getDepthStencilRenderTarget()
1068 {
1069     return &mDepthStencilRenderTarget;
1070 }
1071 
getSyncValues(EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)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 
getD3DSamples() const1114 UINT SwapChain11::getD3DSamples() const
1115 {
1116     return (mEGLSamples == 0) ? 1 : mEGLSamples;
1117 }
1118 
1119 }  // namespace rx
1120