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