Blender  V2.93
GHOST_ContextD3D.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
24 #include <iostream>
25 #include <string>
26 
27 #include <GL/glew.h>
28 #include <GL/wglew.h>
29 
30 #include "GHOST_ContextD3D.h"
31 #include "GHOST_ContextWGL.h" /* For shared drawing */
32 
33 HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
34 PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;
35 
36 GHOST_ContextD3D::GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
37  : GHOST_Context(stereoVisual), m_hWnd(hWnd)
38 {
39 }
40 
42 {
43  m_device->Release();
44  m_device_ctx->ClearState();
45  m_device_ctx->Release();
46 }
47 
49 {
50  return GHOST_kSuccess;
51 }
52 
54 {
55  return GHOST_kFailure;
56 }
57 
59 {
60  return GHOST_kFailure;
61 }
62 
63 GHOST_TSuccess GHOST_ContextD3D::setupD3DLib()
64 {
65  if (s_d3d_lib == NULL) {
66  s_d3d_lib = LoadLibraryA("d3d11.dll");
67 
68  WIN32_CHK(s_d3d_lib != NULL);
69 
70  if (s_d3d_lib == NULL) {
71  fprintf(stderr, "LoadLibrary(\"d3d11.dll\") failed!\n");
72  return GHOST_kFailure;
73  }
74  }
75 
76  if (s_D3D11CreateDeviceFn == NULL) {
77  s_D3D11CreateDeviceFn = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(s_d3d_lib,
78  "D3D11CreateDevice");
79 
80  WIN32_CHK(s_D3D11CreateDeviceFn != NULL);
81 
82  if (s_D3D11CreateDeviceFn == NULL) {
83  fprintf(stderr, "GetProcAddress(s_d3d_lib, \"D3D11CreateDevice\") failed!\n");
84  return GHOST_kFailure;
85  }
86  }
87 
88  return GHOST_kSuccess;
89 }
90 
92 {
93  if (setupD3DLib() == GHOST_kFailure) {
94  return GHOST_kFailure;
95  }
96 
97  HRESULT hres = s_D3D11CreateDeviceFn(
98  NULL,
99  D3D_DRIVER_TYPE_HARDWARE,
100  NULL,
101  /* For debugging you may want to pass D3D11_CREATE_DEVICE_DEBUG here, but that requires
102  * additional setup, see
103  * https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer.
104  */
105  0,
106  NULL,
107  0,
108  D3D11_SDK_VERSION,
109  &m_device,
110  NULL,
111  &m_device_ctx);
112 
113  WIN32_CHK(hres == S_OK);
114 
115  return GHOST_kSuccess;
116 }
117 
119 {
120  return GHOST_kFailure;
121 }
122 
124  struct SharedData {
125  HANDLE device;
126  GLuint fbo;
127  HANDLE render_buf{nullptr};
128  } m_shared;
129 
130  public:
131  GHOST_SharedOpenGLResource(ID3D11Device *device,
132  ID3D11DeviceContext *device_ctx,
133  unsigned int width,
134  unsigned int height,
135  ID3D11RenderTargetView *render_target = nullptr)
136  : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height)
137  {
138  ID3D11Resource *backbuffer_res;
139 
140  if (!render_target) {
141  D3D11_TEXTURE2D_DESC texDesc{};
142  D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{};
143  ID3D11Texture2D *tex;
144 
145  texDesc.Width = width;
146  texDesc.Height = height;
147  texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
148  texDesc.SampleDesc.Count = 1;
149  texDesc.ArraySize = 1;
150  texDesc.MipLevels = 1;
151  texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
152 
153  device->CreateTexture2D(&texDesc, NULL, &tex);
154  if (!tex) {
155  /* If texture creation fails, we just return and leave the render target unset. So it needs
156  * to be NULL-checked before use. */
157  fprintf(stderr, "Error creating texture for shared DirectX-OpenGL resource\n");
158  return;
159  }
160 
161  renderTargetViewDesc.Format = texDesc.Format;
162  renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
163  renderTargetViewDesc.Texture2D.MipSlice = 0;
164 
165  device->CreateRenderTargetView(tex, &renderTargetViewDesc, &render_target);
166 
167  tex->Release();
168  }
169 
170  m_render_target = render_target;
171  if (m_render_target) {
172  m_render_target->GetResource(&backbuffer_res);
173  }
174  if (backbuffer_res) {
175  backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex);
176  backbuffer_res->Release();
177  }
178 
180  fprintf(stderr, "Error creating render target for shared DirectX-OpenGL resource\n");
181  return;
182  }
183  }
184 
186  {
187  if (m_render_target_tex) {
188  m_render_target_tex->Release();
189  }
190  if (m_render_target) {
191  m_render_target->Release();
192  }
193 
194  if (m_is_initialized) {
195  if (m_shared.render_buf) {
196  wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
197  }
198  if (m_shared.device) {
199  wglDXCloseDeviceNV(m_shared.device);
200  }
201  glDeleteFramebuffers(1, &m_shared.fbo);
202  glDeleteRenderbuffers(1, &m_gl_render_buf);
203  }
204  }
205 
207  {
208  if (m_shared.render_buf) {
209  wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
210  }
211 
212  if (!m_render_target_tex) {
213  return;
214  }
215 
216  m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
218  m_gl_render_buf,
219  GL_RENDERBUFFER,
220  WGL_ACCESS_READ_WRITE_NV);
221 
222  if (!m_shared.render_buf) {
223  fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
224  return;
225  }
226  }
227 
229  {
230  m_shared.device = wglDXOpenDeviceNV(m_device);
231  if (m_shared.device == NULL) {
232  fprintf(stderr, "Error opening shared device using wglDXOpenDeviceNV()\n");
233  return GHOST_kFailure;
234  }
235 
236  /* Build the renderbuffer. */
237  glGenRenderbuffers(1, &m_gl_render_buf);
238  glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
239 
241 
242  /* Build the framebuffer */
243  glGenFramebuffers(1, &m_shared.fbo);
244  glBindFramebuffer(GL_FRAMEBUFFER, m_shared.fbo);
245  glFramebufferRenderbuffer(
246  GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_buf);
247  m_is_initialized = true;
248 
249  return GHOST_kSuccess;
250  }
251 
252  void ensureUpdated(unsigned int width, unsigned int height)
253  {
254  if (m_is_initialized == false) {
255  initialize();
256  }
257 
258  if ((m_cur_width != width) || (m_cur_height != height)) {
259  m_cur_width = width;
260  m_cur_height = height;
262  }
263  }
264 
265  GHOST_TSuccess blit(unsigned int width, unsigned int height)
266  {
267  GLint fbo;
268  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
269 
271  return GHOST_kFailure;
272  }
273 
275 
276 #ifdef NDEBUG
277  const float clear_col[] = {0.8f, 0.5f, 1.0f, 1.0f};
278  m_device_ctx->ClearRenderTargetView(m_render_target, clear_col);
279 #endif
280  m_device_ctx->OMSetRenderTargets(1, &m_render_target, nullptr);
281 
282  beginGLOnly();
283 
284  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared.fbo);
285  GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
286  if (err != GL_FRAMEBUFFER_COMPLETE) {
287  fprintf(
288  stderr, "Error: Framebuffer for shared DirectX-OpenGL resource incomplete %u\n", err);
289  return GHOST_kFailure;
290  }
291 
292  /* No glBlitNamedFramebuffer, gotta be 3.3 compatible. */
293  glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
294  glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
295 
296  glBindFramebuffer(GL_FRAMEBUFFER, fbo);
297 
298  endGLOnly();
299 
300  return GHOST_kSuccess;
301  }
302 
303  ID3D11RenderTargetView *m_render_target{nullptr};
304  ID3D11Texture2D *m_render_target_tex{nullptr};
305 
306  private:
307  void beginGLOnly()
308  {
309  wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
310  }
311  void endGLOnly()
312  {
313  wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
314  }
315 
316  ID3D11Device *m_device;
317  ID3D11DeviceContext *m_device_ctx;
318  GLuint m_gl_render_buf;
319  unsigned int m_cur_width, m_cur_height;
320  bool m_is_initialized{false};
321 };
322 
324  unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target)
325 {
326  if (!(WGL_NV_DX_interop && WGL_NV_DX_interop2)) {
327  fprintf(stderr,
328  "Error: Can't render OpenGL framebuffer using Direct3D. NV_DX_interop extension not "
329  "available.");
330  return nullptr;
331  }
333  m_device, m_device_ctx, width, height, render_target);
334 
335  return shared_res;
336 }
338  unsigned int height)
339 {
340  return createSharedOpenGLResource(width, height, nullptr);
341 }
342 
344 {
345  delete shared_res;
346 }
347 
349  unsigned int width,
350  unsigned int height)
351 {
352  return shared_res->blit(width, height);
353 }
354 
356 {
357  return shared_res->m_render_target_tex;
358 }
@ DXGI_FORMAT_R8G8B8A8_UNORM
GHOST_TSuccess
Definition: GHOST_Types.h:91
@ GHOST_kFailure
Definition: GHOST_Types.h:91
@ GHOST_kSuccess
Definition: GHOST_Types.h:91
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
GHOST_TSuccess activateDrawingContext()
GHOST_TSuccess releaseNativeHandles()
class GHOST_SharedOpenGLResource * createSharedOpenGLResource(unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target)
GHOST_TSuccess swapBuffers()
GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
GHOST_TSuccess blitFromOpenGLContext(class GHOST_SharedOpenGLResource *shared_res, unsigned int width, unsigned int height)
ID3D11Texture2D * getSharedTexture2D(class GHOST_SharedOpenGLResource *shared_res)
GHOST_TSuccess initializeDrawingContext()
void disposeSharedOpenGLResource(class GHOST_SharedOpenGLResource *shared_res)
GHOST_TSuccess releaseDrawingContext()
void ensureUpdated(unsigned int width, unsigned int height)
GHOST_TSuccess blit(unsigned int width, unsigned int height)
GHOST_SharedOpenGLResource(ID3D11Device *device, ID3D11DeviceContext *device_ctx, unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target=nullptr)
ID3D11RenderTargetView * m_render_target
ID3D11Texture2D * m_render_target_tex
static FT_Error err
Definition: freetypefont.c:52