@@ -119,6 +119,21 @@ module UIImageModule
119119
120120 # Determine which texture to use
121121 texture_to_render = (this. useEffectTexture && ! isempty (this. effects) && this. effectTexture != C_NULL ) ? this. effectTexture : this. texture
122+
123+ # Validate texture if we're using effect texture
124+ if texture_to_render == this. effectTexture && texture_to_render != C_NULL
125+ # Query texture to check if it's still valid
126+ w = Ref {Cint} (0 ); h = Ref {Cint} (0 )
127+ fmt = Ref {UInt32} (0 ); access = Ref {Cint} (0 )
128+ if SDL2. SDL_QueryTexture (texture_to_render, fmt, access, w, h) != 0
129+ # Texture is invalid, fall back to base texture and clear effect texture
130+ @debug " Effect texture is invalid for $(this. name) , falling back to base texture"
131+ this. effectTexture = C_NULL
132+ texture_to_render = this. texture
133+ this. needsEffectUpdate = true
134+ end
135+ end
136+
122137 # Create texture if it doesn't exist
123138 if texture_to_render == C_NULL && this. texture == C_NULL
124139 @debug " Creating texture from surface because it doesn't exist for image: $(this. name) "
@@ -406,10 +421,14 @@ module UIImageModule
406421 end
407422
408423 function generate_effect_cache_key (this:: UIImage ):: String
409- # Cache key excludes position/rotation (and other transform-only changes)
410- # Effects depend on source image, color, and effect params
424+ # Cache key must be unique per instance to prevent texture sharing issues
425+ # When textures are shared and one instance destroys it, other instances
426+ # end up with invalid texture pointers
427+ # Include instance ID to ensure each sprite has its own effect texture
411428 content = string (
429+ this. id, " |" , # Instance ID - prevents sharing across different sprites
412430 this. path, " |" ,
431+ this. size. x, " x" , this. size. y, " |" ,
413432 this. color, " |" ,
414433 serialize_effects (this. effects)
415434 )
@@ -459,7 +478,11 @@ module UIImageModule
459478 # Use cached texture if available
460479 if haskey (EFFECT_CACHE, this. effectCacheKey)
461480 @debug (" UIImage using cached effect texture" , name= this. name, key= this. effectCacheKey)
462- this. effectTexture = EFFECT_CACHE[this. effectCacheKey]
481+ cached_texture = EFFECT_CACHE[this. effectCacheKey]
482+
483+ # Since cache keys include instance ID, cached texture is ours
484+ # Just use it directly (it's already assigned to this instance)
485+ this. effectTexture = cached_texture
463486 if this. effectTexture != C_NULL
464487 w = Ref {Cint} (0 ); h = Ref {Cint} (0 )
465488 fmt = Ref {UInt32} (0 ); access = Ref {Cint} (0 )
@@ -493,6 +516,13 @@ module UIImageModule
493516 end
494517 end
495518
519+ # Destroy old effect texture before creating new one
520+ # (cache keys include instance ID, so this texture is exclusively ours)
521+ if this. effectTexture != C_NULL
522+ SDL2. SDL_DestroyTexture (this. effectTexture)
523+ this. effectTexture = C_NULL
524+ end
525+
496526 # Create target for effects and apply
497527 target = EffectsModule. ImageTarget (this)
498528 try
@@ -504,7 +534,8 @@ module UIImageModule
504534 fmt = Ref {UInt32} (0 ); access = Ref {Cint} (0 )
505535 SDL2. SDL_QueryTexture (this. effectTexture, fmt, access, w, h)
506536 this. effectSize = Math. Vector2 (w[], h[])
507- # Cache it
537+
538+ # Cache it (cache key includes instance ID, so no sharing issues)
508539 cache_effect_texture (this. effectCacheKey, this. effectTexture)
509540 end
510541 this. needsEffectUpdate = false
0 commit comments