1 //
2 // Copyright 2015 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 // DXGISwapChainWindowSurfaceWGL.cpp: WGL implementation of egl::Surface for windows using a DXGI
8 // swapchain.
9
10 #include "libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h"
11
12 #include "libANGLE/formatutils.h"
13 #include "libANGLE/renderer/gl/FramebufferGL.h"
14 #include "libANGLE/renderer/gl/RendererGL.h"
15 #include "libANGLE/renderer/gl/StateManagerGL.h"
16 #include "libANGLE/renderer/gl/TextureGL.h"
17 #include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
18 #include "libANGLE/renderer/gl/wgl/FunctionsWGL.h"
19
20 #include <EGL/eglext.h>
21
22 namespace rx
23 {
24
DXGISwapChainWindowSurfaceWGL(const egl::SurfaceState & state,StateManagerGL * stateManager,EGLNativeWindowType window,ID3D11Device * device,HANDLE deviceHandle,HDC deviceContext,const FunctionsGL * functionsGL,const FunctionsWGL * functionsWGL,EGLint orientation)25 DXGISwapChainWindowSurfaceWGL::DXGISwapChainWindowSurfaceWGL(const egl::SurfaceState &state,
26 StateManagerGL *stateManager,
27 EGLNativeWindowType window,
28 ID3D11Device *device,
29 HANDLE deviceHandle,
30 HDC deviceContext,
31 const FunctionsGL *functionsGL,
32 const FunctionsWGL *functionsWGL,
33 EGLint orientation)
34 : SurfaceWGL(state),
35 mWindow(window),
36 mStateManager(stateManager),
37 mFunctionsGL(functionsGL),
38 mFunctionsWGL(functionsWGL),
39 mDevice(device),
40 mDeviceHandle(deviceHandle),
41 mWGLDevice(deviceContext),
42 mSwapChainFormat(DXGI_FORMAT_UNKNOWN),
43 mSwapChainFlags(0),
44 mDepthBufferFormat(GL_NONE),
45 mFirstSwap(true),
46 mSwapChain(nullptr),
47 mSwapChain1(nullptr),
48 mFramebufferID(0),
49 mColorRenderbufferID(0),
50 mRenderbufferBufferHandle(nullptr),
51 mDepthRenderbufferID(0),
52 mTextureID(0),
53 mTextureHandle(nullptr),
54 mWidth(0),
55 mHeight(0),
56 mSwapInterval(1),
57 mOrientation(orientation)
58 {}
59
~DXGISwapChainWindowSurfaceWGL()60 DXGISwapChainWindowSurfaceWGL::~DXGISwapChainWindowSurfaceWGL()
61 {
62 if (mRenderbufferBufferHandle != nullptr)
63 {
64 mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mRenderbufferBufferHandle);
65 mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mRenderbufferBufferHandle);
66 }
67
68 if (mFramebufferID != 0)
69 {
70 mStateManager->deleteFramebuffer(mFramebufferID);
71 mFramebufferID = 0;
72 }
73
74 if (mColorRenderbufferID != 0)
75 {
76 mStateManager->deleteRenderbuffer(mColorRenderbufferID);
77 mColorRenderbufferID = 0;
78 }
79
80 if (mDepthRenderbufferID != 0)
81 {
82 mStateManager->deleteRenderbuffer(mDepthRenderbufferID);
83 mDepthRenderbufferID = 0;
84 }
85
86 SafeRelease(mSwapChain);
87 SafeRelease(mSwapChain1);
88 }
89
initialize(const egl::Display * display)90 egl::Error DXGISwapChainWindowSurfaceWGL::initialize(const egl::Display *display)
91 {
92 if (mOrientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE)
93 {
94 // TODO(geofflang): Support the orientation extensions fully. Currently only inverting Y is
95 // supported. To support all orientations, an intermediate framebuffer will be needed with
96 // a blit before swap.
97 return egl::Error(EGL_BAD_ATTRIBUTE,
98 "DXGISwapChainWindowSurfaceWGL requires an orientation of "
99 "EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE.");
100 }
101
102 RECT rect;
103 if (!GetClientRect(mWindow, &rect))
104 {
105 return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the window size.");
106 }
107 mWidth = rect.right - rect.left;
108 mHeight = rect.bottom - rect.top;
109
110 mSwapChainFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
111 mSwapChainFlags = 0;
112 mDepthBufferFormat = GL_DEPTH24_STENCIL8;
113
114 mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID);
115 mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID);
116
117 mFunctionsGL->genRenderbuffers(1, &mDepthRenderbufferID);
118 mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbufferID);
119
120 return createSwapChain();
121 }
122
makeCurrent(const gl::Context * context)123 egl::Error DXGISwapChainWindowSurfaceWGL::makeCurrent(const gl::Context *context)
124 {
125 return egl::NoError();
126 }
127
swap(const gl::Context * context,SurfaceSwapFeedback * feedback)128 egl::Error DXGISwapChainWindowSurfaceWGL::swap(const gl::Context *context,
129 SurfaceSwapFeedback *feedback)
130 {
131 mFunctionsGL->flush();
132
133 ANGLE_TRY(setObjectsLocked(false));
134
135 HRESULT result = mSwapChain->Present(mSwapInterval, 0);
136 mFirstSwap = false;
137
138 ANGLE_TRY(setObjectsLocked(true));
139
140 if (FAILED(result))
141 {
142 std::ostringstream err;
143 err << "Failed to present swap chain, " << gl::FmtHR(result);
144 return egl::Error(EGL_BAD_ALLOC, err.str());
145 }
146
147 return checkForResize();
148 }
149
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)150 egl::Error DXGISwapChainWindowSurfaceWGL::postSubBuffer(const gl::Context *context,
151 EGLint x,
152 EGLint y,
153 EGLint width,
154 EGLint height)
155 {
156 ASSERT(width > 0 && height > 0);
157 ASSERT(mSwapChain1 != nullptr);
158
159 mFunctionsGL->flush();
160
161 ANGLE_TRY(setObjectsLocked(false));
162
163 HRESULT result = S_OK;
164 if (mFirstSwap)
165 {
166 result = mSwapChain1->Present(mSwapInterval, 0);
167 mFirstSwap = false;
168 }
169 else
170 {
171 RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
172 static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
173 DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr};
174 result = mSwapChain1->Present1(mSwapInterval, 0, ¶ms);
175 }
176
177 ANGLE_TRY(setObjectsLocked(true));
178
179 if (FAILED(result))
180 {
181 std::ostringstream err;
182 err << "Failed to present swap chain, " << gl::FmtHR(result);
183 return egl::Error(EGL_BAD_ALLOC, err.str());
184 }
185
186 return checkForResize();
187 }
188
querySurfacePointerANGLE(EGLint attribute,void ** value)189 egl::Error DXGISwapChainWindowSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value)
190 {
191 UNREACHABLE();
192 return egl::NoError();
193 }
194
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)195 egl::Error DXGISwapChainWindowSurfaceWGL::bindTexImage(const gl::Context *context,
196 gl::Texture *texture,
197 EGLint buffer)
198 {
199 ASSERT(mTextureHandle == nullptr);
200
201 const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
202 GLuint textureID = textureGL->getTextureID();
203
204 ID3D11Texture2D *colorBuffer = nullptr;
205 HRESULT result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
206 reinterpret_cast<void **>(&colorBuffer));
207 if (FAILED(result))
208 {
209 std::ostringstream err;
210 err << "Failed to query texture from swap chain, " << gl::FmtHR(result);
211 return egl::Error(EGL_BAD_ALLOC, err.str());
212 }
213
214 mTextureHandle = mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, textureID,
215 GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
216 SafeRelease(colorBuffer);
217 if (mTextureHandle == nullptr)
218 {
219 std::ostringstream err;
220 err << "Failed to register D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
221 return egl::Error(EGL_BAD_ALLOC, err.str());
222 }
223
224 if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mTextureHandle))
225 {
226 mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle);
227 mTextureHandle = nullptr;
228
229 std::ostringstream err;
230 err << "Failed to lock D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
231 return egl::Error(EGL_BAD_ALLOC, err.str());
232 }
233
234 mTextureID = textureID;
235
236 return egl::NoError();
237 }
238
releaseTexImage(const gl::Context * context,EGLint buffer)239 egl::Error DXGISwapChainWindowSurfaceWGL::releaseTexImage(const gl::Context *context, EGLint buffer)
240 {
241 ASSERT(mTextureHandle != nullptr);
242
243 if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mTextureHandle))
244 {
245 std::ostringstream err;
246 err << "Failed to unlock D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
247 return egl::Error(EGL_BAD_ALLOC, err.str());
248 }
249
250 if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle))
251 {
252 std::ostringstream err;
253 err << "Failed to unregister D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
254 return egl::Error(EGL_BAD_ALLOC, err.str());
255 }
256
257 mTextureID = 0;
258 mTextureHandle = nullptr;
259
260 return egl::NoError();
261 }
262
setSwapInterval(const egl::Display * display,EGLint interval)263 void DXGISwapChainWindowSurfaceWGL::setSwapInterval(const egl::Display *display, EGLint interval)
264 {
265 mSwapInterval = interval;
266 }
267
getWidth() const268 EGLint DXGISwapChainWindowSurfaceWGL::getWidth() const
269 {
270 return static_cast<EGLint>(mWidth);
271 }
272
getHeight() const273 EGLint DXGISwapChainWindowSurfaceWGL::getHeight() const
274 {
275 return static_cast<EGLint>(mHeight);
276 }
277
isPostSubBufferSupported() const278 EGLint DXGISwapChainWindowSurfaceWGL::isPostSubBufferSupported() const
279 {
280 return mSwapChain1 != nullptr;
281 }
282
getSwapBehavior() const283 EGLint DXGISwapChainWindowSurfaceWGL::getSwapBehavior() const
284 {
285 return EGL_BUFFER_DESTROYED;
286 }
287
getDC() const288 HDC DXGISwapChainWindowSurfaceWGL::getDC() const
289 {
290 return mWGLDevice;
291 }
292
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)293 egl::Error DXGISwapChainWindowSurfaceWGL::attachToFramebuffer(const gl::Context *context,
294 gl::Framebuffer *framebuffer)
295 {
296 FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
297 ASSERT(framebufferGL->getFramebufferID() == 0);
298
299 if (mFramebufferID == 0)
300 {
301 GLuint framebufferID = 0;
302 mFunctionsGL->genFramebuffers(1, &framebufferID);
303 mStateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferID);
304 mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
305 mColorRenderbufferID);
306
307 if (mDepthBufferFormat != GL_NONE)
308 {
309 const gl::InternalFormat &depthStencilFormatInfo =
310 gl::GetSizedInternalFormatInfo(mDepthBufferFormat);
311 if (depthStencilFormatInfo.depthBits > 0)
312 {
313 mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
314 GL_RENDERBUFFER, mDepthRenderbufferID);
315 }
316 if (depthStencilFormatInfo.stencilBits > 0)
317 {
318 mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
319 GL_RENDERBUFFER, mDepthRenderbufferID);
320 }
321 }
322
323 mFramebufferID = framebufferID;
324 }
325 framebufferGL->setFramebufferID(mFramebufferID);
326 return egl::NoError();
327 }
328
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)329 egl::Error DXGISwapChainWindowSurfaceWGL::detachFromFramebuffer(const gl::Context *context,
330 gl::Framebuffer *framebuffer)
331 {
332 FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
333 ASSERT(framebufferGL->getFramebufferID() == mFramebufferID);
334 framebufferGL->setFramebufferID(0);
335 return egl::NoError();
336 }
337
setObjectsLocked(bool locked)338 egl::Error DXGISwapChainWindowSurfaceWGL::setObjectsLocked(bool locked)
339 {
340 if (mRenderbufferBufferHandle == nullptr)
341 {
342 ASSERT(mTextureHandle == nullptr);
343 return egl::NoError();
344 }
345
346 HANDLE resources[] = {
347 mRenderbufferBufferHandle,
348 mTextureHandle,
349 };
350 GLint count = (mTextureHandle != nullptr) ? 2 : 1;
351
352 if (locked)
353 {
354 if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, count, resources))
355 {
356 std::ostringstream err;
357 err << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
358 return egl::Error(EGL_BAD_ALLOC, err.str());
359 }
360 }
361 else
362 {
363 if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, count, resources))
364 {
365 std::ostringstream err;
366 err << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
367 return egl::Error(EGL_BAD_ALLOC, err.str());
368 }
369 }
370
371 return egl::NoError();
372 }
373
checkForResize()374 egl::Error DXGISwapChainWindowSurfaceWGL::checkForResize()
375 {
376 RECT rect;
377 if (!GetClientRect(mWindow, &rect))
378 {
379 return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the window size.");
380 }
381
382 size_t newWidth = rect.right - rect.left;
383 size_t newHeight = rect.bottom - rect.top;
384 if (newWidth != mWidth || newHeight != mHeight)
385 {
386 mWidth = newWidth;
387 mHeight = newHeight;
388
389 // TODO(geofflang): Handle resize by resizing the swap chain instead of re-creating it.
390 egl::Error error = createSwapChain();
391 if (error.isError())
392 {
393 return error;
394 }
395 }
396
397 return egl::NoError();
398 }
399
GetDXGIFactoryFromDevice(ID3D11Device * device)400 static IDXGIFactory *GetDXGIFactoryFromDevice(ID3D11Device *device)
401 {
402 IDXGIDevice *dxgiDevice = nullptr;
403 HRESULT result =
404 device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDevice));
405 if (FAILED(result))
406 {
407 return nullptr;
408 }
409
410 IDXGIAdapter *dxgiAdapter = nullptr;
411 result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void **>(&dxgiAdapter));
412 SafeRelease(dxgiDevice);
413 if (FAILED(result))
414 {
415 return nullptr;
416 }
417
418 IDXGIFactory *dxgiFactory = nullptr;
419 result =
420 dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&dxgiFactory));
421 SafeRelease(dxgiAdapter);
422 if (FAILED(result))
423 {
424 return nullptr;
425 }
426
427 return dxgiFactory;
428 }
429
createSwapChain()430 egl::Error DXGISwapChainWindowSurfaceWGL::createSwapChain()
431 {
432 egl::Error error = setObjectsLocked(false);
433 if (error.isError())
434 {
435 return error;
436 }
437
438 if (mRenderbufferBufferHandle)
439 {
440 mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mRenderbufferBufferHandle);
441 mRenderbufferBufferHandle = nullptr;
442 }
443
444 // If this surface is bound to a texture, unregister it.
445 bool hadBoundSurface = (mTextureHandle != nullptr);
446 if (hadBoundSurface)
447 {
448 mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mTextureHandle);
449 mTextureHandle = nullptr;
450 }
451
452 IDXGIFactory *dxgiFactory = GetDXGIFactoryFromDevice(mDevice);
453 if (dxgiFactory == nullptr)
454 {
455 return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to query the DXGIFactory.");
456 }
457
458 IDXGIFactory2 *dxgiFactory2 = nullptr;
459 HRESULT result = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2),
460 reinterpret_cast<void **>(&dxgiFactory2));
461 if (SUCCEEDED(result))
462 {
463 ASSERT(dxgiFactory2 != nullptr);
464
465 DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
466 swapChainDesc.BufferCount = 1;
467 swapChainDesc.Format = mSwapChainFormat;
468 swapChainDesc.Width = static_cast<UINT>(mWidth);
469 swapChainDesc.Height = static_cast<UINT>(mHeight);
470 swapChainDesc.Format = mSwapChainFormat;
471 swapChainDesc.Stereo = FALSE;
472 swapChainDesc.SampleDesc.Count = 1;
473 swapChainDesc.SampleDesc.Quality = 0;
474 swapChainDesc.BufferUsage =
475 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
476 swapChainDesc.BufferCount = 1;
477 swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
478 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
479 swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
480 swapChainDesc.Flags = mSwapChainFlags;
481
482 result = dxgiFactory2->CreateSwapChainForHwnd(mDevice, mWindow, &swapChainDesc, nullptr,
483 nullptr, &mSwapChain1);
484 SafeRelease(dxgiFactory2);
485 SafeRelease(dxgiFactory);
486 if (FAILED(result))
487 {
488 std::ostringstream err;
489 err << "Failed to create swap chain for window, " << gl::FmtHR(result);
490 return egl::Error(EGL_BAD_ALLOC, err.str());
491 }
492
493 mSwapChain = mSwapChain1;
494 mSwapChain->AddRef();
495 }
496 else
497 {
498 DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
499 swapChainDesc.BufferCount = 1;
500 swapChainDesc.BufferDesc.Format = mSwapChainFormat;
501 swapChainDesc.BufferDesc.Width = static_cast<UINT>(mWidth);
502 swapChainDesc.BufferDesc.Height = static_cast<UINT>(mHeight);
503 swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
504 swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
505 swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
506 swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
507 swapChainDesc.BufferUsage =
508 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
509 swapChainDesc.Flags = mSwapChainFlags;
510 swapChainDesc.OutputWindow = mWindow;
511 swapChainDesc.SampleDesc.Count = 1;
512 swapChainDesc.SampleDesc.Quality = 0;
513 swapChainDesc.Windowed = TRUE;
514 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
515
516 result = dxgiFactory->CreateSwapChain(mDevice, &swapChainDesc, &mSwapChain);
517 SafeRelease(dxgiFactory);
518 if (FAILED(result))
519 {
520 std::ostringstream err;
521 err << "Failed to create swap chain for window, " << gl::FmtHR(result);
522 return egl::Error(EGL_BAD_ALLOC, err.str());
523 }
524 }
525
526 ID3D11Texture2D *colorBuffer = nullptr;
527 result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
528 reinterpret_cast<void **>(&colorBuffer));
529 if (FAILED(result))
530 {
531 std::ostringstream err;
532 err << "Failed to query texture from swap chain, " << gl::FmtHR(result);
533 return egl::Error(EGL_BAD_ALLOC, err.str());
534 }
535
536 mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID);
537 mRenderbufferBufferHandle =
538 mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, mColorRenderbufferID,
539 GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
540 SafeRelease(colorBuffer);
541 if (mRenderbufferBufferHandle == nullptr)
542 {
543 std::ostringstream err;
544 err << "Failed to register D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
545 return egl::Error(EGL_BAD_ALLOC, err.str());
546 }
547
548 // Rebind the surface to the texture if needed.
549 if (hadBoundSurface)
550 {
551 mTextureHandle = mFunctionsWGL->dxRegisterObjectNV(mDeviceHandle, colorBuffer, mTextureID,
552 GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
553 if (mTextureHandle == nullptr)
554 {
555 std::ostringstream err;
556 err << "Failed to register D3D object, " << gl::FmtErr(HRESULT_CODE(GetLastError()));
557 return egl::Error(EGL_BAD_ALLOC, err.str());
558 }
559 }
560
561 error = setObjectsLocked(true);
562 if (error.isError())
563 {
564 return error;
565 }
566
567 if (mDepthBufferFormat != GL_NONE)
568 {
569 ASSERT(mDepthRenderbufferID != 0);
570 mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbufferID);
571 mFunctionsGL->renderbufferStorage(GL_RENDERBUFFER, mDepthBufferFormat,
572 static_cast<GLsizei>(mWidth),
573 static_cast<GLsizei>(mHeight));
574 }
575
576 mFirstSwap = true;
577
578 return egl::NoError();
579 }
580 } // namespace rx
581