Python: Remove deprecated BGL API

The API was in a deprecation state for many years now.
This API was not compatible with Metal nor Vulkan.

This also remove `Image.bindcode`.

Pull Request: https://projects.blender.org/blender/blender/pulls/140370
This commit is contained in:
Clément Foucault 2025-06-16 12:50:50 +02:00 • committed by Clément Foucault
parent 9ddc67166f
commit decd88f67e
26 changed files with 3 additions and 4499 deletions

File diff suppressed because it is too large Load diff

View file

@ -267,7 +267,6 @@ else:
EXCLUDE_INFO_DOCS = True
EXCLUDE_MODULES = [
"aud",
"bgl",
"blf",
"bl_math",
"imbuf",
@ -2033,7 +2032,6 @@ def write_rst_index(basepath):
standalone_modules = (
# Sub-modules are added in parent page.
"aud",
"bgl",
"bl_math",
"blf",
"bmesh",
@ -2364,7 +2362,6 @@ def copy_handwritten_rsts(basepath):
# TODO: put this docs in Blender's code and use import as per modules above.
handwritten_modules = [
"bgl", # "Blender OpenGl wrapper"
"bmesh.ops", # Generated by `rst_from_bmesh_opdefines.py`.
# Includes.

View file

@ -350,7 +350,7 @@ def banner(context):
"PYTHON INTERACTIVE CONSOLE {:s}".format(version_string),
"",
"Builtin Modules: "
"bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, gpu, blf, mathutils",
"bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, gpu, blf, mathutils",
"Convenience Imports: from mathutils import *; from math import *",
"Convenience Variables: C = bpy.context, D = bpy.data",

View file

@ -89,14 +89,6 @@ def draw_texture_2d(texture, position, width, height):
gpu.matrix.scale((width, height))
shader = gpu.shader.from_builtin('IMAGE')
if isinstance(texture, int):
# Call the legacy bgl to not break the existing API
import bgl
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture)
shader.uniform_int("image", 0)
else:
shader.uniform_sampler("image", texture)
shader.uniform_sampler("image", texture)
batch.draw(shader)

View file

@ -590,10 +590,6 @@ void BLF_draw(int fontid, const char *str, const size_t str_len, ResultBLF *r_in
FontBLF *font = blf_get(fontid);
if (font) {
/* Avoid bgl usage to corrupt BLF drawing. */
GPU_bgl_end();
blf_draw_gpu__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, str_len, r_info);
@ -635,8 +631,6 @@ void BLF_draw_svg_icon(uint icon_id,
#ifndef WITH_HEADLESS
FontBLF *font = global_font[0];
if (font) {
/* Avoid bgl usage to corrupt BLF drawing. */
GPU_bgl_end();
blf_draw_gpu__start(font);
blf_draw_svg_icon(font, icon_id, x, y, size, color, outline_alpha, multicolor, edit_source_cb);
blf_draw_gpu__end(font);

View file

@ -173,13 +173,6 @@ struct Global {
*/
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;
/**
* Triggers a GPU capture if the name matches a DebugScope.
* Set using `--debug-gpu-scope-capture "debug_scope"`.

View file

@ -259,8 +259,6 @@ class Instance : public DrawEngine {
const RenderEngineType *type = render_engine->type;
type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
GPU_bgl_end();
GPU_matrix_pop();
GPU_matrix_pop_projection();
@ -362,7 +360,6 @@ class Instance : public DrawEngine {
GPU_matrix_pop_projection();
blender::draw::command::StateSet::set();
GPU_bgl_end();
RE_engine_draw_release(re);
}

View file

@ -263,9 +263,6 @@ static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionTy
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
/* This is needed until we get rid of BGL which can change the states we are tracking. */
GPU_bgl_end();
}
}
}

View file

@ -215,14 +215,6 @@ void GPU_flush();
void GPU_finish();
void GPU_apply_state();
void GPU_bgl_start();
/**
* Just turn off the `bgl` safeguard system. Can be called even without #GPU_bgl_start.
*/
void GPU_bgl_end();
bool GPU_bgl_get();
/**
* A barrier _must_ be issued _after_ a shader arbitrary write to a buffer or a
* texture (i.e: using imageStore, imageAtomics, or SSBO). Otherwise, the written value may not

View file

@ -1272,13 +1272,6 @@ void **GPU_texture_py_reference_get(GPUTexture *texture);
void GPU_texture_py_reference_set(GPUTexture *texture, void **py_ref);
#endif
/**
* Return the backend handle of the texture.
* \note This is a legacy feature only working on OpenGL backend. It will be removed once we remove
* the python BGL module.
*/
int GPU_texture_opengl_bindcode(const GPUTexture *texture);
/** \} */
/* -------------------------------------------------------------------- */

View file

@ -319,65 +319,6 @@ void GPU_apply_state()
/** \} */
/* -------------------------------------------------------------------- */
/** \name BGL workaround
*
* bgl makes direct GL calls that makes our state tracking out of date.
* This flag make it so that the pyGPU calls will not override the state set by
* bgl functions.
* \{ */
void GPU_bgl_start()
{
Context *ctx = Context::get();
if (!(ctx && ctx->state_manager)) {
return;
}
StateManager &state_manager = *(Context::get()->state_manager);
if (state_manager.use_bgl == false) {
/* Expected by many addons (see #80169, #81289).
* This will reset the blend function. */
GPU_blend(GPU_BLEND_NONE);
/* Equivalent of setting the depth func `glDepthFunc(GL_LEQUAL)`
* Needed since Python scripts may enable depth test.
* Without this block the depth test function is undefined. */
{
eGPUDepthTest depth_test_real = GPU_depth_test_get();
eGPUDepthTest depth_test_temp = GPU_DEPTH_LESS_EQUAL;
if (depth_test_real != depth_test_temp) {
GPU_depth_test(depth_test_temp);
state_manager.apply_state();
GPU_depth_test(depth_test_real);
}
}
state_manager.apply_state();
state_manager.use_bgl = true;
}
}
void GPU_bgl_end()
{
Context *ctx = Context::get();
if (!(ctx && ctx->state_manager)) {
return;
}
StateManager &state_manager = *ctx->state_manager;
if (state_manager.use_bgl == true) {
state_manager.use_bgl = false;
/* Resync state tracking. */
state_manager.force_state();
}
}
bool GPU_bgl_get()
{
return Context::get()->state_manager->use_bgl;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Synchronization Utils
* \{ */

View file

@ -946,12 +946,6 @@ void GPU_texture_py_reference_set(GPUTexture *texture, void **py_ref)
}
#endif
/* TODO: remove. */
int GPU_texture_opengl_bindcode(const GPUTexture *texture)
{
return unwrap(texture)->gl_bindcode_get();
}
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
{
unwrap(texture)->mip_size_get(mip_level, r_size);

View file

@ -215,7 +215,7 @@ void check_gl_error(const char *info)
void check_gl_resources(const char *info)
{
if (!(G.debug & G_DEBUG_GPU) || GPU_bgl_get()) {
if (!(G.debug & G_DEBUG_GPU)) {
return;
}

View file

@ -556,13 +556,6 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
BKE_image_release_ibuf(im, ibuf, lock);
}
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
static int rna_Image_depth_get(PointerRNA *ptr)
{
Image *im = (Image *)ptr->data;
@ -1296,12 +1289,6 @@ static void rna_def_image(BlenderRNA *brna)
prop, "Display Aspect", "Display Aspect for this image, does not affect rendering");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, nullptr);
prop = RNA_def_property(srna, "bindcode", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Image_bindcode_get", nullptr, nullptr);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bindcode", "OpenGL bindcode");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, nullptr);
prop = RNA_def_property(srna, "render_slots", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSlot");
RNA_def_property_collection_sdna(prop, nullptr, "renderslots", nullptr);

View file

@ -66,8 +66,6 @@ static void rna_gizmo_draw_cb(const bContext *C, wmGizmo *gz)
RNA_parameter_set_lookup(&list, "context", &C);
gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
/* This callback may have called bgl functions. */
GPU_bgl_end();
}
static void rna_gizmo_draw_select_cb(const bContext *C, wmGizmo *gz, int select_id)
@ -84,8 +82,6 @@ static void rna_gizmo_draw_select_cb(const bContext *C, wmGizmo *gz, int select_
RNA_parameter_set_lookup(&list, "select_id", &select_id);
gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
/* This callback may have called bgl functions. */
GPU_bgl_end();
}
static int rna_gizmo_test_select_cb(bContext *C, wmGizmo *gz, const int location[2])

View file

@ -12,7 +12,6 @@ set(INC_SYS
)
set(SRC
bgl.cc
bl_math_py_api.cc
blf_py_api.cc
bpy_threads.cc
@ -22,7 +21,6 @@ set(SRC
py_capi_rna.cc
py_capi_utils.cc
bgl.hh
bl_math_py_api.hh
blf_py_api.hh
idprop_py_api.hh

File diff suppressed because it is too large Load diff

View file

@ -1,61 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pygen
*/
#pragma once
#include <Python.h>
PyObject *BPyInit_bgl();
/* This API is deprecated, currently these are only used in `bgl.cc`
* and there should be no reason to make use of them in the future.
* Use a define to indicate they are part of the public API which is being phased out. */
#ifdef USE_BGL_DEPRECATED_API
/**
* Buffer Object
*
* For Python access to OpenGL functions requiring a pointer.
*/
struct Buffer {
PyObject_VAR_HEAD
PyObject *parent;
int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */
int ndimensions;
int *dimensions;
union {
char *asbyte;
short *asshort;
int *asint;
float *asfloat;
double *asdouble;
void *asvoid;
} buf;
};
/** The type object. */
extern PyTypeObject BGL_bufferType;
/**
* Create a buffer object
*
* \param dimensions: An array of ndimensions integers representing the size of each dimension.
* \param initbuffer: When not NULL holds a contiguous buffer
* with the correct format from which the buffer will be initialized
*/
struct Buffer *BGL_MakeBuffer(int type,
int ndimensions,
const int *dimensions,
const void *initbuffer);
int BGL_typeSize(int type);
#endif /* USE_BGL_DEPRECATED_API */

View file

@ -351,19 +351,6 @@ static PyObject *pygpu_offscreen_height_get(BPyGPUOffScreen *self, void * /*type
return PyLong_FromLong(GPU_offscreen_height(self->ofs));
}
PyDoc_STRVAR(
/* Wrap. */
pygpu_offscreen_color_texture_doc,
"OpenGL bindcode for the color texture.\n"
"\n"
":type: int");
static PyObject *pygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void * /*type*/)
{
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
GPUTexture *texture = GPU_offscreen_color_texture(self->ofs);
return PyLong_FromLong(GPU_texture_opengl_bindcode(texture));
}
PyDoc_STRVAR(
/* Wrap. */
pygpu_offscreen_texture_color_doc,
@ -477,12 +464,6 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
depsgraph = BKE_scene_ensure_depsgraph(G_MAIN, scene, view_layer);
/* Disable 'bgl' state since it interfere with off-screen drawing, see: #84402. */
const bool is_bgl = GPU_bgl_get();
if (is_bgl) {
GPU_bgl_end();
}
GPU_offscreen_bind(self->ofs, true);
/* Cache the #GPUViewport so the frame-buffers and associated textures are
@ -513,10 +494,6 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
GPU_offscreen_unbind(self->ofs, true);
if (is_bgl) {
GPU_bgl_start();
}
Py_RETURN_NONE;
}
@ -555,11 +532,6 @@ static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
}
static PyGetSetDef pygpu_offscreen__tp_getseters[] = {
{"color_texture",
(getter)pygpu_offscreen_color_texture_get,
(setter) nullptr,
pygpu_offscreen_color_texture_doc,
nullptr},
{"texture_color",
(getter)pygpu_offscreen_texture_color_get,
(setter) nullptr,

View file

@ -709,8 +709,6 @@ static PyObject *bpy_import_test(const char *modname)
{
PyObject *mod = PyImport_ImportModuleLevel(modname, nullptr, nullptr, nullptr, 0);
GPU_bgl_end();
if (mod) {
Py_DECREF(mod);
}

View file

@ -57,7 +57,6 @@
/* `inittab` initialization functions. */
#include "../bmesh/bmesh_py_api.hh"
#include "../generic/bgl.hh"
#include "../generic/bl_math_py_api.hh"
#include "../generic/blf_py_api.hh"
#include "../generic/idprop_py_api.hh"
@ -272,7 +271,6 @@ static _inittab bpy_internal_modules[] = {
{"mathutils.kdtree", PyInit_mathutils_kdtree},
#endif
{"_bpy_path", BPyInit__bpy_path},
{"bgl", BPyInit_bgl},
{"blf", BPyInit_blf},
{"bl_math", BPyInit_bl_math},
{"imbuf", BPyInit_imbuf},

View file

@ -1185,9 +1185,6 @@ static void wm_draw_window(bContext *C, wmWindow *win)
bScreen *screen = WM_window_get_active_screen(win);
bool stereo = WM_stereo3d_enabled(win, false);
/* Avoid any BGL call issued before this to alter the window drawing. */
GPU_bgl_end();
/* Draw area regions into their own frame-buffer. This way we can redraw
* the areas that need it, and blit the rest from existing frame-buffers. */
wm_draw_window_offscreen(C, win, stereo);

View file

@ -812,7 +812,6 @@ void wm_event_do_notifiers(bContext *C)
/* Auto-run warning. */
wm_test_autorun_warning(C);
/* Deprecation warning. */
wm_test_opengl_deprecation_warning(C);
wm_test_gpu_backend_fallback(C);
GPU_render_end();

View file

@ -2134,12 +2134,6 @@ static uiBlock *block_create_opengl_usage_warning(bContext *C, ARegion *region,
messages->label(message1, ICON_NONE);
messages->label(message2, ICON_NONE);
messages->label(message3, 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);
messages->label(location, ICON_NONE);
}
messages->label(message4, ICON_NONE);
col->separator(0.5f, LayoutSeparatorType::Space);
@ -2149,44 +2143,6 @@ static uiBlock *block_create_opengl_usage_warning(bContext *C, ARegion *region,
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 = static_cast<wmWindow *>((wm->winactive) ? wm->winactive : wm->windows.first);
BKE_report(&wm->runtime->reports,
RPT_ERROR,
"One of the add-ons or scripts 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) {
/* We want this warning on the Main window, not a child window even if active. See #118765. */
if (win->parent) {
win = win->parent;
}
wmWindow *prevwin = CTX_wm_window(C);
CTX_wm_window_set(C, win);
UI_popup_block_invoke(C, block_create_opengl_usage_warning, nullptr, nullptr);
CTX_wm_window_set(C, prevwin);
}
message_shown = true;
}
static uiBlock *block_create_gpu_backend_fallback(bContext *C, ARegion *region, void * /*arg1*/)
{
uiBlock *block = UI_block_begin(

View file

@ -28,5 +28,4 @@ void WM_ghost_show_message_box(const char *title,
GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend);
void wm_test_opengl_deprecation_warning(bContext *C);
void wm_test_gpu_backend_fallback(bContext *C);

View file

@ -23,7 +23,6 @@ import rst_to_doctree_mini
# (file, module)
modules = (
("bgl.rst", "bgl", True),
("gpu.rst", "gpu", False),
)