xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
bindTexImage(const gl::Context *,gl::Texture *,EGLint)144 egl::Error SurfaceD3D::bindTexImage(const gl::Context *, gl::Texture *, EGLint)
145 {
146     return egl::NoError();
147 }
148 
releaseTexImage(const gl::Context *,EGLint)149 egl::Error SurfaceD3D::releaseTexImage(const gl::Context *, EGLint)
150 {
151     return egl::NoError();
152 }
153 
getSyncValues(EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)154 egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
155 {
156     if (!mState.directComposition)
157     {
158         return egl::EglBadSurface()
159                << "getSyncValues: surface requires Direct Composition to be enabled";
160     }
161 
162     return mSwapChain->getSyncValues(ust, msc, sbc);
163 }
164 
getMscRate(EGLint * numerator,EGLint * denominator)165 egl::Error SurfaceD3D::getMscRate(EGLint *numerator, EGLint *denominator)
166 {
167     UNIMPLEMENTED();
168     return egl::EglBadAccess();
169 }
170 
resetSwapChain(const egl::Display * display)171 egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display)
172 {
173     ASSERT(!mSwapChain);
174 
175     int width;
176     int height;
177 
178     if (!mFixedSize)
179     {
180         RECT windowRect;
181         if (!mNativeWindow->getClientRect(&windowRect))
182         {
183             ASSERT(false);
184 
185             return egl::EglBadSurface() << "Could not retrieve the window dimensions";
186         }
187 
188         width  = windowRect.right - windowRect.left;
189         height = windowRect.bottom - windowRect.top;
190     }
191     else
192     {
193         // non-window surface - size is determined at creation
194         width  = mFixedWidth;
195         height = mFixedHeight;
196     }
197 
198     mSwapChain =
199         mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat,
200                                    mDepthStencilFormat, mOrientation, mState.config->samples);
201     if (!mSwapChain)
202     {
203         return egl::EglBadAlloc();
204     }
205 
206     // This is a bit risky to pass the proxy context here, but it can happen at almost any time.
207     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(display);
208     egl::Error error       = resetSwapChain(displayD3D, width, height);
209     if (error.isError())
210     {
211         SafeDelete(mSwapChain);
212         return error;
213     }
214 
215     return egl::NoError();
216 }
217 
resizeSwapChain(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)218 egl::Error SurfaceD3D::resizeSwapChain(DisplayD3D *displayD3D,
219                                        int backbufferWidth,
220                                        int backbufferHeight)
221 {
222     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
223     ASSERT(mSwapChain);
224 
225     EGLint status =
226         mSwapChain->resize(displayD3D, std::max(1, backbufferWidth), std::max(1, backbufferHeight));
227 
228     if (status == EGL_CONTEXT_LOST)
229     {
230         mDisplay->notifyDeviceLost();
231         return egl::Error(status);
232     }
233     else if (status != EGL_SUCCESS)
234     {
235         return egl::Error(status);
236     }
237 
238     mWidth  = backbufferWidth;
239     mHeight = backbufferHeight;
240 
241     return egl::NoError();
242 }
243 
resetSwapChain(DisplayD3D * displayD3D,int backbufferWidth,int backbufferHeight)244 egl::Error SurfaceD3D::resetSwapChain(DisplayD3D *displayD3D,
245                                       int backbufferWidth,
246                                       int backbufferHeight)
247 {
248     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
249     ASSERT(mSwapChain);
250 
251     EGLint status = mSwapChain->reset(displayD3D, std::max(1, backbufferWidth),
252                                       std::max(1, backbufferHeight), mSwapInterval);
253 
254     if (status == EGL_CONTEXT_LOST)
255     {
256         mRenderer->notifyDeviceLost();
257         return egl::Error(status);
258     }
259     else if (status != EGL_SUCCESS)
260     {
261         return egl::Error(status);
262     }
263 
264     mWidth             = backbufferWidth;
265     mHeight            = backbufferHeight;
266     mSwapIntervalDirty = false;
267 
268     return egl::NoError();
269 }
270 
swapRect(DisplayD3D * displayD3D,EGLint x,EGLint y,EGLint width,EGLint height)271 egl::Error SurfaceD3D::swapRect(DisplayD3D *displayD3D,
272                                 EGLint x,
273                                 EGLint y,
274                                 EGLint width,
275                                 EGLint height)
276 {
277     if (!mSwapChain)
278     {
279         return egl::NoError();
280     }
281 
282     if (x + width > mWidth)
283     {
284         width = mWidth - x;
285     }
286 
287     if (y + height > mHeight)
288     {
289         height = mHeight - y;
290     }
291 
292     if (width != 0 && height != 0)
293     {
294         EGLint status = mSwapChain->swapRect(displayD3D, x, y, width, height);
295 
296         if (status == EGL_CONTEXT_LOST)
297         {
298             mRenderer->notifyDeviceLost();
299             return egl::Error(status);
300         }
301         else if (status != EGL_SUCCESS)
302         {
303             return egl::Error(status);
304         }
305     }
306 
307     ANGLE_TRY(checkForOutOfDateSwapChain(displayD3D));
308 
309     return egl::NoError();
310 }
311 
checkForOutOfDateSwapChain(DisplayD3D * displayD3D)312 egl::Error SurfaceD3D::checkForOutOfDateSwapChain(DisplayD3D *displayD3D)
313 {
314     RECT client;
315     int clientWidth  = getWidth();
316     int clientHeight = getHeight();
317     bool sizeDirty   = false;
318     if (!mFixedSize && !mNativeWindow->isIconic())
319     {
320         // The window is automatically resized to 150x22 when it's minimized, but the swapchain
321         // shouldn't be resized because that's not a useful size to render to.
322         if (!mNativeWindow->getClientRect(&client))
323         {
324             UNREACHABLE();
325             return egl::NoError();
326         }
327 
328         // Grow the buffer now, if the window has grown. We need to grow now to avoid losing
329         // information.
330         clientWidth  = client.right - client.left;
331         clientHeight = client.bottom - client.top;
332         sizeDirty    = clientWidth != getWidth() || clientHeight != getHeight();
333     }
334     else if (mFixedSize)
335     {
336         clientWidth  = mFixedWidth;
337         clientHeight = mFixedHeight;
338         sizeDirty    = mFixedWidth != getWidth() || mFixedHeight != getHeight();
339     }
340 
341     if (mSwapIntervalDirty)
342     {
343         ANGLE_TRY(resetSwapChain(displayD3D, clientWidth, clientHeight));
344     }
345     else if (sizeDirty)
346     {
347         ANGLE_TRY(resizeSwapChain(displayD3D, clientWidth, clientHeight));
348     }
349 
350     return egl::NoError();
351 }
352 
swap(const gl::Context * context)353 egl::Error SurfaceD3D::swap(const gl::Context *context)
354 {
355     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
356     return swapRect(displayD3D, 0, 0, mWidth, mHeight);
357 }
358 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)359 egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context,
360                                      EGLint x,
361                                      EGLint y,
362                                      EGLint width,
363                                      EGLint height)
364 {
365     DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay());
366     return swapRect(displayD3D, x, y, width, height);
367 }
368 
getSwapChain() const369 rx::SwapChainD3D *SurfaceD3D::getSwapChain() const
370 {
371     return mSwapChain;
372 }
373 
setSwapInterval(const egl::Display * display,EGLint interval)374 void SurfaceD3D::setSwapInterval(const egl::Display *display, EGLint interval)
375 {
376     if (mSwapInterval == interval)
377     {
378         return;
379     }
380 
381     mSwapInterval      = interval;
382     mSwapIntervalDirty = true;
383 }
384 
setFixedWidth(EGLint width)385 void SurfaceD3D::setFixedWidth(EGLint width)
386 {
387     mFixedWidth = width;
388 }
389 
setFixedHeight(EGLint height)390 void SurfaceD3D::setFixedHeight(EGLint height)
391 {
392     mFixedHeight = height;
393 }
394 
getWidth() const395 EGLint SurfaceD3D::getWidth() const
396 {
397     return mWidth;
398 }
399 
getHeight() const400 EGLint SurfaceD3D::getHeight() const
401 {
402     return mHeight;
403 }
404 
isPostSubBufferSupported() const405 EGLint SurfaceD3D::isPostSubBufferSupported() const
406 {
407     // post sub buffer is always possible on D3D surfaces
408     return EGL_TRUE;
409 }
410 
getSwapBehavior() const411 EGLint SurfaceD3D::getSwapBehavior() const
412 {
413     return EGL_BUFFER_PRESERVED;
414 }
415 
querySurfacePointerANGLE(EGLint attribute,void ** value)416 egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value)
417 {
418     if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
419     {
420         *value = mSwapChain->getShareHandle();
421     }
422     else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE)
423     {
424         *value = mSwapChain->getKeyedMutex();
425     }
426     else
427         UNREACHABLE();
428 
429     return egl::NoError();
430 }
431 
getD3DTextureColorFormat() const432 const angle::Format *SurfaceD3D::getD3DTextureColorFormat() const
433 {
434     return mColorFormat;
435 }
436 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)437 egl::Error SurfaceD3D::attachToFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer)
438 {
439     return egl::NoError();
440 }
441 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)442 egl::Error SurfaceD3D::detachFromFramebuffer(const gl::Context *context,
443                                              gl::Framebuffer *framebuffer)
444 {
445     return egl::NoError();
446 }
447 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)448 angle::Result SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context,
449                                                     GLenum binding,
450                                                     const gl::ImageIndex &imageIndex,
451                                                     GLsizei samples,
452                                                     FramebufferAttachmentRenderTarget **rtOut)
453 {
454     if (binding == GL_BACK)
455     {
456         *rtOut = mSwapChain->getColorRenderTarget();
457     }
458     else
459     {
460         *rtOut = mSwapChain->getDepthStencilRenderTarget();
461     }
462     return angle::Result::Continue;
463 }
464 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)465 angle::Result SurfaceD3D::initializeContents(const gl::Context *context,
466                                              GLenum binding,
467                                              const gl::ImageIndex &imageIndex)
468 {
469     switch (binding)
470     {
471         case GL_BACK:
472             ASSERT(mState.config->renderTargetFormat != GL_NONE);
473             ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getColorRenderTarget()));
474             break;
475 
476         case GL_DEPTH:
477         case GL_STENCIL:
478             ASSERT(mState.config->depthStencilFormat != GL_NONE);
479             ANGLE_TRY(
480                 mRenderer->initRenderTarget(context, mSwapChain->getDepthStencilRenderTarget()));
481             break;
482 
483         default:
484             UNREACHABLE();
485             break;
486     }
487     return angle::Result::Continue;
488 }
489 
WindowSurfaceD3D(const egl::SurfaceState & state,RendererD3D * renderer,egl::Display * display,EGLNativeWindowType window,const egl::AttributeMap & attribs)490 WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state,
491                                    RendererD3D *renderer,
492                                    egl::Display *display,
493                                    EGLNativeWindowType window,
494                                    const egl::AttributeMap &attribs)
495     : SurfaceD3D(state, renderer, display, window, 0, static_cast<EGLClientBuffer>(0), attribs)
496 {}
497 
~WindowSurfaceD3D()498 WindowSurfaceD3D::~WindowSurfaceD3D() {}
499 
PbufferSurfaceD3D(const egl::SurfaceState & state,RendererD3D * renderer,egl::Display * display,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)500 PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state,
501                                      RendererD3D *renderer,
502                                      egl::Display *display,
503                                      EGLenum buftype,
504                                      EGLClientBuffer clientBuffer,
505                                      const egl::AttributeMap &attribs)
506     : SurfaceD3D(state,
507                  renderer,
508                  display,
509                  static_cast<EGLNativeWindowType>(0),
510                  buftype,
511                  clientBuffer,
512                  attribs)
513 {}
514 
~PbufferSurfaceD3D()515 PbufferSurfaceD3D::~PbufferSurfaceD3D() {}
516 
517 }  // namespace rx
518