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/d3d11/formatutils11.h"
13 #include "libANGLE/renderer/d3d/d3d9/formatutils9.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