• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 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 // SurfaceD3D.cpp: D3D implementation of an EGL surface
8 
9 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
10 
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Display.h"
13 #include "libANGLE/Surface.h"
14 #include "libANGLE/renderer/Format.h"
15 #include "libANGLE/renderer/d3d/DisplayD3D.h"
16 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
17 #include "libANGLE/renderer/d3d/RendererD3D.h"
18 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
19 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
20 
21 #include <EGL/eglext.h>
22 #include <tchar.h>
23 #include <algorithm>
24 
25 namespace rx
26 {
27 
SurfaceD3D(const egl::SurfaceState & state,RendererD3D * renderer,egl::Display * display,EGLNativeWindowType window,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)28 SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state,
29                        RendererD3D *renderer,
30                        egl::Display *display,
31                        EGLNativeWindowType window,
32                        EGLenum buftype,
33                        EGLClientBuffer clientBuffer,
34                        const egl::AttributeMap &attribs)
35     : SurfaceImpl(state),
36       mRenderer(renderer),
37       mDisplay(display),
38       mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE),
39       mFixedWidth(0),
40       mFixedHeight(0),
41       mOrientation(static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))),
42       mRenderTargetFormat(state.config->renderTargetFormat),
43       mDepthStencilFormat(state.config->depthStencilFormat),
44       mColorFormat(nullptr),
45       mSwapChain(nullptr),
46       mSwapIntervalDirty(true),
47       mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)),
48       mWidth(static_cast<EGLint>(attribs.get(EGL_WIDTH, 0))),
49       mHeight(static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0))),
50       mSwapInterval(1),
51       mShareHandle(0),
52       mD3DTexture(nullptr),
53       mBuftype(buftype)
54 {
55     if (window != nullptr && !mFixedSize)
56     {
57         mWidth  = -1;
58         mHeight = -1;
59     }
60 
61     if (mFixedSize)
62     {
63         mFixedWidth  = mWidth;
64         mFixedHeight = mHeight;
65     }
66 
67     switch (buftype)
68     {
69         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
70             mShareHandle = static_cast<HANDLE>(clientBuffer);
71             break;
72 
73         case EGL_D3D_TEXTURE_ANGLE:
74             mD3DTexture = static_cast<IUnknown *>(clientBuffer);
75             ASSERT(mD3DTexture != nullptr);
76             mD3DTexture->AddRef();
77             break;
78 
79         default:
80             break;
81     }
82 }
83 
~SurfaceD3D()84 SurfaceD3D::~SurfaceD3D()
85 {
86     releaseSwapChain();
87     SafeDelete(mNativeWindow);
88     SafeRelease(mD3DTexture);
89 }
90 
releaseSwapChain()91 void SurfaceD3D::releaseSwapChain()
92 {
93     SafeDelete(mSwapChain);
94 }
95 
initialize(const egl::Display * display)96 egl::Error SurfaceD3D::initialize(const egl::Display *display)
97 {
98     if (mNativeWindow->getNativeWindow())
99     {
100         if (!mNativeWindow->initialize())
101         {
102             return egl::EglBadSurface();
103         }
104     }
105 
106     if (mBuftype == EGL_D3D_TEXTURE_ANGLE)
107     {
108         ANGLE_TRY(mRenderer->getD3DTextureInfo(mState.config, mD3DTexture, mState.attributes,
109                                                &mFixedWidth, &mFixedHeight, nullptr, nullptr,
110                                                &mColorFormat));
111         if (mState.attributes.contains(EGL_GL_COLORSPACE))
112         {
113             if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS &&
114                 mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS)
115             {
116                 return egl::EglBadMatch()
117                        << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures";
118             }
119         }
120         if (mColorFormat->id == angle::FormatID::R8G8B8A8_TYPELESS)
121         {
122             EGLAttrib colorspace =
123                 mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
124             if (colorspace == EGL_GL_COLORSPACE_SRGB)
125             {
126                 mColorFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_TYPELESS_SRGB);
127             }
128         }
129         if (mColorFormat->id == angle::FormatID::B8G8R8A8_TYPELESS)
130         {
131             EGLAttrib colorspace =
132                 mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
133             if (colorspace == EGL_GL_COLORSPACE_SRGB)
134             {
135                 mColorFormat = &angle::Format::Get(angle::FormatID::B8G8R8A8_TYPELESS_SRGB);
136             }
137         }
138         mRenderTargetFormat = mColorFormat->fboImplementationInternalFormat;
139     }
140 
141     ANGLE_TRY(resetSwapChain(display));
142     return egl::NoError();
143 }
144 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & data)145 FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::Context *context,
146                                                       const gl::FramebufferState &data)
147 {
148     return mRenderer->createDefaultFramebuffer(data);
149 }
150 
bindTexImage(const gl::Context *,gl::Texture *,EGLint)151 egl::Error SurfaceD3D::bindTexImage(const gl::Context *, gl::Texture *, EGLint)
152 {
153     return egl::NoError();
154 }
155 
releaseTexImage(const gl::Context *,EGLint)156 egl::Error SurfaceD3D::releaseTexImage(const gl::Context *, EGLint)
157 {
158     return egl::NoError();
159 }
160 
getSyncValues(EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)161 egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
162 {
163     if (!mState.directComposition)
164     {
165         return egl::EglBadSurface()
166                << "getSyncValues: surface requires Direct Composition to be enabled";
167     }
168 
169     return mSwapChain->getSyncValues(ust, msc, sbc);
170 }
171 
getMscRate(EGLint * numerator,EGLint * denominator)172 egl::Error SurfaceD3D::getMscRate(EGLint *numerator, EGLint *denominator)
173 {
174     UNIMPLEMENTED();
175     return egl::EglBadAccess();
176 }
177 
resetSwapChain(const egl::Display * display)178 egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display)
179 {
180     ASSERT(!mSwapChain);
181 
182     int width;
183     int height;
184 
185     if (!mFixedSize)
186     {
187         RECT windowRect;
188         if (!mNativeWindow->getClientRect(&windowRect))
189         {
190             ASSERT(false);
191 
192             return egl::EglBadSurface() << "Could not retrieve the window dimensions";
193         }
194 
195         width  = windowRect.right - windowRect.left;
196         height = windowRect.bottom - windowRect.top;
197     }
198     else
199     {
200         // non-window surface - size is determined at creation
201         width  = mFixedWidth;
202         height = mFixedHeight;
203     }
204 
205     mSwapChain =
206         mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat,
207                                    mDepthStencilFormat, mOrientation, mState.config->samples);
208     if (!mSwapChain)
209     {
210         return egl::EglBadAlloc();
211     }
212 
213     // This is a bit risky to pass the proxy context here, but it can happen at almost any time.
214     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(display);
215     egl::Error error       = resetSwapChain(displayD3D, width, height);
216     if (error.isError())
217     {
218         SafeDelete(mSwapChain);
219         return error;
220     }
221 
222     return egl::NoError();
223 }
224 
resizeSwapChain(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)225 egl::Error SurfaceD3D::resizeSwapChain(DisplayD3D *displayD3D,
226                                        int backbufferWidth,
227                                        int backbufferHeight)
228 {
229     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
230     ASSERT(mSwapChain);
231 
232     EGLint status =
233         mSwapChain->resize(displayD3D, std::max(1, backbufferWidth), std::max(1, backbufferHeight));
234 
235     if (status == EGL_CONTEXT_LOST)
236     {
237         mDisplay->notifyDeviceLost();
238         return egl::Error(status);
239     }
240     else if (status != EGL_SUCCESS)
241     {
242         return egl::Error(status);
243     }
244 
245     mWidth  = backbufferWidth;
246     mHeight = backbufferHeight;
247 
248     return egl::NoError();
249 }
250 
resetSwapChain(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)251 egl::Error SurfaceD3D::resetSwapChain(DisplayD3D *displayD3D,
252                                       int backbufferWidth,
253                                       int backbufferHeight)
254 {
255     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
256     ASSERT(mSwapChain);
257 
258     EGLint status = mSwapChain->reset(displayD3D, std::max(1, backbufferWidth),
259                                       std::max(1, backbufferHeight), mSwapInterval);
260 
261     if (status == EGL_CONTEXT_LOST)
262     {
263         mRenderer->notifyDeviceLost();
264         return egl::Error(status);
265     }
266     else if (status != EGL_SUCCESS)
267     {
268         return egl::Error(status);
269     }
270 
271     mWidth             = backbufferWidth;
272     mHeight            = backbufferHeight;
273     mSwapIntervalDirty = false;
274 
275     return egl::NoError();
276 }
277 
swapRect(DisplayD3D * displayD3D,EGLint x,EGLint y,EGLint width,EGLint height)278 egl::Error SurfaceD3D::swapRect(DisplayD3D *displayD3D,
279                                 EGLint x,
280                                 EGLint y,
281                                 EGLint width,
282                                 EGLint height)
283 {
284     if (!mSwapChain)
285     {
286         return egl::NoError();
287     }
288 
289     if (x + width > mWidth)
290     {
291         width = mWidth - x;
292     }
293 
294     if (y + height > mHeight)
295     {
296         height = mHeight - y;
297     }
298 
299     if (width != 0 && height != 0)
300     {
301         EGLint status = mSwapChain->swapRect(displayD3D, x, y, width, height);
302 
303         if (status == EGL_CONTEXT_LOST)
304         {
305             mRenderer->notifyDeviceLost();
306             return egl::Error(status);
307         }
308         else if (status != EGL_SUCCESS)
309         {
310             return egl::Error(status);
311         }
312     }
313 
314     ANGLE_TRY(checkForOutOfDateSwapChain(displayD3D));
315 
316     return egl::NoError();
317 }
318 
checkForOutOfDateSwapChain(DisplayD3D * displayD3D)319 egl::Error SurfaceD3D::checkForOutOfDateSwapChain(DisplayD3D *displayD3D)
320 {
321     RECT client;
322     int clientWidth  = getWidth();
323     int clientHeight = getHeight();
324     bool sizeDirty   = false;
325     if (!mFixedSize && !mNativeWindow->isIconic())
326     {
327         // The window is automatically resized to 150x22 when it's minimized, but the swapchain
328         // shouldn't be resized because that's not a useful size to render to.
329         if (!mNativeWindow->getClientRect(&client))
330         {
331             UNREACHABLE();
332             return egl::NoError();
333         }
334 
335         // Grow the buffer now, if the window has grown. We need to grow now to avoid losing
336         // information.
337         clientWidth  = client.right - client.left;
338         clientHeight = client.bottom - client.top;
339         sizeDirty    = clientWidth != getWidth() || clientHeight != getHeight();
340     }
341     else if (mFixedSize)
342     {
343         clientWidth  = mFixedWidth;
344         clientHeight = mFixedHeight;
345         sizeDirty    = mFixedWidth != getWidth() || mFixedHeight != getHeight();
346     }
347 
348     if (mSwapIntervalDirty)
349     {
350         ANGLE_TRY(resetSwapChain(displayD3D, clientWidth, clientHeight));
351     }
352     else if (sizeDirty)
353     {
354         ANGLE_TRY(resizeSwapChain(displayD3D, clientWidth, clientHeight));
355     }
356 
357     return egl::NoError();
358 }
359 
swap(const gl::Context * context)360 egl::Error SurfaceD3D::swap(const gl::Context *context)
361 {
362     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
363     return swapRect(displayD3D, 0, 0, mWidth, mHeight);
364 }
365 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)366 egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context,
367                                      EGLint x,
368                                      EGLint y,
369                                      EGLint width,
370                                      EGLint height)
371 {
372     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
373     return swapRect(displayD3D, x, y, width, height);
374 }
375 
getSwapChain() const376 rx::SwapChainD3D *SurfaceD3D::getSwapChain() const
377 {
378     return mSwapChain;
379 }
380 
setSwapInterval(EGLint interval)381 void SurfaceD3D::setSwapInterval(EGLint interval)
382 {
383     if (mSwapInterval == interval)
384     {
385         return;
386     }
387 
388     mSwapInterval      = interval;
389     mSwapIntervalDirty = true;
390 }
391 
setFixedWidth(EGLint width)392 void SurfaceD3D::setFixedWidth(EGLint width)
393 {
394     mFixedWidth = width;
395 }
396 
setFixedHeight(EGLint height)397 void SurfaceD3D::setFixedHeight(EGLint height)
398 {
399     mFixedHeight = height;
400 }
401 
getWidth() const402 EGLint SurfaceD3D::getWidth() const
403 {
404     return mWidth;
405 }
406 
getHeight() const407 EGLint SurfaceD3D::getHeight() const
408 {
409     return mHeight;
410 }
411 
isPostSubBufferSupported() const412 EGLint SurfaceD3D::isPostSubBufferSupported() const
413 {
414     // post sub buffer is always possible on D3D surfaces
415     return EGL_TRUE;
416 }
417 
getSwapBehavior() const418 EGLint SurfaceD3D::getSwapBehavior() const
419 {
420     return EGL_BUFFER_PRESERVED;
421 }
422 
querySurfacePointerANGLE(EGLint attribute,void ** value)423 egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value)
424 {
425     if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
426     {
427         *value = mSwapChain->getShareHandle();
428     }
429     else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE)
430     {
431         *value = mSwapChain->getKeyedMutex();
432     }
433     else
434         UNREACHABLE();
435 
436     return egl::NoError();
437 }
438 
getD3DTextureColorFormat() const439 const angle::Format *SurfaceD3D::getD3DTextureColorFormat() const
440 {
441     return mColorFormat;
442 }
443 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)444 angle::Result SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context,
445                                                     GLenum binding,
446                                                     const gl::ImageIndex &imageIndex,
447                                                     GLsizei samples,
448                                                     FramebufferAttachmentRenderTarget **rtOut)
449 {
450     if (binding == GL_BACK)
451     {
452         *rtOut = mSwapChain->getColorRenderTarget();
453     }
454     else
455     {
456         *rtOut = mSwapChain->getDepthStencilRenderTarget();
457     }
458     return angle::Result::Continue;
459 }
460 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)461 angle::Result SurfaceD3D::initializeContents(const gl::Context *context,
462                                              const gl::ImageIndex &imageIndex)
463 {
464     if (mState.config->renderTargetFormat != GL_NONE)
465     {
466         ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getColorRenderTarget()));
467     }
468     if (mState.config->depthStencilFormat != GL_NONE)
469     {
470         ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getDepthStencilRenderTarget()));
471     }
472     return angle::Result::Continue;
473 }
474 
WindowSurfaceD3D(const egl::SurfaceState & state,RendererD3D * renderer,egl::Display * display,EGLNativeWindowType window,const egl::AttributeMap & attribs)475 WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state,
476                                    RendererD3D *renderer,
477                                    egl::Display *display,
478                                    EGLNativeWindowType window,
479                                    const egl::AttributeMap &attribs)
480     : SurfaceD3D(state, renderer, display, window, 0, static_cast<EGLClientBuffer>(0), attribs)
481 {}
482 
~WindowSurfaceD3D()483 WindowSurfaceD3D::~WindowSurfaceD3D() {}
484 
PbufferSurfaceD3D(const egl::SurfaceState & state,RendererD3D * renderer,egl::Display * display,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)485 PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state,
486                                      RendererD3D *renderer,
487                                      egl::Display *display,
488                                      EGLenum buftype,
489                                      EGLClientBuffer clientBuffer,
490                                      const egl::AttributeMap &attribs)
491     : SurfaceD3D(state,
492                  renderer,
493                  display,
494                  static_cast<EGLNativeWindowType>(0),
495                  buftype,
496                  clientBuffer,
497                  attribs)
498 {}
499 
~PbufferSurfaceD3D()500 PbufferSurfaceD3D::~PbufferSurfaceD3D() {}
501 
502 }  // namespace rx
503