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