mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-06-15 20:39:48 +08:00
GLRender class - to decouple context from rendering methods
This commit is contained in:
parent
8d45d2c90c
commit
b285831a62
@ -222,6 +222,7 @@ class GLContext:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
try:
|
try:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
if self.__initialized:
|
if self.__initialized:
|
||||||
# 99% of the time (after first init) we get here and just return
|
# 99% of the time (after first init) we get here and just return
|
||||||
logger.debug("GLContext.__init__: already initialized, skipping")
|
logger.debug("GLContext.__init__: already initialized, skipping")
|
||||||
@ -305,12 +306,219 @@ class GLContext:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def GL(self):
|
def GL(self):
|
||||||
"""Imported ``OpenGL.GL`` module."""
|
"""Properly yet lazily imported ``OpenGL.GL`` module."""
|
||||||
return self._gl
|
return self._gl
|
||||||
|
|
||||||
|
##########
|
||||||
|
|
||||||
|
class _GLContextGLFW(GLContext):
|
||||||
|
"""Concrete GLContext using GLFW backend."""
|
||||||
|
@classmethod
|
||||||
|
def backend_name(cls) -> str:
|
||||||
|
return "GLFW"
|
||||||
|
|
||||||
|
def _init_backend_concrete(self):
|
||||||
|
"""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_backend_concrete (GLFW): skipping on macOS")
|
||||||
|
raise RuntimeError("GLFW backend not supported on macOS")
|
||||||
|
|
||||||
|
logger.debug("_init_backend_concrete (GLFW): importing glfw module")
|
||||||
|
import glfw
|
||||||
|
|
||||||
|
logger.debug("_init_backend_concrete (GLFW): calling glfw.init()")
|
||||||
|
if not glfw.init():
|
||||||
|
raise RuntimeError("glfw.init() failed")
|
||||||
|
|
||||||
|
try:
|
||||||
|
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_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_backend_concrete (GLFW): calling make_context_current()")
|
||||||
|
glfw.make_context_current(window)
|
||||||
|
except Exception:
|
||||||
|
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):
|
||||||
|
"""Concrete GLContext using EGL backend."""
|
||||||
|
@classmethod
|
||||||
|
def backend_name(cls) -> str:
|
||||||
|
return "EGL"
|
||||||
|
|
||||||
|
def _init_backend_concrete(self):
|
||||||
|
"""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_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_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_backend_concrete (EGL): EGL version {major.value}.{minor.value}")
|
||||||
|
|
||||||
|
config_attribs = [
|
||||||
|
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 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_backend_concrete (EGL): config chosen, num_configs={num_configs.value}")
|
||||||
|
|
||||||
|
if not EGL.eglBindAPI(EGL.EGL_OPENGL_API):
|
||||||
|
raise RuntimeError("eglBindAPI() failed")
|
||||||
|
|
||||||
|
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.EGL_NONE
|
||||||
|
]
|
||||||
|
context = EGL.eglCreateContext(display, config, EGL.EGL_NO_CONTEXT, context_attribs)
|
||||||
|
if context == EGL.EGL_NO_CONTEXT:
|
||||||
|
raise RuntimeError("eglCreateContext() failed")
|
||||||
|
|
||||||
|
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_backend_concrete (EGL): calling eglMakeCurrent()")
|
||||||
|
if not EGL.eglMakeCurrent(display, surface, surface, context):
|
||||||
|
raise RuntimeError("eglMakeCurrent() failed")
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.debug("_init_backend_concrete (EGL): failed, cleaning up")
|
||||||
|
# Clean up any resources on failure
|
||||||
|
if surface is not None:
|
||||||
|
EGL.eglDestroySurface(display, surface)
|
||||||
|
if context is not None:
|
||||||
|
EGL.eglDestroyContext(display, context)
|
||||||
|
if display is not None:
|
||||||
|
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):
|
||||||
|
"""Concrete GLContext using OSMesa backend."""
|
||||||
|
@classmethod
|
||||||
|
def backend_name(cls) -> str:
|
||||||
|
return "OSMesa"
|
||||||
|
|
||||||
|
def _init_backend_concrete(self):
|
||||||
|
"""Initialize OSMesa for software rendering. Returns (context, buffer). Raises RuntimeError on failure."""
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
logger.debug("_init_backend_concrete (OSMesa): starting")
|
||||||
|
os.environ["PYOPENGL_PLATFORM"] = "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_backend_concrete (OSMesa): imports completed")
|
||||||
|
|
||||||
|
ctx = OSMesaCreateContextExt(OSMESA_RGBA, 24, 0, 0, None)
|
||||||
|
if not ctx:
|
||||||
|
raise RuntimeError("OSMesaCreateContextExt() failed")
|
||||||
|
|
||||||
|
width, height = 64, 64
|
||||||
|
buffer = (ctypes.c_ubyte * (width * height * 4))()
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
|
||||||
|
class __GLRenderMeta(type):
|
||||||
|
"""Internal metaclass for ``GLRender``.
|
||||||
|
|
||||||
|
Implemented as meta - to make ``GLRender`` truly static, including class-level properties which are also properly type-detected by IDEs.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> GLContext:
|
||||||
|
"""Global OpenGL context."""
|
||||||
|
try:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
return self.__context
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
# noinspection PyAttributeOutsideInit
|
||||||
|
self.__context = GLContext()
|
||||||
|
return self.__context
|
||||||
|
|
||||||
def compile_shader(self, source: str, shader_type: int) -> int:
|
def compile_shader(self, source: str, shader_type: int) -> int:
|
||||||
"""Compile a shader and return its ID."""
|
"""Compile a shader and return its ID."""
|
||||||
gl = self._gl
|
gl = self.context.GL
|
||||||
|
|
||||||
shader = gl.glCreateShader(shader_type)
|
shader = gl.glCreateShader(shader_type)
|
||||||
gl.glShaderSource(shader, source)
|
gl.glShaderSource(shader, source)
|
||||||
@ -325,7 +533,7 @@ class GLContext:
|
|||||||
|
|
||||||
def create_program(self, vertex_source: str, fragment_source: str) -> int:
|
def create_program(self, vertex_source: str, fragment_source: str) -> int:
|
||||||
"""Create and link a shader program."""
|
"""Create and link a shader program."""
|
||||||
gl = self._gl
|
gl = self.context.GL
|
||||||
compile = self.compile_shader
|
compile = self.compile_shader
|
||||||
|
|
||||||
vertex_shader = compile(vertex_source, gl.GL_VERTEX_SHADER)
|
vertex_shader = compile(vertex_source, gl.GL_VERTEX_SHADER)
|
||||||
@ -378,14 +586,14 @@ class GLContext:
|
|||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
gl = self._gl
|
gl = self.context.GL
|
||||||
|
|
||||||
start_time = time.perf_counter()
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
if not image_batches:
|
if not image_batches:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
self.make_current()
|
self.context.make_current()
|
||||||
|
|
||||||
# Convert from GLSL ES to desktop GLSL 330
|
# Convert from GLSL ES to desktop GLSL 330
|
||||||
fragment_source = _convert_es_to_desktop(fragment_code)
|
fragment_source = _convert_es_to_desktop(fragment_code)
|
||||||
@ -594,188 +802,11 @@ class GLContext:
|
|||||||
|
|
||||||
##########
|
##########
|
||||||
|
|
||||||
class _GLContextGLFW(GLContext):
|
class GLRender(metaclass=__GLRenderMeta):
|
||||||
"""Concrete GLContext using GLFW backend."""
|
"""Static class for all the high-level methods to render with OpenGL. Never instantiated, methods called directly as functions."""
|
||||||
@classmethod
|
|
||||||
def backend_name(cls) -> str:
|
|
||||||
return "GLFW"
|
|
||||||
|
|
||||||
def _init_backend_concrete(self):
|
def __init__(self):
|
||||||
"""Initialize GLFW. Raises RuntimeError on failure."""
|
raise NotImplementedError(f"{self.__class__!r} is a static class - call its methods directly, as just functions, without instantiating.")
|
||||||
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_backend_concrete (GLFW): skipping on macOS")
|
|
||||||
raise RuntimeError("GLFW backend not supported on macOS")
|
|
||||||
|
|
||||||
logger.debug("_init_backend_concrete (GLFW): importing glfw module")
|
|
||||||
import glfw
|
|
||||||
|
|
||||||
logger.debug("_init_backend_concrete (GLFW): calling glfw.init()")
|
|
||||||
if not glfw.init():
|
|
||||||
raise RuntimeError("glfw.init() failed")
|
|
||||||
|
|
||||||
try:
|
|
||||||
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_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_backend_concrete (GLFW): calling make_context_current()")
|
|
||||||
glfw.make_context_current(window)
|
|
||||||
except Exception:
|
|
||||||
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):
|
|
||||||
"""Concrete GLContext using EGL backend."""
|
|
||||||
@classmethod
|
|
||||||
def backend_name(cls) -> str:
|
|
||||||
return "EGL"
|
|
||||||
|
|
||||||
def _init_backend_concrete(self):
|
|
||||||
"""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_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_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_backend_concrete (EGL): EGL version {major.value}.{minor.value}")
|
|
||||||
|
|
||||||
config_attribs = [
|
|
||||||
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 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_backend_concrete (EGL): config chosen, num_configs={num_configs.value}")
|
|
||||||
|
|
||||||
if not EGL.eglBindAPI(EGL.EGL_OPENGL_API):
|
|
||||||
raise RuntimeError("eglBindAPI() failed")
|
|
||||||
|
|
||||||
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.EGL_NONE
|
|
||||||
]
|
|
||||||
context = EGL.eglCreateContext(display, config, EGL.EGL_NO_CONTEXT, context_attribs)
|
|
||||||
if context == EGL.EGL_NO_CONTEXT:
|
|
||||||
raise RuntimeError("eglCreateContext() failed")
|
|
||||||
|
|
||||||
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_backend_concrete (EGL): calling eglMakeCurrent()")
|
|
||||||
if not EGL.eglMakeCurrent(display, surface, surface, context):
|
|
||||||
raise RuntimeError("eglMakeCurrent() failed")
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
logger.debug("_init_backend_concrete (EGL): failed, cleaning up")
|
|
||||||
# Clean up any resources on failure
|
|
||||||
if surface is not None:
|
|
||||||
EGL.eglDestroySurface(display, surface)
|
|
||||||
if context is not None:
|
|
||||||
EGL.eglDestroyContext(display, context)
|
|
||||||
if display is not None:
|
|
||||||
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):
|
|
||||||
"""Concrete GLContext using OSMesa backend."""
|
|
||||||
@classmethod
|
|
||||||
def backend_name(cls) -> str:
|
|
||||||
return "OSMesa"
|
|
||||||
|
|
||||||
def _init_backend_concrete(self):
|
|
||||||
"""Initialize OSMesa for software rendering. Returns (context, buffer). Raises RuntimeError on failure."""
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
logger.debug("_init_backend_concrete (OSMesa): starting")
|
|
||||||
os.environ["PYOPENGL_PLATFORM"] = "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_backend_concrete (OSMesa): imports completed")
|
|
||||||
|
|
||||||
ctx = OSMesaCreateContextExt(OSMESA_RGBA, 24, 0, 0, None)
|
|
||||||
if not ctx:
|
|
||||||
raise RuntimeError("OSMesaCreateContextExt() failed")
|
|
||||||
|
|
||||||
width, height = 64, 64
|
|
||||||
buffer = (ctypes.c_ubyte * (width * height * 4))()
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
@ -891,7 +922,7 @@ class GLSLShader(io.ComfyNode):
|
|||||||
batch_images = [img_tensor[batch_idx].cpu().numpy().astype(np.float32) for img_tensor in image_list]
|
batch_images = [img_tensor[batch_idx].cpu().numpy().astype(np.float32) for img_tensor in image_list]
|
||||||
image_batches.append(batch_images)
|
image_batches.append(batch_images)
|
||||||
|
|
||||||
all_batch_outputs = GLContext().render_shader_batch(
|
all_batch_outputs = GLRender.render_shader_batch(
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
out_width,
|
out_width,
|
||||||
out_height,
|
out_height,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user