globals -> concrete backend attribs

This commit is contained in:
Lex Darlog (DRL) 2026-02-23 01:37:25 -03:00
parent 40fa050d3b
commit d2d750d9c4

View File

@ -18,8 +18,6 @@ logger = logging.getLogger(__name__)
# OpenGL modules - initialized lazily when context is created
gl = None
glfw = None
EGL = None
def _check_opengl_availability():
@ -322,49 +320,47 @@ class _GLContextGLFW(GLContext):
return "GLFW"
def _init_backend_concrete(self):
global glfw
self._window, glfw = self.__init_glfw()
def _make_current_concrete(self):
glfw.make_context_current(self._window)
@staticmethod
def __init_glfw():
"""Initialize GLFW. Returns (window, glfw_module). Raises RuntimeError on failure."""
logger.debug("__init_glfw: starting")
"""Initialize GLFW. Raises RuntimeError on failure."""
logger.debug("_init_backend_concrete (GLFW): starting")
# On macOS, glfw.init() must be called from main thread or it hangs forever
if sys.platform == "darwin":
logger.debug("__init_glfw: skipping on macOS")
logger.debug("_init_backend_concrete (GLFW): skipping on macOS")
raise RuntimeError("GLFW backend not supported on macOS")
logger.debug("__init_glfw: importing glfw module")
import glfw as _glfw
logger.debug("_init_backend_concrete (GLFW): importing glfw module")
import glfw
logger.debug("__init_glfw: calling glfw.init()")
if not _glfw.init():
logger.debug("_init_backend_concrete (GLFW): calling glfw.init()")
if not glfw.init():
raise RuntimeError("glfw.init() failed")
try:
logger.debug("__init_glfw: setting window hints")
_glfw.window_hint(_glfw.VISIBLE, _glfw.FALSE)
_glfw.window_hint(_glfw.CONTEXT_VERSION_MAJOR, 3)
_glfw.window_hint(_glfw.CONTEXT_VERSION_MINOR, 3)
_glfw.window_hint(_glfw.OPENGL_PROFILE, _glfw.OPENGL_CORE_PROFILE)
logger.debug("_init_backend_concrete (GLFW): setting window hints")
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
logger.debug("__init_glfw: calling create_window()")
window = _glfw.create_window(64, 64, "ComfyUI GLSL", None, None)
logger.debug("_init_backend_concrete (GLFW): calling create_window()")
window = glfw.create_window(64, 64, "ComfyUI GLSL", None, None)
if not window:
raise RuntimeError("glfw.create_window() failed")
logger.debug("__init_glfw: calling make_context_current()")
_glfw.make_context_current(window)
logger.debug("__init_glfw: completed successfully")
return window, _glfw
logger.debug("_init_backend_concrete (GLFW): calling make_context_current()")
glfw.make_context_current(window)
except Exception:
logger.debug("__init_glfw: failed, terminating glfw")
_glfw.terminate()
logger.debug("_init_backend_concrete (GLFW): failed, terminating glfw")
glfw.terminate()
raise
self._window = window
self._glfw = glfw
logger.debug("_init_backend_concrete (GLFW): completed successfully")
def _make_current_concrete(self):
self._glfw.make_context_current(self._window)
##########
class _GLContextEGL(GLContext):
@ -374,97 +370,88 @@ class _GLContextEGL(GLContext):
return "EGL"
def _init_backend_concrete(self):
global EGL
self._egl_display, self._egl_context, self._egl_surface, EGL = self.__init_egl()
def _make_current_concrete(self):
from OpenGL.EGL import eglMakeCurrent
eglMakeCurrent(self._egl_display, self._egl_surface, self._egl_surface, self._egl_context)
@staticmethod
def __init_egl():
"""Initialize EGL for headless rendering. Returns (display, context, surface, EGL_module). Raises RuntimeError on failure."""
logger.debug("__init_egl: starting")
from OpenGL import EGL as _EGL
from OpenGL.EGL import (
eglGetDisplay, eglInitialize, eglChooseConfig, eglCreateContext,
eglMakeCurrent, eglCreatePbufferSurface, eglBindAPI,
eglTerminate, eglDestroyContext, eglDestroySurface,
EGL_DEFAULT_DISPLAY, EGL_NO_CONTEXT, EGL_NONE,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, EGL_ALPHA_SIZE, EGL_DEPTH_SIZE,
EGL_WIDTH, EGL_HEIGHT, EGL_OPENGL_API,
)
logger.debug("__init_egl: imports completed")
"""Initialize EGL for headless rendering. Raises RuntimeError on failure."""
logger.debug("_init_backend_concrete (EGL): starting")
from OpenGL import EGL
logger.debug("_init_backend_concrete (EGL): imports completed")
display = None
context = None
surface = None
try:
logger.debug("__init_egl: calling eglGetDisplay()")
display = eglGetDisplay(EGL_DEFAULT_DISPLAY)
if display == _EGL.EGL_NO_DISPLAY:
logger.debug("_init_backend_concrete (EGL): calling eglGetDisplay()")
display = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY)
if display == EGL.EGL_NO_DISPLAY:
raise RuntimeError("eglGetDisplay() failed")
logger.debug("__init_egl: calling eglInitialize()")
major, minor = _EGL.EGLint(), _EGL.EGLint()
if not eglInitialize(display, major, minor):
logger.debug("_init_backend_concrete (EGL): calling eglInitialize()")
major, minor = EGL.EGLint(), EGL.EGLint()
if not EGL.eglInitialize(display, major, minor):
display = None # Not initialized, don't terminate
raise RuntimeError("eglInitialize() failed")
logger.debug(f"__init_egl: EGL version {major.value}.{minor.value}")
logger.debug(f"_init_backend_concrete (EGL): EGL version {major.value}.{minor.value}")
config_attribs = [
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0, EGL_NONE
EGL.EGL_SURFACE_TYPE, EGL.EGL_PBUFFER_BIT,
EGL.EGL_RENDERABLE_TYPE, EGL.EGL_OPENGL_BIT,
EGL.EGL_RED_SIZE, 8, EGL.EGL_GREEN_SIZE, 8, EGL.EGL_BLUE_SIZE, 8, EGL.EGL_ALPHA_SIZE, 8,
EGL.EGL_DEPTH_SIZE, 0, EGL.EGL_NONE
]
configs = (_EGL.EGLConfig * 1)()
num_configs = _EGL.EGLint()
if not eglChooseConfig(display, config_attribs, configs, 1, num_configs) or num_configs.value == 0:
configs = (EGL.EGLConfig * 1)()
num_configs = EGL.EGLint()
if not EGL.eglChooseConfig(display, config_attribs, configs, 1, num_configs) or num_configs.value == 0:
raise RuntimeError("eglChooseConfig() failed")
config = configs[0]
logger.debug(f"__init_egl: config chosen, num_configs={num_configs.value}")
logger.debug(f"_init_backend_concrete (EGL): config chosen, num_configs={num_configs.value}")
if not eglBindAPI(EGL_OPENGL_API):
if not EGL.eglBindAPI(EGL.EGL_OPENGL_API):
raise RuntimeError("eglBindAPI() failed")
logger.debug("__init_egl: calling eglCreateContext()")
logger.debug("_init_backend_concrete (EGL): calling eglCreateContext()")
context_attribs = [
_EGL.EGL_CONTEXT_MAJOR_VERSION, 3,
_EGL.EGL_CONTEXT_MINOR_VERSION, 3,
_EGL.EGL_CONTEXT_OPENGL_PROFILE_MASK, _EGL.EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_NONE
EGL.EGL_CONTEXT_MAJOR_VERSION, 3,
EGL.EGL_CONTEXT_MINOR_VERSION, 3,
EGL.EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL.EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL.EGL_NONE
]
context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs)
if context == EGL_NO_CONTEXT:
context = EGL.eglCreateContext(display, config, EGL.EGL_NO_CONTEXT, context_attribs)
if context == EGL.EGL_NO_CONTEXT:
raise RuntimeError("eglCreateContext() failed")
logger.debug("__init_egl: calling eglCreatePbufferSurface()")
pbuffer_attribs = [EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE]
surface = eglCreatePbufferSurface(display, config, pbuffer_attribs)
if surface == _EGL.EGL_NO_SURFACE:
logger.debug("_init_backend_concrete (EGL): calling eglCreatePbufferSurface()")
pbuffer_attribs = [EGL.EGL_WIDTH, 64, EGL.EGL_HEIGHT, 64, EGL.EGL_NONE]
surface = EGL.eglCreatePbufferSurface(display, config, pbuffer_attribs)
if surface == EGL.EGL_NO_SURFACE:
raise RuntimeError("eglCreatePbufferSurface() failed")
logger.debug("__init_egl: calling eglMakeCurrent()")
if not eglMakeCurrent(display, surface, surface, context):
logger.debug("_init_backend_concrete (EGL): calling eglMakeCurrent()")
if not EGL.eglMakeCurrent(display, surface, surface, context):
raise RuntimeError("eglMakeCurrent() failed")
logger.debug("__init_egl: completed successfully")
return display, context, surface, _EGL
except Exception:
logger.debug("__init_egl: failed, cleaning up")
logger.debug("_init_backend_concrete (EGL): failed, cleaning up")
# Clean up any resources on failure
if surface is not None:
eglDestroySurface(display, surface)
EGL.eglDestroySurface(display, surface)
if context is not None:
eglDestroyContext(display, context)
EGL.eglDestroyContext(display, context)
if display is not None:
eglTerminate(display)
EGL.eglTerminate(display)
raise
self._egl_display = display
self._egl_context = context
self._egl_surface = surface
self._EGL = EGL
self._eglMakeCurrent = EGL.eglMakeCurrent
logger.debug("_init_backend_concrete (EGL): completed successfully")
def _make_current_concrete(self):
self._eglMakeCurrent(self._egl_display, self._egl_surface, self._egl_surface, self._egl_context)
##########
class _GLContextOSMesa(GLContext):
@ -474,27 +461,19 @@ class _GLContextOSMesa(GLContext):
return "OSMesa"
def _init_backend_concrete(self):
self._osmesa_ctx, self._osmesa_buffer = self.__init_osmesa()
def _make_current_concrete(self):
from OpenGL.osmesa import OSMesaMakeCurrent
OSMesaMakeCurrent(self._osmesa_ctx, self._osmesa_buffer, gl.GL_UNSIGNED_BYTE, 64, 64)
@staticmethod
def __init_osmesa():
"""Initialize OSMesa for software rendering. Returns (context, buffer). Raises RuntimeError on failure."""
import ctypes
logger.debug("__init_osmesa: starting")
logger.debug("_init_backend_concrete (OSMesa): starting")
os.environ["PYOPENGL_PLATFORM"] = "osmesa"
logger.debug("__init_osmesa: importing OpenGL.osmesa")
logger.debug("_init_backend_concrete (OSMesa): importing OpenGL.osmesa")
from OpenGL import GL as _gl
from OpenGL.osmesa import (
OSMesaCreateContextExt, OSMesaMakeCurrent, OSMesaDestroyContext,
OSMESA_RGBA,
)
logger.debug("__init_osmesa: imports completed")
logger.debug("_init_backend_concrete (OSMesa): imports completed")
ctx = OSMesaCreateContextExt(OSMESA_RGBA, 24, 0, 0, None)
if not ctx:
@ -503,13 +482,19 @@ class _GLContextOSMesa(GLContext):
width, height = 64, 64
buffer = (ctypes.c_ubyte * (width * height * 4))()
logger.debug("__init_osmesa: calling OSMesaMakeCurrent()")
logger.debug("_init_backend_concrete (OSMesa): calling OSMesaMakeCurrent()")
if not OSMesaMakeCurrent(ctx, buffer, _gl.GL_UNSIGNED_BYTE, width, height):
OSMesaDestroyContext(ctx)
raise RuntimeError("OSMesaMakeCurrent() failed")
logger.debug("__init_osmesa: completed successfully")
return ctx, buffer
self._osmesa_ctx = ctx
self._osmesa_buffer = buffer
logger.debug("_init_backend_concrete (OSMesa): completed successfully")
def _make_current_concrete(self):
from OpenGL.osmesa import OSMesaMakeCurrent
OSMesaMakeCurrent(self._osmesa_ctx, self._osmesa_buffer, self._gl.GL_UNSIGNED_BYTE, 64, 64)
# ----------------------------------------------------------