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