[Bf-blender-cvs] [2cedad990a9] soc-2019-openxr: Initial HMD viewport rendering (DirectX only first)

Julian Eisel noreply at git.blender.org
Mon Jul 1 17:33:28 CEST 2019


Commit: 2cedad990a975185fc8a24efbd827c7fd93f650d
Author: Julian Eisel
Date:   Mon Jul 1 15:57:32 2019 +0200
Branches: soc-2019-openxr
https://developer.blender.org/rB2cedad990a975185fc8a24efbd827c7fd93f650d

Initial HMD viewport rendering (DirectX only first)

Finally: This makes it possible to render a viewport to an HMD via
OpenXR. Pure OpenGL rendering will need some more tweaks to work.
To my great delight, performance is quite good for reasonably sized
scenes.

Had to do some hacks and marked some TODOs. Nothing too bad though.

Here are a couple of notes:
* Current initial pose is pretty useless, think it just looks downwards
  from world origin. Will change that soon.
* The rendered viewport has some issues: Too dark (bad lighting?), grid
  doesn't show up even though I told it to, lighting seems to change with
  view position/rotation, etc. Needs some polish.
* Ideally we'd just use the D3D11 Texture given to us via the OpenXR
  swapchain and blit the OpenGL framebuffer into that. However the
  NV_DX_interop extension fails doing this. Seems like this is a NVidia
  Optimus only issue, but I'm missing the hardware to confirm.
  So instead, we blit into the D3D11 back buffer first and then into the
  Texture.
* The draw-manager uses its own offscreen context so we have to get the
  render result from the draw-manager context to the VR session's
  context first. Luckily I've already added code to support blitting from
  one OpenGL context into another. But it requires blitting twice.
  Blitting should be very cheap, but still...
  Draw-manager could get a context to use passed instead.

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

M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_IContext.h
M	intern/ghost/intern/GHOST_C-api.cpp
M	intern/ghost/intern/GHOST_Context.cpp
M	intern/ghost/intern/GHOST_Context.h
M	intern/ghost/intern/GHOST_ContextD3D.cpp
M	intern/ghost/intern/GHOST_ContextD3D.h
M	intern/ghost/intern/GHOST_ContextWGL.cpp
M	intern/ghost/intern/GHOST_IXrGraphicsBinding.h
M	intern/ghost/intern/GHOST_SystemWin32.cpp
M	intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
M	intern/ghost/intern/GHOST_XrSession.cpp
M	source/blender/draw/DRW_engine.h
M	source/blender/draw/intern/draw_manager.c
M	source/blender/editors/space_view3d/view3d_draw.c
M	source/blender/makesdna/DNA_view3d_types.h
M	source/blender/windowmanager/intern/wm_draw.c
M	source/blender/windowmanager/intern/wm_surface.c
M	source/blender/windowmanager/intern/wm_xr.c
M	source/blender/windowmanager/wm_surface.h

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

diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 3f3c25eca43..d9f9cf93bd3 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -215,6 +215,12 @@ GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
 GHOST_TSuccess GHOST_BlitOpenGLOffscreenContext(GHOST_WindowHandle windowhandle,
                                                 GHOST_ContextHandle offscreen_contexthandle);
 
+extern GHOST_TSuccess GHOST_ContextBlitOpenGLOffscreenContext(
+    GHOST_ContextHandle onscreen_contexthandle,
+    GHOST_ContextHandle offscreen_contexthandle,
+    GHOST_TInt32 width,
+    GHOST_TInt32 height);
+
 extern GHOST_ContextHandle GHOST_GetWindowContext(GHOST_WindowHandle windowhandle);
 
 /**
@@ -1010,6 +1016,7 @@ typedef struct {
 } GHOST_XrContextCreateInfo;
 
 typedef struct {
+  int ofsx, ofsy;
   int width, height;
 
   struct {
@@ -1030,7 +1037,10 @@ void GHOST_XrContextDestroy(struct GHOST_XrContext *xr_context);
 typedef void *(*GHOST_XrGraphicsContextBindFn)(GHOST_TXrGraphicsBinding graphics_lib);
 typedef void (*GHOST_XrGraphicsContextUnbindFn)(GHOST_TXrGraphicsBinding graphics_lib,
                                                 void *graphics_context);
-typedef void (*GHOST_XrDrawViewFn)(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
+/* XXX hacky: returns GHOST_ContextHandle so DirectX binding can get a handle to the OpenGL
+ * offscreen context. */
+typedef GHOST_ContextHandle (*GHOST_XrDrawViewFn)(const GHOST_XrDrawViewInfo *draw_view,
+                                                  void *customdata);
 
 void GHOST_XrGraphicsContextBindFuncs(struct GHOST_XrContext *xr_context,
                                       GHOST_XrGraphicsContextBindFn bind_fn,
diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h
index b83cea95404..cb6eb5fc76b 100644
--- a/intern/ghost/GHOST_IContext.h
+++ b/intern/ghost/GHOST_IContext.h
@@ -56,6 +56,10 @@ class GHOST_IContext {
    */
   virtual GHOST_TSuccess releaseDrawingContext() = 0;
 
+  virtual GHOST_TSuccess blitOpenGLOffscreenContext(class GHOST_Context *offscreen,
+                                                    GHOST_TInt32 width,
+                                                    GHOST_TInt32 height) = 0;
+
   virtual unsigned int getDefaultFramebuffer() = 0;
 
   virtual GHOST_TSuccess swapBuffers() = 0;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index ddd364d63ec..74e244e79e8 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -154,6 +154,17 @@ GHOST_TSuccess GHOST_BlitOpenGLOffscreenContext(GHOST_WindowHandle windowhandle,
   return window->blitOpenGLOffscreenContext((GHOST_IContext *)offscreen_contexthandle);
 }
 
+GHOST_TSuccess GHOST_ContextBlitOpenGLOffscreenContext(GHOST_ContextHandle onscreen_contexthandle,
+                                                       GHOST_ContextHandle offscreen_contexthandle,
+                                                       GHOST_TInt32 width,
+                                                       GHOST_TInt32 height)
+{
+  GHOST_IContext *context = (GHOST_IContext *)onscreen_contexthandle;
+
+  return context->blitOpenGLOffscreenContext(
+      (class GHOST_Context *)offscreen_contexthandle, width, height);
+}
+
 GHOST_ContextHandle GHOST_GetWindowContext(GHOST_WindowHandle windowhandle)
 {
   GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp
index d9c1475b675..4df47006a56 100644
--- a/intern/ghost/intern/GHOST_Context.cpp
+++ b/intern/ghost/intern/GHOST_Context.cpp
@@ -157,6 +157,7 @@ GHOST_TSuccess GHOST_Context::blitOpenGLOffscreenContext(GHOST_Context *offscree
   GLuint fbo_offscreen;
   GLuint fbo_onscreen;
   GLuint render_buf_shared;
+  GLint fbo_prev_draw;
 
   if ((m_type != GHOST_kDrawingContextTypeOpenGL) ||
       (offscreen->m_type != GHOST_kDrawingContextTypeOpenGL)) {
@@ -173,6 +174,8 @@ GHOST_TSuccess GHOST_Context::blitOpenGLOffscreenContext(GHOST_Context *offscree
 
   offscreen->activateDrawingContext();
 
+  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo_prev_draw);
+
   /* Create shared renderbuffer */
   glGenRenderbuffers(1, &render_buf_shared);
   glBindRenderbuffer(GL_RENDERBUFFER, render_buf_shared);
@@ -185,7 +188,7 @@ GHOST_TSuccess GHOST_Context::blitOpenGLOffscreenContext(GHOST_Context *offscree
       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf_shared);
 
   /* Blit offscreen framebuffer into renderbuffer */
-  glBindFramebuffer(GL_READ_FRAMEBUFFER, offscreen->getDefaultFramebuffer());
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_prev_draw);
   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_offscreen);
   glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
 
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 16feb98d1b9..d7a720bb545 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -146,9 +146,9 @@ class GHOST_Context : public GHOST_IContext {
     return GHOST_kFailure;
   }
 
-  virtual GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_Context *offscreen,
-                                                    GHOST_TInt32 width,
-                                                    GHOST_TInt32 height);
+  GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_Context *offscreen,
+                                            GHOST_TInt32 width,
+                                            GHOST_TInt32 height);
 
  protected:
   void initContextGLEW();
diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp
index b6c2a402e5f..8e357a80702 100644
--- a/intern/ghost/intern/GHOST_ContextD3D.cpp
+++ b/intern/ghost/intern/GHOST_ContextD3D.cpp
@@ -41,55 +41,74 @@ static void drawTestTriangle(ID3D11Device *m_device,
 #endif
 
 class SharedOpenGLContext {
-  GHOST_ContextD3D *m_d3d_ctx;
+  ID3D11Device *m_d3d_device;
   GHOST_ContextWGL *m_wgl_ctx;
+  /* NV_DX_interop2 requires ID3D11Texture2D as backbuffer when sharing with GL_RENDERBUFFER */
+  ID3D11Texture2D *m_d3d_render_target;
   GLuint m_gl_render_buf;
 
  public:
   struct SharedData {
     HANDLE device;
     GLuint fbo;
-    HANDLE render_buf;
+    HANDLE render_buf{nullptr};
   } m_shared;
 
-  SharedOpenGLContext(GHOST_ContextD3D *d3d_ctx, GHOST_ContextWGL *wgl_ctx)
-      : m_d3d_ctx(d3d_ctx), m_wgl_ctx(wgl_ctx)
+  /* XXX Should have a map of render_target items to shared resource data (SharedData) to
+   * allow multiple shared surfaces in a context. Current code assumes a single one. That would be
+   * an issue if we wanted to use the OpenXR provided textures (changes for each eye and each
+   * redraw) and not the constant D3D swapchain texture like now. */
+  SharedOpenGLContext(ID3D11Device *d3d_device,
+                      GHOST_ContextWGL *wgl_ctx,
+                      ID3D11Texture2D *render_target)
+      : m_d3d_device(d3d_device), m_wgl_ctx(wgl_ctx), m_d3d_render_target(render_target)
   {
   }
   ~SharedOpenGLContext()
   {
-    wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
-    wglDXCloseDeviceNV(m_shared.device);
+    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_buf);
   }
 
-  GHOST_TSuccess initialize()
+  void reregisterSharedObject()
   {
-    ID3D11Resource *color_buf_res;
-    ID3D11Texture2D *color_buf_tex;
+    if (m_shared.render_buf) {
+      wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
+      m_shared.render_buf = nullptr;
+    }
+
+    m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
+                                                m_d3d_render_target,
+                                                m_gl_render_buf,
+                                                GL_RENDERBUFFER,
+                                                WGL_ACCESS_READ_WRITE_NV);
+    if (!m_shared.render_buf) {
+      fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
+      return;
+    }
+  }
 
+  GHOST_TSuccess initialize()
+  {
     m_wgl_ctx->activateDrawingContext();
 
-    m_shared.device = wglDXOpenDeviceNV(m_d3d_ctx->m_device);
+    m_shared.device = wglDXOpenDeviceNV(m_d3d_device);
     if (m_shared.device == NULL) {
       fprintf(stderr, "Error opening shared device using wglDXOpenDeviceNV()\n");
       return GHOST_kFailure;
     }
 
-    /* NV_DX_interop2 requires ID3D11Texture2D as backbuffer when sharing with GL_RENDERBUFFER */
-    m_d3d_ctx->m_backbuffer_view->GetResource(&color_buf_res);
-    color_buf_res->QueryInterface<ID3D11Texture2D>(&color_buf_tex);
-
     /* Build the renderbuffer. */
     glGenRenderbuffers(1, &m_gl_render_buf);
     glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
 
-    m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
-                                                color_buf_tex,
-                                                m_gl_render_buf,
-                                                GL_RENDERBUFFER,
-                                                WGL_ACCESS_READ_WRITE_NV);
+    reregisterSharedObject();
 
     /* Build the framebuffer */
     glGenFramebuffers(1, &m_shared.fbo);
@@ -102,6 +121,9 @@ class SharedOpenGLContext {
   void update(int width, int height)
   {
     m_wgl_ctx->setDefaultFramebufferSize(width, height);
+    m_wgl_ctx->activateDrawingContext();
+    /* TODO avoid re-registering if resource to share has not changed. */
+    reregisterSharedObject();
   }
 
   void beginGLOnly()
@@ -125,6 +147,7 @@ GHOST_ContextD3D::~GHOST_ContextD3D()
   m_swapchain->Release();
   m_backbuffer_view->Release();
   m_device->Release();
+  m_device_ctx->ClearState();
   m_device_ctx->Release();
 }
 
@@ -144,6 +167,74 @@ GHOST_TSuccess GHOST_ContextD3D::releaseDrawingContext()
   return GHOST_kFailure;
 }
 
+GHOST_TSuccess GHOS

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list