Skip to content

Commit dc4b5d6

Browse files
authored
Merge pull request #286 from winnerspiros/copilot/fix-vulkan-renderer-crash
Android: fix Vulkan black screen by forcing RGBA8888 on the SurfaceHolder
2 parents 5bca2b4 + 793f856 commit dc4b5d6

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

osu.Android/OsuGameActivity.cs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,33 @@ protected override void OnCreate(Bundle? savedInstanceState)
249249
{
250250
try
251251
{
252-
GetSurface()?.Holder?.AddCallback(this);
252+
var holder = GetSurface()?.Holder;
253+
254+
if (holder != null)
255+
{
256+
// Request RGBA8888 on the Android SurfaceHolder unconditionally BEFORE
257+
// registering our callback. Without this, Android defaults to RGB565
258+
// for the SurfaceView when no renderer explicitly requests a different
259+
// format — SDL3 only calls setFormat(RGBA8888) for OpenGL, not Vulkan,
260+
// so Vulkan sessions receive an RGB565 ANativeWindow. An RGB565 swapchain
261+
// is incompatible with our 8-bit-per-channel rendering pipeline and
262+
// causes a black screen followed by a native Draw-thread crash on Adreno
263+
// GPUs (evidenced by SDL_PIXELFORMAT_RGB565 + "drawable size 3088×1440"
264+
// in the runtime log for every Vulkan crash session). RGBA8888 is what
265+
// OpenGL already uses and is the correct baseline for all renderers.
266+
// Calling SetFormat before AddCallback ensures the format is stamped
267+
// on the SurfaceHolder before SDL creates the VkAndroidSurfaceKHR.
268+
try
269+
{
270+
holder.SetFormat(global::Android.Graphics.Format.Rgba8888);
271+
}
272+
catch (Exception e)
273+
{
274+
Debug.WriteLine($"[osu!] Failed to request RGBA8888 surface format: {e.Message}");
275+
}
276+
277+
holder.AddCallback(this);
278+
}
253279
}
254280
catch (Exception e)
255281
{
@@ -586,6 +612,43 @@ public void SurfaceCreated(ISurfaceHolder holder)
586612

587613
public void SurfaceChanged(ISurfaceHolder holder, global::Android.Graphics.Format format, int width, int height)
588614
{
615+
// Guard: if the Android surface materialised with a 16-bit pixel format (RGB565)
616+
// while Vulkan is configured, request a format change to RGBA8888 immediately.
617+
//
618+
// Root cause: SDL3 only calls setFormat(RGBA8888) for OpenGL, not Vulkan.
619+
// Android's default SurfaceView pixel format on many displays (especially high-
620+
// density landscape panels) is RGB565. An RGB565 ANativeWindow means the Vulkan
621+
// WSI can only negotiate R5G6B5_UNORM as the swapchain format, which is
622+
// incompatible with our 8-bit-per-channel pipeline and produces a black screen
623+
// followed by a native Draw-thread crash on Adreno GPUs.
624+
//
625+
// The proactive SetFormat(RGBA8888) call in the DecorView.Post lambda above is
626+
// the primary fix (runs before the Surface is typically created). This reactive
627+
// guard is the belt-and-braces fallback for timing windows where the Surface is
628+
// already created when the Post fires (e.g. rapid cold-starts, system-restored
629+
// windows). Calling SetFormat here triggers SurfaceDestroyed + SurfaceCreated +
630+
// SurfaceChanged with the corrected format; Veldrid's VkSurfaceKHR-loss recovery
631+
// picks up the new ANativeWindow and negotiates a proper BGRA/RGBA 8-bit swapchain.
632+
if (format == global::Android.Graphics.Format.Rgb565 && LogManagement.IsVulkanConfigured())
633+
{
634+
Logger.Log(
635+
"[osu!] Android surface pixel format RGB565 is incompatible with the Vulkan rendering pipeline " +
636+
"— requesting RGBA8888 and triggering a surface recreate. " +
637+
"This is the root cause of the Vulkan black-screen crash on Adreno (SDL_PIXELFORMAT_RGB565 in runtime log). " +
638+
"The next SurfaceChanged will carry the corrected format.",
639+
LoggingTarget.Performance,
640+
LogLevel.Important);
641+
642+
try
643+
{
644+
holder.SetFormat(global::Android.Graphics.Format.Rgba8888);
645+
}
646+
catch (Exception e)
647+
{
648+
Debug.WriteLine($"[osu!] Failed to request RGBA8888 format change for Vulkan: {e.Message}");
649+
}
650+
}
651+
589652
if (width > 0 && height > 0)
590653
{
591654
surfaceEvent.Set();

0 commit comments

Comments
 (0)