• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // D3DTextureSurfaceWGL.cpp: WGL implementation of egl::Surface for D3D texture interop.
8 
9 #include "libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h"
10 
11 #include "libANGLE/Surface.h"
12 #include "libANGLE/renderer/d3d_format.h"
13 #include "libANGLE/renderer/dxgi_format_map.h"
14 #include "libANGLE/renderer/gl/FramebufferGL.h"
15 #include "libANGLE/renderer/gl/RendererGL.h"
16 #include "libANGLE/renderer/gl/StateManagerGL.h"
17 #include "libANGLE/renderer/gl/TextureGL.h"
18 #include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
19 #include "libANGLE/renderer/gl/wgl/FunctionsWGL.h"
20 
21 namespace rx
22 {
23 
24 namespace
25 {
26 
GetD3D11TextureInfo(EGLenum buftype,ID3D11Texture2D * texture11,size_t * width,size_t * height,const angle::Format ** angleFormat,IUnknown ** object,IUnknown ** device)27 egl::Error GetD3D11TextureInfo(EGLenum buftype,
28                                ID3D11Texture2D *texture11,
29                                size_t *width,
30                                size_t *height,
31                                const angle::Format **angleFormat,
32                                IUnknown **object,
33                                IUnknown **device)
34 {
35     D3D11_TEXTURE2D_DESC textureDesc;
36     texture11->GetDesc(&textureDesc);
37 
38     if (buftype == EGL_D3D_TEXTURE_ANGLE)
39     {
40         // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
41         switch (textureDesc.Format)
42         {
43             case DXGI_FORMAT_R8G8B8A8_UNORM:
44             case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
45             case DXGI_FORMAT_B8G8R8A8_UNORM:
46             case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
47             case DXGI_FORMAT_R16G16B16A16_FLOAT:
48             case DXGI_FORMAT_R32G32B32A32_FLOAT:
49                 break;
50 
51             default:
52                 SafeRelease(texture11);
53                 return egl::EglBadParameter()
54                        << "Unknown client buffer texture format: " << textureDesc.Format;
55         }
56     }
57 
58     ID3D11Device *d3d11Device = nullptr;
59     texture11->GetDevice(&d3d11Device);
60     if (d3d11Device == nullptr)
61     {
62         SafeRelease(texture11);
63         return egl::EglBadParameter() << "Could not query the D3D11 device from the client buffer.";
64     }
65 
66     if (angleFormat)
67     {
68         *angleFormat = &d3d11_angle::GetFormat(textureDesc.Format);
69     }
70 
71     if (width)
72     {
73         *width = textureDesc.Width;
74     }
75     if (height)
76     {
77         *height = textureDesc.Height;
78     }
79 
80     if (device)
81     {
82         *device = d3d11Device;
83     }
84     else
85     {
86         SafeRelease(d3d11Device);
87     }
88 
89     if (object)
90     {
91         *object = texture11;
92     }
93     else
94     {
95         SafeRelease(texture11);
96     }
97 
98     return egl::NoError();
99 }
100 
GetD3D9TextureInfo(EGLenum buftype,IDirect3DTexture9 * texture9,size_t * width,size_t * height,const angle::Format ** angleFormat,IUnknown ** object,IUnknown ** device)101 egl::Error GetD3D9TextureInfo(EGLenum buftype,
102                               IDirect3DTexture9 *texture9,
103                               size_t *width,
104                               size_t *height,
105                               const angle::Format **angleFormat,
106                               IUnknown **object,
107                               IUnknown **device)
108 {
109     D3DSURFACE_DESC surfaceDesc;
110     if (FAILED(texture9->GetLevelDesc(0, &surfaceDesc)))
111     {
112         SafeRelease(texture9);
113         return egl::EglBadParameter() << "Could not query description of the D3D9 surface.";
114     }
115 
116     if (buftype == EGL_D3D_TEXTURE_ANGLE)
117     {
118         // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
119         switch (surfaceDesc.Format)
120         {
121             case D3DFMT_R8G8B8:
122             case D3DFMT_A8R8G8B8:
123             case D3DFMT_A16B16G16R16F:
124             case D3DFMT_A32B32G32R32F:
125                 break;
126 
127             default:
128                 SafeRelease(texture9);
129                 return egl::EglBadParameter()
130                        << "Unknown client buffer texture format: " << surfaceDesc.Format;
131         }
132     }
133 
134     if (angleFormat)
135     {
136         const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(surfaceDesc.Format);
137         ASSERT(d3dFormatInfo.info().id != angle::FormatID::NONE);
138         *angleFormat = &d3dFormatInfo.info();
139     }
140 
141     if (width)
142     {
143         *width = surfaceDesc.Width;
144     }
145     if (height)
146     {
147         *height = surfaceDesc.Height;
148     }
149 
150     IDirect3DDevice9 *d3d9Device = nullptr;
151     HRESULT result               = texture9->GetDevice(&d3d9Device);
152     if (FAILED(result))
153     {
154         SafeRelease(texture9);
155         return egl::EglBadParameter() << "Could not query the D3D9 device from the client buffer.";
156     }
157 
158     if (device)
159     {
160         *device = d3d9Device;
161     }
162     else
163     {
164         SafeRelease(d3d9Device);
165     }
166 
167     if (object)
168     {
169         *object = texture9;
170     }
171     else
172     {
173         SafeRelease(texture9);
174     }
175 
176     return egl::NoError();
177 }
178 
GetD3DTextureInfo(EGLenum buftype,EGLClientBuffer clientBuffer,ID3D11Device * d3d11Device,ID3D11Device1 * d3d11Device1,size_t * width,size_t * height,const angle::Format ** angleFormat,IUnknown ** object,IUnknown ** device)179 egl::Error GetD3DTextureInfo(EGLenum buftype,
180                              EGLClientBuffer clientBuffer,
181                              ID3D11Device *d3d11Device,
182                              ID3D11Device1 *d3d11Device1,
183                              size_t *width,
184                              size_t *height,
185                              const angle::Format **angleFormat,
186                              IUnknown **object,
187                              IUnknown **device)
188 {
189     if (buftype == EGL_D3D_TEXTURE_ANGLE)
190     {
191         IUnknown *buffer            = static_cast<IUnknown *>(clientBuffer);
192         ID3D11Texture2D *texture11  = nullptr;
193         IDirect3DTexture9 *texture9 = nullptr;
194         if (SUCCEEDED(buffer->QueryInterface<ID3D11Texture2D>(&texture11)))
195         {
196             return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object,
197                                        device);
198         }
199         else if (SUCCEEDED(buffer->QueryInterface<IDirect3DTexture9>(&texture9)))
200         {
201             return GetD3D9TextureInfo(buftype, texture9, width, height, angleFormat, object,
202                                       device);
203         }
204         else
205         {
206             return egl::EglBadParameter()
207                    << "Provided buffer is not a IDirect3DTexture9 or ID3D11Texture2D.";
208         }
209     }
210     else if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
211     {
212         ASSERT(d3d11Device);
213         HANDLE shareHandle         = static_cast<HANDLE>(clientBuffer);
214         ID3D11Texture2D *texture11 = nullptr;
215         HRESULT result = d3d11Device->OpenSharedResource(shareHandle, __uuidof(ID3D11Texture2D),
216                                                          reinterpret_cast<void **>(&texture11));
217         if (FAILED(result) && d3d11Device1)
218         {
219             result = d3d11Device1->OpenSharedResource1(shareHandle, __uuidof(ID3D11Texture2D),
220                                                        reinterpret_cast<void **>(&texture11));
221         }
222 
223         if (FAILED(result))
224         {
225             return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result);
226         }
227 
228         return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object, device);
229     }
230     else
231     {
232         UNREACHABLE();
233         return egl::EglBadDisplay() << "Unknown buftype for D3DTextureSurfaceWGL.";
234     }
235 }
236 
237 }  // anonymous namespace
238 
D3DTextureSurfaceWGL(const egl::SurfaceState & state,StateManagerGL * stateManager,EGLenum buftype,EGLClientBuffer clientBuffer,DisplayWGL * display,HDC deviceContext,ID3D11Device * displayD3D11Device,ID3D11Device1 * displayD3D11Device1,const FunctionsGL * functionsGL,const FunctionsWGL * functionsWGL)239 D3DTextureSurfaceWGL::D3DTextureSurfaceWGL(const egl::SurfaceState &state,
240                                            StateManagerGL *stateManager,
241                                            EGLenum buftype,
242                                            EGLClientBuffer clientBuffer,
243                                            DisplayWGL *display,
244                                            HDC deviceContext,
245                                            ID3D11Device *displayD3D11Device,
246                                            ID3D11Device1 *displayD3D11Device1,
247                                            const FunctionsGL *functionsGL,
248                                            const FunctionsWGL *functionsWGL)
249     : SurfaceWGL(state),
250       mBuftype(buftype),
251       mClientBuffer(clientBuffer),
252       mDisplayD3D11Device(displayD3D11Device),
253       mDisplayD3D11Device1(displayD3D11Device1),
254       mDisplay(display),
255       mStateManager(stateManager),
256       mFunctionsGL(functionsGL),
257       mFunctionsWGL(functionsWGL),
258       mDeviceContext(deviceContext),
259       mWidth(0),
260       mHeight(0),
261       mColorFormat(nullptr),
262       mDeviceHandle(nullptr),
263       mObject(nullptr),
264       mKeyedMutex(nullptr),
265       mBoundObjectTextureHandle(nullptr),
266       mBoundObjectRenderbufferHandle(nullptr),
267       mFramebufferID(0),
268       mColorRenderbufferID(0),
269       mDepthStencilRenderbufferID(0)
270 {}
271 
~D3DTextureSurfaceWGL()272 D3DTextureSurfaceWGL::~D3DTextureSurfaceWGL()
273 {
274     ASSERT(mBoundObjectTextureHandle == nullptr);
275 
276     SafeRelease(mObject);
277     SafeRelease(mKeyedMutex);
278 
279     if (mDeviceHandle)
280     {
281         if (mBoundObjectRenderbufferHandle)
282         {
283             mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectRenderbufferHandle);
284             mBoundObjectRenderbufferHandle = nullptr;
285         }
286         mStateManager->deleteRenderbuffer(mColorRenderbufferID);
287         mStateManager->deleteRenderbuffer(mDepthStencilRenderbufferID);
288         mStateManager->deleteFramebuffer(mFramebufferID);
289 
290         if (mBoundObjectTextureHandle)
291         {
292             mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle);
293             mBoundObjectTextureHandle = nullptr;
294         }
295 
296         mDisplay->releaseD3DDevice(mDeviceHandle);
297         mDeviceHandle = nullptr;
298     }
299 }
300 
ValidateD3DTextureClientBuffer(EGLenum buftype,EGLClientBuffer clientBuffer,ID3D11Device * d3d11Device,ID3D11Device1 * d3d11Device1)301 egl::Error D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(EGLenum buftype,
302                                                                 EGLClientBuffer clientBuffer,
303                                                                 ID3D11Device *d3d11Device,
304                                                                 ID3D11Device1 *d3d11Device1)
305 {
306     return GetD3DTextureInfo(buftype, clientBuffer, d3d11Device, d3d11Device1, nullptr, nullptr,
307                              nullptr, nullptr, nullptr);
308 }
309 
initialize(const egl::Display * display)310 egl::Error D3DTextureSurfaceWGL::initialize(const egl::Display *display)
311 {
312     IUnknown *device = nullptr;
313     ANGLE_TRY(GetD3DTextureInfo(mBuftype, mClientBuffer, mDisplayD3D11Device, mDisplayD3D11Device1,
314                                 &mWidth, &mHeight, &mColorFormat, &mObject, &device));
315 
316     if (mColorFormat)
317     {
318         if (mState.attributes.contains(EGL_GL_COLORSPACE))
319         {
320             if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS &&
321                 mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS)
322             {
323                 return egl::EglBadMatch()
324                        << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures";
325             }
326         }
327     }
328 
329     // Grab the keyed mutex, if one exists
330     mObject->QueryInterface(&mKeyedMutex);
331 
332     ASSERT(device != nullptr);
333     egl::Error error = mDisplay->registerD3DDevice(device, &mDeviceHandle);
334     SafeRelease(device);
335     if (error.isError())
336     {
337         return error;
338     }
339 
340     mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID);
341     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID);
342     mBoundObjectRenderbufferHandle = mFunctionsWGL->dxRegisterObjectNV(
343         mDeviceHandle, mObject, mColorRenderbufferID, GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
344     if (mBoundObjectRenderbufferHandle == nullptr)
345     {
346         return egl::EglBadAlloc() << "Failed to register D3D object, "
347                                   << gl::FmtErr(HRESULT_CODE(GetLastError()));
348     }
349 
350     const egl::Config *config = mState.config;
351     if (config->depthStencilFormat != GL_NONE)
352     {
353         mFunctionsGL->genRenderbuffers(1, &mDepthStencilRenderbufferID);
354         mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthStencilRenderbufferID);
355         mFunctionsGL->renderbufferStorage(GL_RENDERBUFFER, config->depthStencilFormat,
356                                           static_cast<GLsizei>(mWidth),
357                                           static_cast<GLsizei>(mHeight));
358     }
359 
360     return egl::NoError();
361 }
362 
makeCurrent(const gl::Context * context)363 egl::Error D3DTextureSurfaceWGL::makeCurrent(const gl::Context *context)
364 {
365     if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle))
366     {
367         DWORD error = GetLastError();
368         return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error));
369     }
370 
371     return egl::NoError();
372 }
373 
unMakeCurrent(const gl::Context * context)374 egl::Error D3DTextureSurfaceWGL::unMakeCurrent(const gl::Context *context)
375 {
376     if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle))
377     {
378         DWORD error = GetLastError();
379         return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error));
380     }
381 
382     return egl::NoError();
383 }
384 
swap(const gl::Context * context)385 egl::Error D3DTextureSurfaceWGL::swap(const gl::Context *context)
386 {
387     return egl::NoError();
388 }
389 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)390 egl::Error D3DTextureSurfaceWGL::postSubBuffer(const gl::Context *context,
391                                                EGLint x,
392                                                EGLint y,
393                                                EGLint width,
394                                                EGLint height)
395 {
396     UNIMPLEMENTED();
397     return egl::NoError();
398 }
399 
querySurfacePointerANGLE(EGLint attribute,void ** value)400 egl::Error D3DTextureSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value)
401 {
402     switch (attribute)
403     {
404         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
405             *value = (mBuftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) ? mClientBuffer : nullptr;
406             break;
407 
408         case EGL_DXGI_KEYED_MUTEX_ANGLE:
409             *value = mKeyedMutex;
410             break;
411 
412         default:
413             UNREACHABLE();
414     }
415 
416     return egl::NoError();
417 }
418 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)419 egl::Error D3DTextureSurfaceWGL::bindTexImage(const gl::Context *context,
420                                               gl::Texture *texture,
421                                               EGLint buffer)
422 {
423     ASSERT(mBoundObjectTextureHandle == nullptr);
424 
425     const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
426     GLuint textureID           = textureGL->getTextureID();
427 
428     mBoundObjectTextureHandle = mFunctionsWGL->dxRegisterObjectNV(
429         mDeviceHandle, mObject, textureID, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
430     if (mBoundObjectTextureHandle == nullptr)
431     {
432         DWORD error = GetLastError();
433         return egl::EglBadAlloc() << "Failed to register D3D object, "
434                                   << gl::FmtErr(HRESULT_CODE(error));
435     }
436 
437     if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle))
438     {
439         DWORD error = GetLastError();
440         return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error));
441     }
442 
443     return egl::NoError();
444 }
445 
releaseTexImage(const gl::Context * context,EGLint buffer)446 egl::Error D3DTextureSurfaceWGL::releaseTexImage(const gl::Context *context, EGLint buffer)
447 {
448     ASSERT(mBoundObjectTextureHandle != nullptr);
449     if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle))
450     {
451         DWORD error = GetLastError();
452         return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error));
453     }
454 
455     if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle))
456     {
457         DWORD error = GetLastError();
458         return egl::EglBadAlloc() << "Failed to unregister D3D object, "
459                                   << gl::FmtErr(HRESULT_CODE(error));
460     }
461     mBoundObjectTextureHandle = nullptr;
462 
463     return egl::NoError();
464 }
465 
setSwapInterval(EGLint interval)466 void D3DTextureSurfaceWGL::setSwapInterval(EGLint interval)
467 {
468     UNIMPLEMENTED();
469 }
470 
getWidth() const471 EGLint D3DTextureSurfaceWGL::getWidth() const
472 {
473     return static_cast<EGLint>(mWidth);
474 }
475 
getHeight() const476 EGLint D3DTextureSurfaceWGL::getHeight() const
477 {
478     return static_cast<EGLint>(mHeight);
479 }
480 
isPostSubBufferSupported() const481 EGLint D3DTextureSurfaceWGL::isPostSubBufferSupported() const
482 {
483     return EGL_FALSE;
484 }
485 
getSwapBehavior() const486 EGLint D3DTextureSurfaceWGL::getSwapBehavior() const
487 {
488     return EGL_BUFFER_PRESERVED;
489 }
490 
getDC() const491 HDC D3DTextureSurfaceWGL::getDC() const
492 {
493     return mDeviceContext;
494 }
495 
getD3DTextureColorFormat() const496 const angle::Format *D3DTextureSurfaceWGL::getD3DTextureColorFormat() const
497 {
498     return mColorFormat;
499 }
500 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)501 egl::Error D3DTextureSurfaceWGL::attachToFramebuffer(const gl::Context *context,
502                                                      gl::Framebuffer *framebuffer)
503 {
504     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
505     ASSERT(framebufferGL->getFramebufferID() == 0);
506     if (mFramebufferID == 0)
507     {
508         GLuint framebufferID = 0;
509         mFunctionsGL->genFramebuffers(1, &framebufferID);
510         mStateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferID);
511         mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
512                                               mColorRenderbufferID);
513         if (mState.config->depthSize > 0)
514         {
515             mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
516                                                   GL_RENDERBUFFER, mDepthStencilRenderbufferID);
517         }
518         if (mState.config->stencilSize > 0)
519         {
520             mFunctionsGL->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
521                                                   GL_RENDERBUFFER, mDepthStencilRenderbufferID);
522         }
523         mFramebufferID = framebufferID;
524     }
525     framebufferGL->setFramebufferID(mFramebufferID);
526     return egl::NoError();
527 }
528 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)529 egl::Error D3DTextureSurfaceWGL::detachFromFramebuffer(const gl::Context *context,
530                                                        gl::Framebuffer *framebuffer)
531 {
532     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
533     ASSERT(framebufferGL->getFramebufferID() == mFramebufferID);
534     framebufferGL->setFramebufferID(0);
535     return egl::NoError();
536 }
537 
538 }  // namespace rx
539