Skip to content

[rcore][drm] SUPPORT_DRM_CACHE stops presenting after 2 page flips on Mali (RK3326) #6056

Description

@jtakakura

Please, before submitting a new issue verify and check:

  • I tested it on latest raylib version from master branch
  • I checked there is no similar issue already reported
  • I checked the documentation on the wiki
  • My code has no errors or misuse of raylib

Issue description

Follow-up to #4988, where more testing and benchmarking was asked for before making the cached path the default. I have an R36S, which uses ARM's Mali blob rather than mesa, so the results are different from the Raspberry Pi it was developed on.

With SUPPORT_DRM_CACHE defined, the screen never updates. Not "runs and then freezes" — nothing appears after the first couple of frames. The game loop is unaffected: my log shows it running at 39-60 fps, button presses still change scenes, and the program exits cleanly. Only presentation is dead.

I interposed on libdrm and gbm to see what happens:

addfb      call=1 rc=0 handle=1
addfb      call=2 rc=0 handle=2
addfb      call=3 rc=0 handle=4
lock_front call=1 bo=0x512a790 NEW distinct=1
lock_front call=2 bo=0x52390d0 NEW distinct=2
lock_front call=3 bo=0x5238b20 NEW distinct=3
lock_front call=4 bo=0x51ab430 NEW distinct=4
pageflip   call=1 rc=0
pageflip   call=2 rc=0

After this there are no further drmModeAddFB and no further drmModePageFlip calls for the rest of the session, while gbm_surface_lock_front_buffer() and gbm_surface_release_buffer() keep being called every frame. lock_front never returns NULL, so this is not buffer exhaustion.

gbm_surface_lock_front_buffer() hands out a 4th distinct gbm_bo pointer on this driver. fbCache holds MAX_DRM_CACHED_BUFFERS = 3 and GetOrCreateFbForBo() has no eviction, so from the 4th buffer on it takes

if (fbCacheCount >= MAX_DRM_CACHED_BUFFERS) return 0; // FB cache full

and SwapScreenBuffer() releases the buffer and returns before the page flip, every frame, permanently. errCnt[2] counts exactly this, but the block that prints the counters is commented out.

I would guess mesa reuses the same three buffers, which would explain why this does not show up on a Pi.

Would keying off gbm_bo_get_user_data() instead of the fixed array work? The code already calls gbm_bo_set_user_data() with the fb id for DestroyFrameBufferCallback.

The default path works fine on the same device: 25.57 ms per frame (39.1 fps, exactly two vblanks of the 78.2 Hz panel), and it stays at 25.57 ms even with 24 full-screen alpha-blended quads. So the cached path would be a large win here if it worked.

I am happy to test patches, I have the hardware.

Environment

  • Device: R36S (Rockchip RK3326, Cortex-A35), ArkOS (Ubuntu 19.10, glibc 2.30)
  • GPU: Mali-G31, libmali-bifrost-g31-rxp0-gbm.so, OpenGL ES 3.2, EGL 1.4
  • Panel: 640x480 at 78.2 Hz (DRM mode 640x480p78)
  • raylib 6.0 with PLATFORM_DRM, GRAPHICS_API_OPENGL_ES2, cross-compiled with Zig. GetOrCreateFbForBo() and SwapScreenBuffer() are byte-identical between 6.0 and master (d46a593), so this is not fixed on master.

To reach this bug at all on a Mali blob you first have to get past #5777 — this driver does not export eglGetPlatformDisplay, so the binary will not start. I worked around it by defining that symbol myself and falling back to eglGetProcAddress("eglGetPlatformDisplayEXT") and then eglGetDisplay(). Separate bug, same device; mentioning it only so this is reproducible.

Issue Screenshot

Not useful here — the symptom is that the screen never changes.

Code Example

Any program is enough; it fails before anything is drawn. On a Mali device you also need the #5777 workaround described above, or it will not start.

#include "raylib.h"

int main(void)
{
    InitWindow(640, 480, "drm cache test");
    SetTargetFPS(60);

    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(GetTime() - (int)GetTime() < 0.5 ? RED : BLUE);
        EndDrawing();
    }

    CloseWindow();
    return 0;
}

Built with SUPPORT_DRM_CACHE the screen stays on one colour forever; without it, it alternates as expected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions