Changeset View
Standalone View
source/blender/python/generic/bgl.c
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| /** \file | /** \file | ||||
| * \ingroup pygen | * \ingroup pygen | ||||
| * | * | ||||
| * This file is the 'bgl' module which wraps OpenGL functions and constants, | * This file is the 'bgl' module which wraps OpenGL functions and constants, | ||||
| * allowing script writers to make OpenGL calls in their Python scripts. | * allowing script writers to make OpenGL calls in their Python scripts. | ||||
| * | * | ||||
| * \note | * \note | ||||
| * This module is very similar to 'PyOpenGL' which could replace 'bgl' one day. | * This module is very similar to 'PyOpenGL' which could replace 'bgl' one day. | ||||
| */ | */ | ||||
| #include <Python.h> | #include <Python.h> | ||||
| #include "BLI_string.h" | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "GPU_context.h" | |||||
| #include "GPU_state.h" | #include "GPU_state.h" | ||||
| #include "py_capi_utils.h" | |||||
| #include "BKE_global.h" | |||||
| #include "../generic/py_capi_utils.h" | #include "../generic/py_capi_utils.h" | ||||
| #include <epoxy/gl.h> | #include <epoxy/gl.h> | ||||
| #include "bgl.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) | |||||
campbellbarton: Use `(void)`, to prevent `-Wstrict-prototypes` warning. | |||||
| { | |||||
| /* 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 | /** \name Local utility defines for wrapping OpenGL | ||||
| * \{ */ | * \{ */ | ||||
| /* By golly George! It looks like fancy pants macro time! */ | /* By golly George! It looks like fancy pants macro time! */ | ||||
| /* TYPE_str is the string to pass to Py_ArgParse (for the format) */ | /* TYPE_str is the string to pass to Py_ArgParse (for the format) */ | ||||
| /* TYPE_var is the name to pass to the GL function */ | /* TYPE_var is the name to pass to the GL function */ | ||||
| ▲ Show 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | |||||
| #define _arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ | #define _arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ | ||||
| _arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str | _arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str | ||||
| #define _arg_str11(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \ | #define _arg_str11(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \ | ||||
| _arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) a11##_str | _arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) a11##_str | ||||
| #define arg_str(...) VA_NARGS_CALL_OVERLOAD(_arg_str, __VA_ARGS__) | #define arg_str(...) VA_NARGS_CALL_OVERLOAD(_arg_str, __VA_ARGS__) | ||||
| #define ret_def_void | #define ret_def_void | ||||
| #define ret_set_void | #define ret_set_void | ||||
| #define ret_default_void | |||||
| #define ret_ret_void return Py_INCREF(Py_None), Py_None | #define ret_ret_void return Py_INCREF(Py_None), Py_None | ||||
| #define ret_def_GLint int ret_int | #define ret_def_GLint int ret_int | ||||
| #define ret_set_GLint ret_int = | #define ret_set_GLint ret_int = | ||||
| #define ret_default_GLint -1 | |||||
| #define ret_ret_GLint return PyLong_FromLong(ret_int) | #define ret_ret_GLint return PyLong_FromLong(ret_int) | ||||
| #define ret_def_GLuint uint ret_uint | #define ret_def_GLuint uint ret_uint | ||||
| #define ret_set_GLuint ret_uint = | #define ret_set_GLuint ret_uint = | ||||
| #define ret_default_GLuint 0 | |||||
| #define ret_ret_GLuint return PyLong_FromLong((long)ret_uint) | #define ret_ret_GLuint return PyLong_FromLong((long)ret_uint) | ||||
| #if 0 | #if 0 | ||||
| # define ret_def_GLsizei size_t ret_size_t | # define ret_def_GLsizei size_t ret_size_t | ||||
| # define ret_set_GLsizei ret_size_t = | # define ret_set_GLsizei ret_size_t = | ||||
| # define ret_ret_GLsizei return PyLong_FromSsize_t(ret_size_t) | # define ret_ret_GLsizei return PyLong_FromSsize_t(ret_size_t) | ||||
| #endif | #endif | ||||
| #if 0 | #if 0 | ||||
| # define ret_def_GLsync uint ret_sync | # define ret_def_GLsync uint ret_sync | ||||
| # define ret_set_GLsync ret_sync = | # define ret_set_GLsync ret_sync = | ||||
| # define ret_ret_GLsync return PyLong_FromLong((long)ret_sync) | # define ret_ret_GLsync return PyLong_FromLong((long)ret_sync) | ||||
| #endif | #endif | ||||
| #define ret_def_GLenum uint ret_uint | #define ret_def_GLenum uint ret_uint | ||||
| #define ret_set_GLenum 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_ret_GLenum return PyLong_FromLong((long)ret_uint) | ||||
| #define ret_def_GLboolean uchar ret_bool | #define ret_def_GLboolean uchar ret_bool | ||||
| #define ret_set_GLboolean 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_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_set_GLstring ret_str = | ||||
| #define ret_default_GLstring (const uchar *)default_GLstring | |||||
| #define ret_ret_GLstring \ | #define ret_ret_GLstring \ | ||||
| if (ret_str) { \ | if (ret_str) { \ | ||||
| return PyUnicode_FromString((const char *)ret_str); \ | return PyUnicode_FromString((const char *)ret_str); \ | ||||
| } \ | } \ | ||||
| \ | \ | ||||
| PyErr_SetString(PyExc_AttributeError, "could not get opengl string"); \ | PyErr_SetString(PyExc_AttributeError, "could not get opengl string"); \ | ||||
| return NULL; | return NULL; | ||||
| ▲ Show 20 Lines • Show All 657 Lines • ▼ Show 20 Lines | |||||
| * \{ */ | * \{ */ | ||||
| #ifdef WITH_OPENGL | #ifdef WITH_OPENGL | ||||
| # define BGL_Wrap(funcname, ret, arg_list) \ | # define BGL_Wrap(funcname, ret, arg_list) \ | ||||
| static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \ | static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \ | ||||
| { \ | { \ | ||||
| arg_def arg_list; \ | arg_def arg_list; \ | ||||
| ret_def_##ret; \ | ret_def_##ret; \ | ||||
| report_deprecated_call(#funcname); \ | |||||
| if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \ | if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \ | ||||
| return NULL; \ | return NULL; \ | ||||
Done Inline ActionsThe deprecated warning is often overlooked. mano-wii: The deprecated warning is often overlooked.
The error message cannot be ignored.
If we wanted… | |||||
Done Inline ActionsThis would still not show to the user on a mac. I believe the best option is to load sys.excepthook with a custom callback that reports back to the user. Still investigating how to do this via CPython jbakker: This would still not show to the user on a mac. I believe the best option is to load sys. | |||||
| } \ | } \ | ||||
| const bool has_opengl_backend = GPU_backend_get_type() == GPU_BACKEND_OPENGL; \ | |||||
Done Inline ActionsIs it possible to continue with the functions logic (even if the BGL call does nothing), as any function that is expected to return a non None value will error (although admittedly there aren't too many of these). campbellbarton: Is it possible to continue with the functions logic (even if the BGL call does nothing), as any… | |||||
Done Inline ActionsThe biggest issue is that on metal the opengl library isn't loaded, that will crash when continuing the logic. Adding logic to use the correct return type might be doable, For example -1 for integer types. Will have a look how to do this jbakker: The biggest issue is that on metal the opengl library isn't loaded, that will crash when… | |||||
| if (has_opengl_backend) { \ | |||||
| GPU_bgl_start(); \ | GPU_bgl_start(); \ | ||||
| ret_set_##ret gl##funcname(arg_var arg_list); \ | ret_set_##ret gl##funcname(arg_var arg_list); \ | ||||
| } \ | |||||
| else { \ | |||||
| report_deprecated_call_to_user(); \ | |||||
| ret_set_##ret ret_default_##ret; \ | |||||
| } \ | |||||
| ret_ret_##ret; \ | ret_ret_##ret; \ | ||||
| } | } | ||||
| #else | #else | ||||
| static void bgl_no_opengl_error(void) | static void bgl_no_opengl_error(void) | ||||
| { | { | ||||
| PyErr_SetString(PyExc_RuntimeError, "Built without OpenGL support"); | PyErr_SetString(PyExc_RuntimeError, "Built without OpenGL support"); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 1,497 Lines • ▼ Show 20 Lines | PyObject *BPyInit_bgl(void) | ||||
| PyObject *submodule, *dict; | PyObject *submodule, *dict; | ||||
| submodule = PyModule_Create(&BGL_module_def); | submodule = PyModule_Create(&BGL_module_def); | ||||
| dict = PyModule_GetDict(submodule); | dict = PyModule_GetDict(submodule); | ||||
| if (PyType_Ready(&BGL_bufferType) < 0) { | if (PyType_Ready(&BGL_bufferType) < 0) { | ||||
| return NULL; /* should never happen */ | 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); | PyModule_AddObject(submodule, "Buffer", (PyObject *)&BGL_bufferType); | ||||
| Py_INCREF((PyObject *)&BGL_bufferType); | Py_INCREF((PyObject *)&BGL_bufferType); | ||||
| init_bgl_version_1_0_methods(submodule, dict); | init_bgl_version_1_0_methods(submodule, dict); | ||||
| init_bgl_version_1_1_methods(submodule, dict); | init_bgl_version_1_1_methods(submodule, dict); | ||||
| init_bgl_version_1_2_methods(submodule, dict); | init_bgl_version_1_2_methods(submodule, dict); | ||||
| init_bgl_version_1_3_methods(submodule, dict); | init_bgl_version_1_3_methods(submodule, dict); | ||||
| init_bgl_version_1_4_methods(submodule, dict); | init_bgl_version_1_4_methods(submodule, dict); | ||||
| ▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines | |||||
Use (void), to prevent -Wstrict-prototypes warning.