[Bf-blender-cvs] [cac6b6f3888] master: BGL_Wrap: disable calls on non-opengl backends.

Jeroen Bakker noreply at git.blender.org
Thu Jan 19 08:19:21 CET 2023


Commit: cac6b6f388812cb3f0d0e2515fa4ac7f13335903
Author: Jeroen Bakker
Date:   Thu Jan 19 08:18:27 2023 +0100
Branches: master
https://developer.blender.org/rBcac6b6f388812cb3f0d0e2515fa4ac7f13335903

BGL_Wrap: disable calls on non-opengl backends.

Goal of this patch is to stop the invocation of OpenGL calls via the bgl module
on a none OpenGL GPU backend, report this as a python deprecation warning
and report this to the user.

## Deprecation warning to developers

```
>>> import bgl
>>> bgl.glUseProgram(0)
<blender_console>:1: DeprecationWarning: 'bgl.glUseProgram' is deprecated and will be removed in Blender 3.7. Report or update your script to use 'gpu' module.
```

## Deprecation message to users

The message to the user is shown as part of the Info Space and as a message box.
{F14159203 width=100%}
{F14158674 width=100%}

During implementation we tried several ideas:

# Use python warning as errors: This isn't fine grained enough and can show incorrect information to the user.
# Throw deprecation as error and use sys.excepthook to report the user message.
   This required a custom exception class to identify the bgl deprecation and a CPython handler function to
   be set during python initialization. Although this is the most flexible there was a disconnect between the
   exception class, exception function and the excepthook registration.
# A variant how we handle autoexec failures. A flag is stored in Global and when set the user message is reported.
   Not that flexible, but code is more connected to the boolean stored in the Global struct.

Although using Global struct isn't nice I chose this solution due to its traceability. It is clear to developers
reading the code how the mechanism works by using search all functionality of your IDE.

Reviewed By: MichaelPW, campbellbarton

Maniphest Tasks: T103863

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

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

M	source/blender/blenkernel/BKE_global.h
M	source/blender/python/generic/CMakeLists.txt
M	source/blender/python/generic/bgl.c
M	source/blender/windowmanager/intern/wm_event_system.cc
M	source/blender/windowmanager/intern/wm_window.c
M	source/blender/windowmanager/intern/wm_window_private.h

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

diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index f3acb7d3746..23cbd73cf36 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -139,6 +139,13 @@ typedef struct Global {
    * Typically Python drivers.
    */
   char autoexec_fail[200];
+
+  /**
+   * Has there been an opengl deprecation call detected when running on a none OpenGL backend.
+   */
+  bool opengl_deprecation_usage_detected;
+  const char *opengl_deprecation_usage_filename;
+  int opengl_deprecation_usage_lineno;
 } Global;
 
 /* **************** GLOBAL ********************* */
diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt
index 27b7ad28943..96345a2fa34 100644
--- a/source/blender/python/generic/CMakeLists.txt
+++ b/source/blender/python/generic/CMakeLists.txt
@@ -8,6 +8,7 @@ set(INC
   ../../makesdna
   ../../makesrna
   ../../../../intern/guardedalloc
+  ../../../../intern/clog
 )
 
 set(INC_SYS
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index fe64b247d43..c77dabfb539 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -12,17 +12,55 @@
 
 #include <Python.h>
 
+#include "BLI_string.h"
 #include "BLI_utildefines.h"
+
 #include "MEM_guardedalloc.h"
 
+#include "GPU_context.h"
 #include "GPU_state.h"
 
+#include "py_capi_utils.h"
+
+#include "BKE_global.h"
+
 #include "../generic/py_capi_utils.h"
 
 #include <epoxy/gl.h>
 
 #include "bgl.h"
 
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bgl"};
+
+/* -------------------------------------------------------------------- */
+/** \name Local utility defines for wrapping OpenGL
+ * \{ */
+
+static void report_deprecated_call(const char *function_name)
+{
+  char message[256];
+  SNPRINTF(message,
+           "'bgl.gl%s' is deprecated and will be removed in Blender 3.7. Report or update your "
+           "script to use 'gpu' module.",
+           function_name);
+  CLOG_WARN(&LOG, "%s", message);
+  PyErr_WarnEx(PyExc_DeprecationWarning, message, 1);
+}
+
+static void report_deprecated_call_to_user(void)
+{
+  /* Only report the first deprecated usage. */
+  if (G.opengl_deprecation_usage_detected) {
+    return;
+  }
+  G.opengl_deprecation_usage_detected = true;
+  PyC_FileAndNum(&G.opengl_deprecation_usage_filename, &G.opengl_deprecation_usage_lineno);
+}
+
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name Local utility defines for wrapping OpenGL
  * \{ */
@@ -366,14 +404,17 @@ typedef struct BufferOrOffset {
 
 #define ret_def_void
 #define ret_set_void
+#define ret_default_void
 #define ret_ret_void return Py_INCREF(Py_None), Py_None
 
 #define ret_def_GLint int ret_int
 #define ret_set_GLint ret_int =
+#define ret_default_GLint -1
 #define ret_ret_GLint return PyLong_FromLong(ret_int)
 
 #define ret_def_GLuint uint ret_uint
 #define ret_set_GLuint ret_uint =
+#define ret_default_GLuint 0
 #define ret_ret_GLuint return PyLong_FromLong((long)ret_uint)
 
 #if 0
@@ -390,14 +431,19 @@ typedef struct BufferOrOffset {
 
 #define ret_def_GLenum uint ret_uint
 #define ret_set_GLenum ret_uint =
+#define ret_default_GLenum 0
 #define ret_ret_GLenum return PyLong_FromLong((long)ret_uint)
 
 #define ret_def_GLboolean uchar ret_bool
 #define ret_set_GLboolean ret_bool =
+#define ret_default_GLboolean GL_FALSE
 #define ret_ret_GLboolean return PyLong_FromLong((long)ret_bool)
 
-#define ret_def_GLstring const uchar *ret_str
+#define ret_def_GLstring \
+  const char *default_GLstring = ""; \
+  const uchar *ret_str
 #define ret_set_GLstring ret_str =
+#define ret_default_GLstring (const uchar *)default_GLstring
 
 #define ret_ret_GLstring \
   if (ret_str) { \
@@ -1071,11 +1117,19 @@ static PyObject *Buffer_repr(Buffer *self)
     { \
       arg_def arg_list; \
       ret_def_##ret; \
+      report_deprecated_call(#funcname); \
       if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \
         return NULL; \
       } \
-      GPU_bgl_start(); \
-      ret_set_##ret gl##funcname(arg_var arg_list); \
+      const bool has_opengl_backend = GPU_backend_get_type() == GPU_BACKEND_OPENGL; \
+      if (has_opengl_backend) { \
+        GPU_bgl_start(); \
+        ret_set_##ret gl##funcname(arg_var arg_list); \
+      } \
+      else { \
+        report_deprecated_call_to_user(); \
+        ret_set_##ret ret_default_##ret; \
+      } \
       ret_ret_##ret; \
     }
 #else
@@ -2589,6 +2643,12 @@ PyObject *BPyInit_bgl(void)
     return NULL; /* should never happen */
   }
 
+  if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) {
+    CLOG_ERROR(&LOG,
+               "'bgl' imported without an OpenGL backend. Please update your add-ons to use the "
+               "'gpu' module. In Blender 3.7 'bgl' will be removed.");
+  }
+
   PyModule_AddObject(submodule, "Buffer", (PyObject *)&BGL_bufferType);
   Py_INCREF((PyObject *)&BGL_bufferType);
 
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index 05fe351c385..9004bfc0e4b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -77,6 +77,7 @@
 #include "wm_event_types.h"
 #include "wm_surface.h"
 #include "wm_window.h"
+#include "wm_window_private.h"
 
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_query.h"
@@ -704,6 +705,8 @@ void wm_event_do_notifiers(bContext *C)
 
   /* Auto-run warning. */
   wm_test_autorun_warning(C);
+  /* Deprecation warning. */
+  wm_test_opengl_deprecation_warning(C);
 
   GPU_render_end();
 }
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 74907917193..a73b9f6f51c 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1646,6 +1646,75 @@ GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gp
   return GHOST_kDrawingContextTypeNone;
 }
 
+static uiBlock *block_create_opengl_usage_warning(struct bContext *C,
+                                                  struct ARegion *region,
+                                                  void *UNUSED(arg1))
+{
+  uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
+  UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+  UI_block_emboss_set(block, UI_EMBOSS);
+
+  uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
+
+  /* Title and explanation text. */
+  uiLayout *col = uiLayoutColumn(layout, false);
+  uiItemL_ex(col, TIP_("Python script uses OpenGL for drawing."), ICON_NONE, true, false);
+  uiItemL(col, TIP_("This may lead to unexpected behavior"), ICON_NONE);
+  uiItemL(col,
+          TIP_("One of the add-ons or scripts is using OpenGL and will not work correct on Metal."),
+          ICON_NONE);
+  uiItemL(col,
+          TIP_("Please contact the developer of the add-on to migrate to use 'gpu' module."),
+          ICON_NONE);
+  if (G.opengl_deprecation_usage_filename) {
+    char location[1024];
+    SNPRINTF(
+        location, "%s:%d", G.opengl_deprecation_usage_filename, G.opengl_deprecation_usage_lineno);
+    uiItemL(col, location, ICON_NONE);
+  }
+  uiItemL(col, TIP_("See system tab in preferences to switch to OpenGL backend."), ICON_NONE);
+
+  uiItemS(layout);
+
+  UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
+
+  return block;
+}
+
+void wm_test_opengl_deprecation_warning(bContext *C)
+{
+  static bool message_shown = false;
+
+  /* Exit when no failure detected. */
+  if (!G.opengl_deprecation_usage_detected) {
+    return;
+  }
+
+  /* Have we already shown a message during this Blender session. bgl calls are done in a draw
+   * handler that will run many times. */
+  if (message_shown) {
+    return;
+  }
+
+  wmWindowManager *wm = CTX_wm_manager(C);
+  wmWindow *win = (wm->winactive) ? wm->winactive : wm->windows.first;
+
+  BKE_report(
+      &wm->reports,
+      RPT_ERROR,
+      TIP_("One of the add-ons or script is using OpenGL and will not work correct on Metal. "
+           "Please contact the developer of the add-on to migrate to use 'gpu' module."));
+
+  if (win) {
+    wmWindow *prevwin = CTX_wm_window(C);
+    CTX_wm_window_set(C, win);
+    UI_popup_block_invoke(C, block_create_opengl_usage_warning, NULL, NULL);
+    CTX_wm_window_set(C, prevwin);
+  }
+
+  message_shown = true;
+}
+
 eWM_CapabilitiesFlag WM_capabilities_flag(void)
 {
   static eWM_CapabilitiesFlag flag = -1;
diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h
index dad3e749817..d855f2b6007 100644
--- a/source/blender/windowmanager/intern/wm_window_private.h
+++ b/source/blender/windowmanager/intern/wm_window_private.h
@@ -12,6 +12,12 @@
 
 #include "GPU_context.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+
 /* *************** Message box *************** */
 /* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is
  * defined here as it was implemented to be used for showing
@@ -26,3 +32,9 @@ void WM_ghost_show_message_box(const char *title,
                                GHOST_DialogOptions dialog_options);
 
 GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend);
+
+void wm_test_opengl_deprecation_warning(struct bContext *C);
+
+#ifdef __cplusplus
+}
+#endif



More information about the Bf-blender-cvs mailing list