Просмотр исходного кода

app: fix potential bug on exit due to already dropped anim when draw() is called after window quit request. see below for more detailed info.

= Crash =

1. User quits -> god.stop_app() -> runtime stops
2. Arc<ManagedSeqAnim> drops -> delete_unmanaged_anim() -> animation removed from self.anims
3. miniquad event loop calls draw() one more time
4. draw_call() hits GfxDrawInstruction::Animation(anim_id) -> self.anims.get_mut(&anim_id).unwrap()
   PANIC! Animation was already deleted in step 2

= Cause =

- DrawCall holds Animation(AnimId) - just an ID, not a reference
- self.anims: HashMap<AnimId, GfxSeqAnim> stores actual animation data
- ManagedSeqAnim::drop() removes animation from self.anims
- DrawCalls may still reference deleted animations
- Race during shutdown: animations deleted before final draw()

= Fix =

Change Animation(AnimId) to Animation(ManagedSeqAnimPtr):
- Arc keeps ManagedSeqAnim alive as long as DrawCall exists
- Drop only fires when all DrawCalls are dropped
- Animation stays in self.anims until safe to delete
- Uses Rust ownership to prevent bug at compile time
jkds 7 месяцев назад
Родитель
Сommit
6b9ef3aff2
3 измененных файлов с 10 добавлено и 10 удалено
  1. 8 8
      bin/app/src/gfx/mod.rs
  2. 1 1
      bin/app/src/gfx/trax.rs
  3. 1 1
      bin/app/src/ui/vid/mod.rs

+ 8 - 8
bin/app/src/gfx/mod.rs

@@ -472,14 +472,14 @@ impl AsyncEncodable for DrawMesh {
     }
 }
 
-#[derive(Debug, Clone, SerialEncodable)]
+#[derive(Debug, Clone)]
 pub enum DrawInstruction {
     SetScale(f32),
     Move(Point),
     SetPos(Point),
     ApplyView(Rectangle),
     Draw(DrawMesh),
-    Animation(AnimId),
+    Animation(ManagedSeqAnimPtr),
     EnableDebug,
     SetPipeline(GraphicPipeline),
 }
@@ -506,7 +506,7 @@ impl DrawInstruction {
     }
 }
 
-#[derive(Clone, Debug, Default, SerialEncodable)]
+#[derive(Clone, Debug, Default)]
 pub struct DrawCall {
     pub instrs: Vec<DrawInstruction>,
     pub dcs: Vec<DcId>,
@@ -560,7 +560,7 @@ enum GfxDrawInstruction {
     SetPos(Point),
     ApplyView(Rectangle),
     Draw(GfxDrawMesh),
-    Animation(AnimId),
+    Animation(ManagedSeqAnimPtr),
     EnableDebug,
     SetPipeline(GraphicPipeline),
 }
@@ -721,10 +721,10 @@ impl<'a> RenderContext<'a> {
                     self.ctx.apply_bindings(&bindings);
                     self.ctx.draw(0, mesh.num_elements, 1);
                 }
-                GfxDrawInstruction::Animation(anim_id) => {
-                    let anim = self.anims.get_mut(&anim_id).unwrap();
-                    anim.is_visible = true;
-                    if let Some(dc) = anim.tick() {
+                GfxDrawInstruction::Animation(anim) => {
+                    let gfx_anim = self.anims.get_mut(&anim.id).unwrap();
+                    gfx_anim.is_visible = true;
+                    if let Some(dc) = gfx_anim.tick() {
                         self.draw_call(&dc, indent + 1, is_debug);
                     }
                 }

+ 1 - 1
bin/app/src/gfx/trax.rs

@@ -57,7 +57,7 @@ impl Trax {
         0u8.encode(&mut self.buf).unwrap();
         epoch.encode(&mut self.buf).unwrap();
         batch_id.encode(&mut self.buf).unwrap();
-        dcs.encode(&mut self.buf).unwrap();
+        //dcs.encode(&mut self.buf).unwrap();
     }
 
     pub fn put_start_batch(

+ 1 - 1
bin/app/src/ui/vid/mod.rs

@@ -250,7 +250,7 @@ impl Video {
                     vec![
                         DrawInstruction::SetPipeline(GraphicPipeline::YUV),
                         DrawInstruction::Move(rect.pos()),
-                        DrawInstruction::Animation(vid_data.anim.id),
+                        DrawInstruction::Animation(vid_data.anim.clone()),
                     ],
                     vec![],
                     self.z_index.get(),