[Bf-blender-cvs] [3b1ef223bad] master: Ghost: Support drawing OpenGL framebuffers into a DirectX 11 buffer

Julian Eisel noreply at git.blender.org
Thu Mar 5 19:17:36 CET 2020


Commit: 3b1ef223bad5ba902bbb17cdc3686bfe807a6f50
Author: Julian Eisel
Date:   Thu Mar 5 18:29:29 2020 +0100
Branches: master
https://developer.blender.org/rB3b1ef223bad5ba902bbb17cdc3686bfe807a6f50

Ghost: Support drawing OpenGL framebuffers into a DirectX 11 buffer

Adds a minimal DirectX 11 Ghost context, plus some shared DirectX-OpenGL
resource interface using the NV_DX_interop2 WGL extension. From what I
know, this should be available on modern GPUs. If not, it should fail
gracefully.
There should be no user visible changes at this point.

Needed for DirectX-only OpenXR platforms (e.g. Windows Mixed Reality). I
heard there are other use-cases as well though.

It's known that this currently fails on some AMD systems, but that seems
to be fixable.

Most of this comes from the 2019 GSoC project, "Core Support of Virtual
Reality Headsets through OpenXR"
(https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).

Reviewed by: Jeroen Bakker, Ray Molenkam, Brecht van Lommel

Differential Revision: https://developer.blender.org/D6190

===================================================================

M	intern/ghost/CMakeLists.txt
M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_ISystem.h
M	intern/ghost/GHOST_Types.h
M	intern/ghost/intern/GHOST_C-api.cpp
A	intern/ghost/intern/GHOST_ContextD3D.cpp
A	intern/ghost/intern/GHOST_ContextD3D.h
M	intern/ghost/intern/GHOST_System.cpp
M	intern/ghost/intern/GHOST_System.h
M	intern/ghost/intern/GHOST_SystemWin32.cpp
M	intern/ghost/intern/GHOST_SystemWin32.h
M	intern/ghost/intern/GHOST_WindowWin32.cpp

===================================================================

diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index cc671e31f92..c4f1efe1580 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -280,11 +280,13 @@ elseif(WIN32)
   )
 
   list(APPEND SRC
+    intern/GHOST_ContextD3D.cpp
     intern/GHOST_DisplayManagerWin32.cpp
     intern/GHOST_DropTargetWin32.cpp
     intern/GHOST_SystemWin32.cpp
     intern/GHOST_WindowWin32.cpp
 
+    intern/GHOST_ContextD3D.h
     intern/GHOST_DisplayManagerWin32.h
     intern/GHOST_DropTargetWin32.h
     intern/GHOST_SystemWin32.h
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ba46a868df6..a3cc9aa1df5 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -229,6 +229,25 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
 extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
                                                  GHOST_ContextHandle contexthandle);
 
+#ifdef WIN32
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \param systemhandle The handle to the system
+ * \return A handle to the new context ( == NULL if creation failed).
+ */
+GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle);
+
+/**
+ * Dispose of a context.
+ * \param systemhandle The handle to the system
+ * \param contexthandle Handle to the context to be disposed.
+ * \return Indication of success.
+ */
+GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
+                                           GHOST_ContextHandle contexthandle);
+#endif
+
 /**
  * Returns the window user data.
  * \param windowhandle The handle to the window
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 4634eb1bc66..5d529141ca7 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -266,6 +266,12 @@ class GHOST_ISystem {
    */
   virtual GHOST_IContext *createOffscreenContext() = 0;
 
+  /**
+   * Overload to allow requesting a different context type. By default only OpenGL is supported.
+   * However by explicitly overloading this a system may add support for others.
+   */
+  virtual GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type) = 0;
+
   /**
    * Dispose of a context.
    * \param   context Pointer to the context to be disposed.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 98dd1de867f..38a6a0b04d2 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -140,7 +140,10 @@ typedef enum { GHOST_kWindowOrderTop = 0, GHOST_kWindowOrderBottom } GHOST_TWind
 
 typedef enum {
   GHOST_kDrawingContextTypeNone = 0,
-  GHOST_kDrawingContextTypeOpenGL
+  GHOST_kDrawingContextTypeOpenGL,
+#ifdef WIN32
+  GHOST_kDrawingContextTypeD3D,
+#endif
 } GHOST_TDrawingContextType;
 
 typedef enum {
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 3c3860bd2c0..9a7e3da828b 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -146,6 +146,25 @@ GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
   return system->disposeContext(context);
 }
 
+#ifdef WIN32
+GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle)
+{
+  GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+
+  return (GHOST_ContextHandle)system->createOffscreenContext(GHOST_kDrawingContextTypeD3D);
+}
+
+GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
+                                           GHOST_ContextHandle contexthandle)
+{
+  GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+  GHOST_IContext *context = (GHOST_IContext *)contexthandle;
+
+  return system->disposeContext(context);
+}
+
+#endif
+
 GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
                                       const char *title,
                                       GHOST_TInt32 left,
diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp
new file mode 100644
index 00000000000..ed65d499073
--- /dev/null
+++ b/intern/ghost/intern/GHOST_ContextD3D.cpp
@@ -0,0 +1,358 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ *
+ * For testing purposes, it can be useful to do some DirectX only drawing. A patch for this can be
+ * found here: https://developer.blender.org/P1284
+ */
+
+#include <iostream>
+#include <string>
+
+#include <GL/glew.h>
+#include <GL/wglew.h>
+
+#include "GHOST_ContextWGL.h" /* For shared drawing */
+#include "GHOST_ContextD3D.h"
+
+HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
+PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;
+
+GHOST_ContextD3D::GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
+    : GHOST_Context(stereoVisual), m_hWnd(hWnd)
+{
+}
+
+GHOST_ContextD3D::~GHOST_ContextD3D()
+{
+  m_device->Release();
+  m_device_ctx->ClearState();
+  m_device_ctx->Release();
+}
+
+GHOST_TSuccess GHOST_ContextD3D::swapBuffers()
+{
+  return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::activateDrawingContext()
+{
+  return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::releaseDrawingContext()
+{
+  return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::setupD3DLib()
+{
+  if (s_d3d_lib == NULL) {
+    s_d3d_lib = LoadLibraryA("d3d11.dll");
+
+    WIN32_CHK(s_d3d_lib != NULL);
+
+    if (s_d3d_lib == NULL) {
+      fprintf(stderr, "LoadLibrary(\"d3d11.dll\") failed!\n");
+      return GHOST_kFailure;
+    }
+  }
+
+  if (s_D3D11CreateDeviceFn == NULL) {
+    s_D3D11CreateDeviceFn = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(s_d3d_lib,
+                                                                    "D3D11CreateDevice");
+
+    WIN32_CHK(s_D3D11CreateDeviceFn != NULL);
+
+    if (s_D3D11CreateDeviceFn == NULL) {
+      fprintf(stderr, "GetProcAddress(s_d3d_lib, \"D3D11CreateDevice\") failed!\n");
+      return GHOST_kFailure;
+    }
+  }
+
+  return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::initializeDrawingContext()
+{
+  if (setupD3DLib() == GHOST_kFailure) {
+    return GHOST_kFailure;
+  }
+
+  HRESULT hres = s_D3D11CreateDeviceFn(
+      NULL,
+      D3D_DRIVER_TYPE_HARDWARE,
+      NULL,
+      /* For debugging you may want to pass D3D11_CREATE_DEVICE_DEBUG here, but that requires
+       * additional setup, see
+       * https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer.
+       */
+      0,
+      NULL,
+      0,
+      D3D11_SDK_VERSION,
+      &m_device,
+      NULL,
+      &m_device_ctx);
+
+  WIN32_CHK(hres == S_OK);
+
+  return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::releaseNativeHandles()
+{
+  return GHOST_kFailure;
+}
+
+class GHOST_SharedOpenGLResource {
+  struct SharedData {
+    HANDLE device;
+    GLuint fbo;
+    HANDLE render_buf{nullptr};
+  } m_shared;
+
+ public:
+  GHOST_SharedOpenGLResource(ID3D11Device *device,
+                             ID3D11DeviceContext *device_ctx,
+                             unsigned int width,
+                             unsigned int height,
+                             ID3D11RenderTargetView *render_target = nullptr)
+      : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height)
+  {
+    ID3D11Resource *backbuffer_res;
+
+    if (!render_target) {
+      D3D11_TEXTURE2D_DESC texDesc{};
+      D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{};
+      ID3D11Texture2D *tex;
+
+      texDesc.Width = width;
+      texDesc.Height = height;
+      texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+      texDesc.SampleDesc.Count = 1;
+      texDesc.ArraySize = 1;
+      texDesc.MipLevels = 1;
+      texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+
+      device->CreateTexture2D(&texDesc, NULL, &tex);
+      if (!tex) {
+        /* If texture creation fails, we just return and leave the render target unset. So it needs
+         * to be NULL-checked before use. */
+        fprintf(stderr, "Error creating texture for shared DirectX-OpenGL resource\n");
+        return;
+      }
+
+      renderTargetViewDesc.Format = texDesc.Format;
+      renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+      renderTargetViewDesc.Texture2D.MipSlice = 0;
+
+      device->CreateRenderTargetView(tex, &renderTargetViewDesc, &render_target);
+
+      tex->Release();
+    }
+
+    m_render_target = render_target;
+    if (m_render_target) {
+      m_render_target->GetResource(&backbuffer_res);
+    }
+    if (backbuffer_res) {
+      backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex);
+      backbuffer_res->Release();
+    }
+
+    if (!m_render_target || !m_render_target_tex) {
+      fprintf(stderr, "Error creating render target for shared DirectX-OpenGL resource\n");
+      return;
+    }
+  }
+
+  ~GHOST_SharedOpenGLResource()
+  {
+    if (m_render_target_tex) {
+      m_render_target_tex->Release();
+    }
+    if (m_render_target) {
+      m_render_target->Release();
+    }
+
+    if (m_is_initialized) {
+      if (m_shared.render_buf) {
+        wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
+      }
+      if (m_shared.device) {
+        wglDXCloseDeviceNV(m_shared.device);
+      }
+      glDeleteFramebuffers(1, &m_shared.fbo);
+      glDeleteRenderbuffers(1, &m_gl_render_bu

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list