[Bf-blender-cvs] [86232e1e235] cycles-x: Fix missing render progress on Windows in Cycles X

Sergey Sharybin noreply at git.blender.org
Fri Sep 10 18:26:41 CEST 2021


Commit: 86232e1e235b6edb2ae9f6b1693e9fb10674b859
Author: Sergey Sharybin
Date:   Thu Sep 9 18:34:32 2021 +0200
Branches: cycles-x
https://developer.blender.org/rB86232e1e235b6edb2ae9f6b1693e9fb10674b859

Fix missing render progress on Windows in Cycles X

The issue is caused by `::wglShareLists()` returning an error if the
shared context is currently in use, so that the OpenGL context for
GPUDisplay did fail to be created.

After a lot of experimentation all the non-intrusive changes to support
OpenGL context creation with shared textures has failed.

The easiest way to have reliable OpenGL context creation is to do it on
the main thread.

For the offline rendering this is done in the pipeline.c. This change
takes advantage of this and uses the Render::gl_context for the GPU
display implementation for offline rendering.

For the viewport rendering we don't have Render, but the engine is
created from the main thread, so we can create context from the Cycles
side.

Not really happy with such approach, but this seems to be easiest and
safest way to go for now to get other bits of Cycles X finished. In the
future Vulkan should make things easier for the context creation and
multi-threaded applications.

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

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

M	intern/cycles/blender/blender_gpu_display.cpp
M	intern/cycles/blender/blender_gpu_display.h
M	source/blender/render/RE_engine.h
M	source/blender/render/intern/engine.c
M	source/blender/windowmanager/WM_api.h
M	source/blender/windowmanager/intern/wm_window.c

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

diff --git a/intern/cycles/blender/blender_gpu_display.cpp b/intern/cycles/blender/blender_gpu_display.cpp
index 29d483a008f..23175436281 100644
--- a/intern/cycles/blender/blender_gpu_display.cpp
+++ b/intern/cycles/blender/blender_gpu_display.cpp
@@ -21,10 +21,16 @@
 #include "util/util_opengl.h"
 
 extern "C" {
+struct RenderEngine;
+
+bool RE_engine_has_render_context(struct RenderEngine *engine);
+void RE_engine_render_context_enable(struct RenderEngine *engine);
+void RE_engine_render_context_disable(struct RenderEngine *engine);
+
 bool DRW_opengl_context_release();
 void DRW_opengl_context_activate(bool drw_state);
 
-void *WM_opengl_context_create_from_thread();
+void *WM_opengl_context_create();
 void WM_opengl_context_activate(void *gl_context);
 void WM_opengl_context_dispose(void *gl_context);
 void WM_opengl_context_release(void *context);
@@ -271,7 +277,7 @@ uint BlenderDisplaySpaceShader::get_shader_program()
  */
 
 BlenderGPUDisplay::BlenderGPUDisplay(BL::RenderEngine &b_engine, BL::Scene &b_scene)
-    : display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
+    : b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
 {
   /* Create context while on the main thread. */
   gl_context_create();
@@ -288,16 +294,14 @@ BlenderGPUDisplay::~BlenderGPUDisplay()
 
 bool BlenderGPUDisplay::do_update_begin(int texture_width, int texture_height)
 {
-  if (!gl_context_) {
+  if (!gl_context_enable()) {
     return false;
   }
 
-  WM_opengl_context_activate(gl_context_);
-
   glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
 
   if (!gl_texture_resources_ensure()) {
-    WM_opengl_context_release(gl_context_);
+    gl_context_disable();
     return false;
   }
 
@@ -345,7 +349,7 @@ void BlenderGPUDisplay::do_update_end()
   gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
   glFlush();
 
-  WM_opengl_context_release(gl_context_);
+  gl_context_disable();
 }
 
 /* --------------------------------------------------------------------
@@ -425,20 +429,12 @@ DeviceGraphicsInteropDestination BlenderGPUDisplay::do_graphics_interop_get()
 
 void BlenderGPUDisplay::graphics_interop_activate()
 {
-  if (!gl_context_) {
-    return;
-  }
-
-  WM_opengl_context_activate(gl_context_);
+  gl_context_enable();
 }
 
 void BlenderGPUDisplay::graphics_interop_deactivate()
 {
-  if (!gl_context_) {
-    return;
-  }
-
-  WM_opengl_context_release(gl_context_);
+  gl_context_disable();
 }
 
 /* --------------------------------------------------------------------
@@ -509,22 +505,69 @@ void BlenderGPUDisplay::do_draw()
 
 void BlenderGPUDisplay::gl_context_create()
 {
-  const bool drw_state = DRW_opengl_context_release();
+  /* When rendering in viewport there is no render context available via engine.
+   * Check whether own context is to be created here.
+   *
+   * NOTE: If the `b_engine_`'s context is not available, we are expected to be on a main thread
+   * here. */
+  use_gl_context_ = !RE_engine_has_render_context(
+      reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
 
-  gl_context_ = WM_opengl_context_create_from_thread();
+  if (use_gl_context_) {
+    const bool drw_state = DRW_opengl_context_release();
+    gl_context_ = WM_opengl_context_create();
+    if (gl_context_) {
+      /* On Windows an old context is restored after creation, and subsequent release of context
+       * generates a Win32 error. Harmless for users, but annoying to have possible misleading
+       * error prints in the console. */
+#ifndef _WIN32
+      WM_opengl_context_release(gl_context_);
+#endif
+    }
+    else {
+      LOG(ERROR) << "Error creating OpenGL context.";
+    }
 
-  if (gl_context_) {
-    /* Context creation leaves it active. Need to release it so that it can be bound from another
-     * thread. */
-    /* TODO(sergey): Need to look again into it: seems on Windoes this generates invalid handle
-     * error in `wglMakeCurrent()`. */
-    WM_opengl_context_release(gl_context_);
+    DRW_opengl_context_activate(drw_state);
   }
-  else {
-    LOG(ERROR) << "Error creating OpenGL context.";
+}
+
+bool BlenderGPUDisplay::gl_context_enable()
+{
+  if (use_gl_context_) {
+    if (!gl_context_) {
+      return false;
+    }
+    WM_opengl_context_activate(gl_context_);
+    return true;
   }
 
-  DRW_opengl_context_activate(drw_state);
+  RE_engine_render_context_enable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
+  return true;
+}
+
+void BlenderGPUDisplay::gl_context_disable()
+{
+  if (use_gl_context_) {
+    if (gl_context_) {
+      WM_opengl_context_release(gl_context_);
+    }
+    return;
+  }
+
+  RE_engine_render_context_disable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
+}
+
+void BlenderGPUDisplay::gl_context_dispose()
+{
+  if (gl_context_) {
+    const bool drw_state = DRW_opengl_context_release();
+
+    WM_opengl_context_activate(gl_context_);
+    WM_opengl_context_dispose(gl_context_);
+
+    DRW_opengl_context_activate(drw_state);
+  }
 }
 
 bool BlenderGPUDisplay::gl_draw_resources_ensure()
@@ -556,29 +599,25 @@ bool BlenderGPUDisplay::gl_draw_resources_ensure()
 
 void BlenderGPUDisplay::gl_resources_destroy()
 {
+  gl_context_enable();
+
   if (vertex_buffer_ != 0) {
     glDeleteBuffers(1, &vertex_buffer_);
   }
 
-  if (gl_context_) {
-    const bool drw_state = DRW_opengl_context_release();
-
-    WM_opengl_context_activate(gl_context_);
-
-    if (texture_.gl_pbo_id_) {
-      glDeleteBuffers(1, &texture_.gl_pbo_id_);
-      texture_.gl_pbo_id_ = 0;
-    }
+  if (texture_.gl_pbo_id_) {
+    glDeleteBuffers(1, &texture_.gl_pbo_id_);
+    texture_.gl_pbo_id_ = 0;
+  }
 
-    if (texture_.gl_id_) {
-      glDeleteTextures(1, &texture_.gl_id_);
-      texture_.gl_id_ = 0;
-    }
+  if (texture_.gl_id_) {
+    glDeleteTextures(1, &texture_.gl_id_);
+    texture_.gl_id_ = 0;
+  }
 
-    WM_opengl_context_dispose(gl_context_);
+  gl_context_disable();
 
-    DRW_opengl_context_activate(drw_state);
-  }
+  gl_context_dispose();
 }
 
 bool BlenderGPUDisplay::gl_texture_resources_ensure()
diff --git a/intern/cycles/blender/blender_gpu_display.h b/intern/cycles/blender/blender_gpu_display.h
index 8748da08d10..32ad245eeaa 100644
--- a/intern/cycles/blender/blender_gpu_display.h
+++ b/intern/cycles/blender/blender_gpu_display.h
@@ -119,9 +119,11 @@ class BlenderGPUDisplay : public GPUDisplay {
 
   virtual DeviceGraphicsInteropDestination do_graphics_interop_get() override;
 
-  /* Helper function which allocates new GPU context, without affecting the current
-   * active GPU context. */
+  /* Helper function which allocates new GPU context. */
   void gl_context_create();
+  bool gl_context_enable();
+  void gl_context_disable();
+  void gl_context_dispose();
 
   /* Make sure texture is allocated and its initial configuration is performed. */
   bool gl_texture_resources_ensure();
@@ -144,10 +146,13 @@ class BlenderGPUDisplay : public GPUDisplay {
    * NOTE: The buffer needs to be bound. */
   void vertex_buffer_update();
 
-  /* OpenGL context created by Blender's Window Manager.
-   * This context is used to perform texture update from the render thread, asynchronously from the
-   * main thread which draws the viewport. */
+  BL::RenderEngine b_engine_;
+
+  /* OpenGL context which is used the render engine doesn't have its own. */
   void *gl_context_ = nullptr;
+  /* The when Blender RenderEngine side context is not available and the GPUDisplay is to create
+   * its own context. */
+  bool use_gl_context_ = false;
 
   /* Texture which contains pixels of the render result. */
   struct {
@@ -160,7 +165,7 @@ class BlenderGPUDisplay : public GPUDisplay {
     /* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
      * pixels to it.
      *
-     * NOTE: Allocated on the `gl_context_` context. */
+     * NOTE: Allocated on the engine's context. */
     uint gl_id_ = 0;
     uint gl_pbo_id_ = 0;
 
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index f86b9b5626e..23769203b9d 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -237,6 +237,12 @@ struct RenderEngine *RE_engine_get(const struct Render *re);
 
 bool RE_engine_is_rendering(const struct Render *re);
 
+/* NOTE: Only used for Cycles's BLenderGPUDisplay integration with the draw manager. A subject
+ * for re-consideration. Do not use this functionality. */
+bool RE_engine_has_render_context(struct RenderEngine *engine);
+void RE_engine_render_context_enable(struct RenderEngine *engine);
+void RE_engine_render_context_disable(struct RenderEngine *engine);
+
 /* Engine Types */
 
 void RE_engines_init(void);
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 0fc74f37896..b4fd7e90936 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -1103,3 +1103,31 @@ bool RE_engine_is_rendering(const Render *re)
   }
   return re->engine->flag & RE_ENGINE_RENDERING;
 }
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL context manipulation.
+ *
+ * NOTE: Only used for Cycles's BLenderGPUDisplay integration with the draw manager. A subject
+ * for re-consideration. Do not use this functionality.
+ * \{ */
+
+bool RE_engine_has_render_context(RenderEngine *engine)
+{
+  if (engine->re == NULL) {
+    return false;
+  }
+
+  return RE_gl_context_get(engine->re) != NULL;
+}
+
+void RE_engine_render_context_enable(RenderEngine *engine)
+{
+  DRW_render_context_enable(engine->re);
+}
+
+void RE_engine_render_context_disable(RenderEngine *engine)
+{
+  DRW_render_context_disable(engine->re);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 991aaef7f7b..7ecbcad886d 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -172,7 +172,6 @@ void WM_window_ensure_active_view_layer(struct wmWindow *win) ATTR_NONNULL(1);
 bool WM_window_is_temp_screen(const struct wmWindow *win) ATTR_WARN_UNUSED_RESULT;
 
 void *WM_opengl_context_create(void);
-void *WM_opengl_context_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list