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