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