⚠️ Clean-Room / Educational

This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.

Fix PPU: white framebuffer with high TileData (render_bg/render_window/swap)

📋 Executive Summary

⚠️ REVERSED ATTEMPT

This Step attempted to correct the gating criteriavram_has_tiles_which was too strict for CGB games with high tiledata but low diversity of unique tile IDs. The changes were reverted because they did not completely resolve the white framebuffer issue.

Identified Problem:

  • Games liketetris_dx.gbcandzelda-dx.gbcthey reportedtiledata_effectivehigh (56.6% and 79.0%) butfb_nonzero=0/23040(completely white framebuffer).
  • The criterion ofvram_has_tiles_required diversity >= 5 unique tile IDs, butzelda-dx.gbcI only had 1 unique tile ID.

Tried Solution:

  • Relax criteria to allow render whentiledata_effective >= 200althoughunique_tile_idsbe low (>= 1) in CGB mode.
  • Conditional override:cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1).

Result:

  • tetris_dx.gbc: Significant improvement -vram_has_tiles_activates correctly (Frame 676).
  • ⚠️ zelda-dx.gbc: vram_has_tiles_is activated (Frame 13) but framebuffer is still blank.
  • ❌ The changes were reverted because the problem persists (requires further investigation).

🔧 Hardware Concept

Tiles Detection Criteria in VRAM

Fountain:Pan Docs - "Video RAM", "Tile Data", "Background Tile Map"

The PPU needs to determine when there are valid tiles in VRAM to decide whether to render the background or display a checkerboard. In real games, especially during initialization or screen transitions, there may be situations where there is tile data loaded but with low diversity of unique tile IDs in the tilemap.

Original Problem:

The previous criterion required both useful data (tiledata_nonzero >= 200eithercomplete_tiles >= 10) ANDdiversity in the tilemap (unique_tile_ids >= 5). This caused false negatives in CGB games likezelda-dx.gbcwhich have high tiledata but only 1 unique tile ID.

Attempted Solution (Reversed):

Relax criteria for CGB mode: yestiledata_effective >= 200andunique_tile_ids >= 1, allow rendering even if diversity is low.

// Original criterion (strict)
vram_has_tiles_ = has_tiles_data && has_tilemap_diversity;

// Tried criterion (relaxed for CGB) - REVERSED
bool cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1);
vram_has_tiles_ = has_tiles_data && (has_tilemap_diversity || cgb_high_tiledata_override);

Why it was Reverted:

Although the change improved the activation ofvram_has_tiles_, the framebuffer kept going blank onzelda-dx.gbc. This suggests that the problem is not just gating but that there is another problem in the rendering pipeline (possibly tile routing, framebuffer swapping, or incorrect cleanup).

💻 Implementation

Modified Files (Reverted Changes):

  • src/core/cpp/PPU.cpp- Lines ~1559-1578 (functionrender_scanline())

Attempted Change:

// Calculation of tiledata_effective for CGB
int tiledata_bank1 = count_vram_nonzero_bank1_tiledata();
int tiledata_effective = (tiledata_nonzero > tiledata_bank1) ? tiledata_nonzero : tiledata_bank1;

// Override for CGB with high tiledata
bool cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1);

// New criteria
vram_has_tiles_ = has_tiles_data && (has_tilemap_diversity || cgb_high_tiledata_override);

🧪 Tests and Verification

Compilation:

$python3 setup.py build_ext --inplace
✅ Compilation successful (exit code: 0)

Parallel Suite (2 minutes, all ROMs):

$ export VBC_SUITE=1
$ # Parallel execution of 8 ROMs
✅ Suite completed (exit code: 0)

Log Evidence:

tetris_dx.gbc:

[VRAM-STATE-CHANGE] Frame 676 | has_tiles: 0 -> 1 | tiledata: 4032/4032 | tiles: 252/384 | unique_ids: 185
[VIDEO-SUMMARY] Frame 700 | tiledata=56.6% | tiles: 252/384 | unique_ids: 185 | fb_nonzero: 15360/23040 (66.7%)
[CGB-RGB-CHECK] Frame 700 | Non-white pixels: YES (66.7%)

Significant improvement: vram_has_tiles_activates correctly, framebuffer has non-white pixels.

zelda-dx.gbc:

[VRAM-STATE-CHANGE] Frame 13 | has_tiles: 0 -> 1 | tiledata: 5632/5632 | tiles: 352/384 | unique_ids: 1
[VIDEO-SUMMARY] Frame 700 | tiledata=79.0% | tiles: 352/384 | unique_ids: 1 | fb_nonzero: 0/23040 (0.0%)
[CGB-RGB-CHECK] Frame 700 | Non-white pixels: NO (all white or black)

⚠️ Problem persists: vram_has_tiles_activates but framebuffer is still completely white (0%).

🔍 Post-Mortem Analysis

Key Findings:

  1. Gating is not the only problem: Althoughvram_has_tiles_activates correctly inzelda-dx.gbc, the framebuffer is still white.
  2. Low diversity may be valid: zelda-dx.gbchas 352 full tiles but only 1 unique tile ID (possibly loads the same tile on the entire screen during initialization).
  3. Deeper problem: Inline rendering does not usevram_has_tiles_like gating (the for loop inrender_scanline()doesn't check this flag), so there must be another problem:
    • Incorrect tile addressing
    • Framebuffer swap not working correctly
    • Incorrect framebuffer cleanup
    • problem inget_tile_color_for_bg()

Why it was Reverted:

  • The change improves the behavior oftetris_dx.gbcbut it doesn't solvezelda-dx.gbc.
  • The relaxed criteria could cause false positives in other games.
  • A deeper investigation of the rendering pipeline is needed before modifying the gating.

Suggested Next Steps (for future Steps):

  1. Instrument the inline rendering loop inrender_scanline()to check what color values ​​are written to the framebuffer.
  2. Verify thatswap_framebuffers()correctly swaps front/back pointers.
  3. Auditget_tile_color_for_bg()with real datazelda-dx.gbc.
  4. Consider whether the problem is specific to CGB (VRAM banks, CGB paddles).

🎯 Conclusion

This Step documented an attempt to correct the criteria ofvram_has_tiles_which was reverted because it didn't completely solve the white framebuffer issue. The changes were beneficial fortetris_dx.gbcbut insufficient forzelda-dx.gbc.

The analysis revealed that the white framebuffer problem is not just the gating ofvram_has_tiles_but rather there is a deeper issue in the rendering pipeline that requires additional investigation.

Final State:DRAFT/REVERT - Code changes were reverted but documentation is maintained for traceability.