only make textures when GL context exists
This commit is contained in:
parent
73c504abb7
commit
fc672bcdff
@ -199,6 +199,11 @@ class ImageData(BaseLayoutElement):
|
||||
# The actual image will be loaded in the background and the texture created
|
||||
# via _on_async_image_loaded() callback when ready
|
||||
|
||||
# Create texture from pending image if one exists (deferred from async load)
|
||||
# This ensures texture creation happens when GL context is active
|
||||
if hasattr(self, '_pending_pil_image') and self._pending_pil_image is not None:
|
||||
self._create_texture_from_pending_image()
|
||||
|
||||
# Use cached texture if available
|
||||
if hasattr(self, '_texture_id') and self._texture_id:
|
||||
texture_id = self._texture_id
|
||||
@ -337,12 +342,13 @@ class ImageData(BaseLayoutElement):
|
||||
"""
|
||||
Callback when async image loading completes.
|
||||
|
||||
NOTE: This is called from a signal, potentially before GL context is ready.
|
||||
We store the image and create the texture during the next render() call
|
||||
when the GL context is guaranteed to be active.
|
||||
|
||||
Args:
|
||||
pil_image: Loaded PIL Image (already RGBA, already resized)
|
||||
"""
|
||||
from OpenGL.GL import (glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D,
|
||||
glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR, GL_RGBA, GL_UNSIGNED_BYTE, glDeleteTextures)
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
@ -359,6 +365,38 @@ class ImageData(BaseLayoutElement):
|
||||
pil_image = pil_image.transpose(Image.ROTATE_90) # CCW 270 = rotate left
|
||||
print(f"ImageData: Applied PIL rotation {angle}° to {self.image_path}")
|
||||
|
||||
# Store the image for texture creation during next render()
|
||||
# This avoids GL context issues when callback runs on wrong thread/timing
|
||||
self._pending_pil_image = pil_image
|
||||
self._img_width = pil_image.width
|
||||
self._img_height = pil_image.height
|
||||
self._async_loading = False
|
||||
|
||||
# Update metadata for future renders - always update to reflect rotated dimensions
|
||||
self.image_dimensions = (pil_image.width, pil_image.height)
|
||||
|
||||
# print(f"ImageData: Image ready for texture creation: {self.image_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"ImageData: Error processing async loaded image: {e}")
|
||||
self._pending_pil_image = None
|
||||
self._async_loading = False
|
||||
|
||||
def _create_texture_from_pending_image(self):
|
||||
"""
|
||||
Create OpenGL texture from pending PIL image.
|
||||
Called during render() when GL context is active.
|
||||
"""
|
||||
if not hasattr(self, '_pending_pil_image') or self._pending_pil_image is None:
|
||||
return False
|
||||
|
||||
from OpenGL.GL import (glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D,
|
||||
glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR, GL_RGBA, GL_UNSIGNED_BYTE, glDeleteTextures)
|
||||
|
||||
try:
|
||||
pil_image = self._pending_pil_image
|
||||
|
||||
# Delete old texture if it exists
|
||||
if hasattr(self, '_texture_id') and self._texture_id:
|
||||
glDeleteTextures([self._texture_id])
|
||||
@ -376,19 +414,18 @@ class ImageData(BaseLayoutElement):
|
||||
# Cache texture
|
||||
self._texture_id = texture_id
|
||||
self._texture_path = self.image_path
|
||||
self._img_width = pil_image.width
|
||||
self._img_height = pil_image.height
|
||||
self._async_loading = False
|
||||
|
||||
# Update metadata for future renders - always update to reflect rotated dimensions
|
||||
self.image_dimensions = (pil_image.width, pil_image.height)
|
||||
# Clear pending image to free memory
|
||||
self._pending_pil_image = None
|
||||
|
||||
# print(f"ImageData: Async loaded texture for {self.image_path}")
|
||||
# print(f"ImageData: Created texture for {self.image_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"ImageData: Error creating texture from async loaded image: {e}")
|
||||
print(f"ImageData: Error creating texture: {e}")
|
||||
self._texture_id = None
|
||||
self._async_loading = False
|
||||
self._pending_pil_image = None
|
||||
return False
|
||||
|
||||
def _on_async_image_load_failed(self, error_msg: str):
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user