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,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                              size_t *width,
183                              size_t *height,
184                              const angle::Format **angleFormat,
185                              IUnknown **object,
186                              IUnknown **device)
187 {
188     if (buftype == EGL_D3D_TEXTURE_ANGLE)
189     {
190         IUnknown *buffer            = static_cast<IUnknown *>(clientBuffer);
191         ID3D11Texture2D *texture11  = nullptr;
192         IDirect3DTexture9 *texture9 = nullptr;
193         if (SUCCEEDED(buffer->QueryInterface<ID3D11Texture2D>(&texture11)))
194         {
195             return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object,
196                                        device);
197         }
198         else if (SUCCEEDED(buffer->QueryInterface<IDirect3DTexture9>(&texture9)))
199         {
200             return GetD3D9TextureInfo(buftype, texture9, width, height, angleFormat, object,
201                                       device);
202         }
203         else
204         {
205             return egl::EglBadParameter()
206                    << "Provided buffer is not a IDirect3DTexture9 or ID3D11Texture2D.";
207         }
208     }
209     else if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
210     {
211         ASSERT(d3d11Device);
212         HANDLE shareHandle         = static_cast<HANDLE>(clientBuffer);
213         ID3D11Texture2D *texture11 = nullptr;
214         HRESULT result = d3d11Device->OpenSharedResource(shareHandle, __uuidof(ID3D11Texture2D),
215                                                          reinterpret_cast<void **>(&texture11));
216         if (FAILED(result))
217         {
218             return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result);
219         }
220 
221         return GetD3D11TextureInfo(buftype, texture11, width, height, angleFormat, object, device);
222     }
223     else
224     {
225         UNREACHABLE();
226         return egl::EglBadDisplay() << "Unknown buftype for D3DTextureSurfaceWGL.";
227     }
228 }
229 
230 }  // anonymous namespace
231 
D3DTextureSurfaceWGL(const egl::SurfaceState & state,StateManagerGL * stateManager,EGLenum buftype,EGLClientBuffer clientBuffer,DisplayWGL * display,HDC deviceContext,ID3D11Device * displayD3D11Device,const FunctionsGL * functionsGL,const FunctionsWGL * functionsWGL)232 D3DTextureSurfaceWGL::D3DTextureSurfaceWGL(const egl::SurfaceState &state,
233                                            StateManagerGL *stateManager,
234                                            EGLenum buftype,
235                                            EGLClientBuffer clientBuffer,
236                                            DisplayWGL *display,
237                                            HDC deviceContext,
238                                            ID3D11Device *displayD3D11Device,
239                                            const FunctionsGL *functionsGL,
240                                            const FunctionsWGL *functionsWGL)
241     : SurfaceWGL(state),
242       mBuftype(buftype),
243       mClientBuffer(clientBuffer),
244       mDisplayD3D11Device(displayD3D11Device),
245       mDisplay(display),
246       mStateManager(stateManager),
247       mFunctionsGL(functionsGL),
248       mFunctionsWGL(functionsWGL),
249       mDeviceContext(deviceContext),
250       mWidth(0),
251       mHeight(0),
252       mColorFormat(nullptr),
253       mDeviceHandle(nullptr),
254       mObject(nullptr),
255       mKeyedMutex(nullptr),
256       mBoundObjectTextureHandle(nullptr),
257       mBoundObjectRenderbufferHandle(nullptr),
258       mColorRenderbufferID(0),
259       mDepthStencilRenderbufferID(0)
260 {}
261 
~D3DTextureSurfaceWGL()262 D3DTextureSurfaceWGL::~D3DTextureSurfaceWGL()
263 {
264     ASSERT(mBoundObjectTextureHandle == nullptr);
265 
266     SafeRelease(mObject);
267     SafeRelease(mKeyedMutex);
268 
269     if (mDeviceHandle)
270     {
271         if (mBoundObjectRenderbufferHandle)
272         {
273             mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectRenderbufferHandle);
274             mBoundObjectRenderbufferHandle = nullptr;
275         }
276         mStateManager->deleteRenderbuffer(mColorRenderbufferID);
277         mStateManager->deleteRenderbuffer(mDepthStencilRenderbufferID);
278 
279         if (mBoundObjectTextureHandle)
280         {
281             mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle);
282             mBoundObjectTextureHandle = nullptr;
283         }
284 
285         mDisplay->releaseD3DDevice(mDeviceHandle);
286         mDeviceHandle = nullptr;
287     }
288 }
289 
ValidateD3DTextureClientBuffer(EGLenum buftype,EGLClientBuffer clientBuffer,ID3D11Device * d3d11Device)290 egl::Error D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(EGLenum buftype,
291                                                                 EGLClientBuffer clientBuffer,
292                                                                 ID3D11Device *d3d11Device)
293 {
294     return GetD3DTextureInfo(buftype, clientBuffer, d3d11Device, nullptr, nullptr, nullptr, nullptr,
295                              nullptr);
296 }
297 
initialize(const egl::Display * display)298 egl::Error D3DTextureSurfaceWGL::initialize(const egl::Display *display)
299 {
300     IUnknown *device = nullptr;
301     ANGLE_TRY(GetD3DTextureInfo(mBuftype, mClientBuffer, mDisplayD3D11Device, &mWidth, &mHeight,
302                                 &mColorFormat, &mObject, &device));
303 
304     if (mColorFormat)
305     {
306         if (mState.attributes.contains(EGL_GL_COLORSPACE))
307         {
308             if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS &&
309                 mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS)
310             {
311                 return egl::EglBadMatch()
312                        << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures";
313             }
314         }
315     }
316 
317     // Grab the keyed mutex, if one exists
318     mObject->QueryInterface(&mKeyedMutex);
319 
320     ASSERT(device != nullptr);
321     egl::Error error = mDisplay->registerD3DDevice(device, &mDeviceHandle);
322     SafeRelease(device);
323     if (error.isError())
324     {
325         return error;
326     }
327 
328     mFunctionsGL->genRenderbuffers(1, &mColorRenderbufferID);
329     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbufferID);
330     mBoundObjectRenderbufferHandle = mFunctionsWGL->dxRegisterObjectNV(
331         mDeviceHandle, mObject, mColorRenderbufferID, GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
332     if (mBoundObjectRenderbufferHandle == nullptr)
333     {
334         return egl::EglBadAlloc() << "Failed to register D3D object, "
335                                   << gl::FmtErr(HRESULT_CODE(GetLastError()));
336     }
337 
338     const egl::Config *config = mState.config;
339     if (config->depthStencilFormat != GL_NONE)
340     {
341         mFunctionsGL->genRenderbuffers(1, &mDepthStencilRenderbufferID);
342         mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDepthStencilRenderbufferID);
343         mFunctionsGL->renderbufferStorage(GL_RENDERBUFFER, config->depthStencilFormat,
344                                           static_cast<GLsizei>(mWidth),
345                                           static_cast<GLsizei>(mHeight));
346     }
347 
348     return egl::NoError();
349 }
350 
makeCurrent(const gl::Context * context)351 egl::Error D3DTextureSurfaceWGL::makeCurrent(const gl::Context *context)
352 {
353     if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle))
354     {
355         DWORD error = GetLastError();
356         return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error));
357     }
358 
359     return egl::NoError();
360 }
361 
unMakeCurrent(const gl::Context * context)362 egl::Error D3DTextureSurfaceWGL::unMakeCurrent(const gl::Context *context)
363 {
364     if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectRenderbufferHandle))
365     {
366         DWORD error = GetLastError();
367         return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error));
368     }
369 
370     return egl::NoError();
371 }
372 
swap(const gl::Context * context)373 egl::Error D3DTextureSurfaceWGL::swap(const gl::Context *context)
374 {
375     return egl::NoError();
376 }
377 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)378 egl::Error D3DTextureSurfaceWGL::postSubBuffer(const gl::Context *context,
379                                                EGLint x,
380                                                EGLint y,
381                                                EGLint width,
382                                                EGLint height)
383 {
384     UNIMPLEMENTED();
385     return egl::NoError();
386 }
387 
querySurfacePointerANGLE(EGLint attribute,void ** value)388 egl::Error D3DTextureSurfaceWGL::querySurfacePointerANGLE(EGLint attribute, void **value)
389 {
390     switch (attribute)
391     {
392         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
393             *value = (mBuftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) ? mClientBuffer : nullptr;
394             break;
395 
396         case EGL_DXGI_KEYED_MUTEX_ANGLE:
397             *value = mKeyedMutex;
398             break;
399 
400         default:
401             UNREACHABLE();
402     }
403 
404     return egl::NoError();
405 }
406 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)407 egl::Error D3DTextureSurfaceWGL::bindTexImage(const gl::Context *context,
408                                               gl::Texture *texture,
409                                               EGLint buffer)
410 {
411     ASSERT(mBoundObjectTextureHandle == nullptr);
412 
413     const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
414     GLuint textureID           = textureGL->getTextureID();
415 
416     mBoundObjectTextureHandle = mFunctionsWGL->dxRegisterObjectNV(
417         mDeviceHandle, mObject, textureID, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV);
418     if (mBoundObjectTextureHandle == nullptr)
419     {
420         DWORD error = GetLastError();
421         return egl::EglBadAlloc() << "Failed to register D3D object, "
422                                   << gl::FmtErr(HRESULT_CODE(error));
423     }
424 
425     if (!mFunctionsWGL->dxLockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle))
426     {
427         DWORD error = GetLastError();
428         return egl::EglBadAlloc() << "Failed to lock object, " << gl::FmtErr(HRESULT_CODE(error));
429     }
430 
431     return egl::NoError();
432 }
433 
releaseTexImage(const gl::Context * context,EGLint buffer)434 egl::Error D3DTextureSurfaceWGL::releaseTexImage(const gl::Context *context, EGLint buffer)
435 {
436     ASSERT(mBoundObjectTextureHandle != nullptr);
437     if (!mFunctionsWGL->dxUnlockObjectsNV(mDeviceHandle, 1, &mBoundObjectTextureHandle))
438     {
439         DWORD error = GetLastError();
440         return egl::EglBadAlloc() << "Failed to unlock object, " << gl::FmtErr(HRESULT_CODE(error));
441     }
442 
443     if (!mFunctionsWGL->dxUnregisterObjectNV(mDeviceHandle, mBoundObjectTextureHandle))
444     {
445         DWORD error = GetLastError();
446         return egl::EglBadAlloc() << "Failed to unregister D3D object, "
447                                   << gl::FmtErr(HRESULT_CODE(error));
448     }
449     mBoundObjectTextureHandle = nullptr;
450 
451     return egl::NoError();
452 }
453 
setSwapInterval(EGLint interval)454 void D3DTextureSurfaceWGL::setSwapInterval(EGLint interval)
455 {
456     UNIMPLEMENTED();
457 }
458 
getWidth() const459 EGLint D3DTextureSurfaceWGL::getWidth() const
460 {
461     return static_cast<EGLint>(mWidth);
462 }
463 
getHeight() const464 EGLint D3DTextureSurfaceWGL::getHeight() const
465 {
466     return static_cast<EGLint>(mHeight);
467 }
468 
isPostSubBufferSupported() const469 EGLint D3DTextureSurfaceWGL::isPostSubBufferSupported() const
470 {
471     return EGL_FALSE;
472 }
473 
getSwapBehavior() const474 EGLint D3DTextureSurfaceWGL::getSwapBehavior() const
475 {
476     return EGL_BUFFER_PRESERVED;
477 }
478 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & data)479 FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::Context *context,
480                                                                 const gl::FramebufferState &data)
481 {
482     const FunctionsGL *functions = GetFunctionsGL(context);
483     StateManagerGL *stateManager = GetStateManagerGL(context);
484 
485     GLuint framebufferID = 0;
486     functions->genFramebuffers(1, &framebufferID);
487     stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferID);
488     functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
489                                        mColorRenderbufferID);
490     if (mState.config->depthSize > 0)
491     {
492         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
493                                            mDepthStencilRenderbufferID);
494     }
495     if (mState.config->stencilSize > 0)
496     {
497         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
498                                            mDepthStencilRenderbufferID);
499     }
500 
501     return new FramebufferGL(data, framebufferID, true, false);
502 }
503 
getDC() const504 HDC D3DTextureSurfaceWGL::getDC() const
505 {
506     return mDeviceContext;
507 }
508 
getD3DTextureColorFormat() const509 const angle::Format *D3DTextureSurfaceWGL::getD3DTextureColorFormat() const
510 {
511     return mColorFormat;
512 }
513 
514 }  // namespace rx
515