SDL icon indicating copy to clipboard operation
SDL copied to clipboard

Android wrong pixel format information

Open Zamyk opened this issue 3 years ago • 10 comments

Hello, on android when I use SDL_GetDisplayMode function before creating window it always has bad pixel format - RGB_565. When I use it just after creating window, it most of the time has good pixel format(RGBX_8888), but sometimes RGB_565. But when I use it some time after creating window (I added 300ms delay), it seems to work every time.

#include <SDL.h>

void logDisplayModes() {
  SDL_Log("SDL_GetNumVideoDisplays(): %i", SDL_GetNumVideoDisplays());
  int display_in_use = 0;
  SDL_DisplayMode mode;
  int display_mode_count = SDL_GetNumDisplayModes(display_in_use);
  if (display_mode_count < 1) {
    SDL_Log("SDL_GetNumDisplayModes failed: %s", SDL_GetError());          
  }
  SDL_Log("SDL_GetNumDisplayModes: %i", display_mode_count);
  
  for (int i = 0; i < display_mode_count; ++i) {
    if (SDL_GetDisplayMode(display_in_use, i, &mode) != 0) {
      SDL_Log("SDL_GetDisplayMode failed: %s", SDL_GetError());              
    }
    int f = mode.format;
  
    SDL_Log("Mode %i\tbpp %i\t%s\t%i x %i",
      i, SDL_BITSPERPIXEL(f),
      SDL_GetPixelFormatName(f),
      mode.w, mode.h);
  }  
}


int main(int argc, char* argv[]) {      

  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
      SDL_Log("SDL init failed: %s", SDL_GetError());
      SDL_ClearError();
      return 0;
  }

  int width = 1080;
  int height = 2160;  
  uint32_t flags = 0;
#ifdef ANDROID
  flags = SDL_WINDOW_FULLSCREEN;
#endif  
  logDisplayModes(); // this one outputs RGB_565
  SDL_Window* window = SDL_CreateWindow("AndroidSdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
  if (!window) {
      SDL_Log("Creating window failed: %s", SDL_GetError());
      SDL_ClearError();
      return 0;
  }
  SDL_Delay(300);    // without this delay sometimes (1) and (2) outputs RGB_565
  logDisplayModes(); // (1) outputs RGBX8888
  uint32_t pixelFormat = SDL_GetWindowPixelFormat(window); // (2) outputs RGBX8888
  SDL_Log("Pixel Format == %u %s\n",pixelFormat, SDL_GetPixelFormatName(pixelFormat));   
  SDL_Event event;
  while(true) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        return 0;                        
      }        
    }                      
    SDL_Surface* screenSurf = SDL_GetWindowSurface(window);
    if(screenSurf == nullptr) {
      SDL_Log("((SDL))screen surface was nullptr");
      return 0;
    }
    SDL_FillRect(screenSurf, nullptr, 0xff00ff00);
    if(SDL_UpdateWindowSurface(window) == -1) {
      SDL_Log("((SDL))Error during update window surface %s", SDL_GetError());          
      if(window == nullptr) {
        return  0;
      }
    }    
  }  
  return 0;
}

Logs without delay and bad pixel format(sometimes is same as with delay):

44931:08-07 16:23:47.583  9575  9575 V SDL     : Device: X00TD
44932:08-07 16:23:47.583  9575  9575 V SDL     : Model: Zenfone Max Pro M1
44933:08-07 16:23:47.583  9575  9575 V SDL     : onCreate()
44934:08-07 16:23:47.589  9575  9575 V SDL     : nativeSetupJNI()
44935:08-07 16:23:47.591  9575  9575 V SDL     : AUDIO nativeSetupJNI()
44936:08-07 16:23:47.591  9575  9575 V SDL     : CONTROLLER nativeSetupJNI()
44939:08-07 16:23:47.638  9575  9575 V SDL     : onStart()
44940:08-07 16:23:47.641  9575  9575 V SDL     : onResume()
44952:08-07 16:23:47.700  9575  9575 V SDL     : surfaceCreated()
44953:08-07 16:23:47.700  9575  9575 V SDL     : surfaceChanged()
44954:08-07 16:23:47.700  9575  9575 V SDL     : Window size: 1080x1971
44955:08-07 16:23:47.701  9575  9575 V SDL     : Device size: 1080x2160
44961:08-07 16:23:47.710  9575  9599 V SDL     : Running main function SDL_main from library /data/app/~~KvNPLJtl07hw8hMl2Bxitw==/org.libsdl.app-Ug1Hn5Jo5nGX79hDDToaYg==/lib/arm64/libmain.so
44962:08-07 16:23:47.710  9575  9599 V SDL     : nativeRunMain()
44969:08-07 16:23:47.720  9575  9599 I SDL/APP : SDL_GetNumVideoDisplays(): 1
44971:08-07 16:23:47.721  9575  9599 I SDL/APP : SDL_GetNumDisplayModes: 1
44972:08-07 16:23:47.721  9575  9599 I SDL/APP : Mode 0	bpp 16	SDL_PIXELFORMAT_RGB565	1080 x 2160
44974:08-07 16:23:47.726  9575  9599 V SDL     : setOrientation() requestedOrientation=7 width=1080 height=2160 resizable=false hint=
44978:08-07 16:23:47.729  9575  9599 I SDL/APP : pixel format wanted SDL_PIXELFORMAT_RGBX8888 (2), got SDL_PIXELFORMAT_RGBX8888 (2)
44981:08-07 16:23:47.783  1454  1561 I ActivityTaskManager: Displayed org.libsdl.app/.SDLActivity: +406ms
44983:08-07 16:23:47.817  9575  9575 V SDL     : surfaceChanged()
44984:08-07 16:23:47.817  9575  9575 V SDL     : Window size: 1080x2160
44985:08-07 16:23:47.817  9575  9575 V SDL     : Device size: 1080x2160
44986:08-07 16:23:47.818  9575  9599 I SDL/APP : SDL_GetNumVideoDisplays(): 1
44987:08-07 16:23:47.818  9575  9599 I SDL/APP : SDL_GetNumDisplayModes: 1
44988:08-07 16:23:47.818  9575  9599 I SDL/APP : Mode 0	bpp 16	SDL_PIXELFORMAT_RGB565	1080 x 2160
44989:08-07 16:23:47.818  9575  9599 I SDL/APP : Pixel Format == 353701890 SDL_PIXELFORMAT_RGB565
44990:08-07 16:23:47.830  9575  9575 V SDL     : onWindowFocusChanged(): true
44991:08-07 16:23:47.830  9575  9575 V SDL     : nativeFocusChanged()

Logs with delay:

44726:08-07 16:23:43.318  9514  9514 V SDL     : Device: X00TD
44727:08-07 16:23:43.318  9514  9514 V SDL     : Model: Zenfone Max Pro M1
44728:08-07 16:23:43.318  9514  9514 V SDL     : onCreate()
44729:08-07 16:23:43.324  9514  9514 V SDL     : nativeSetupJNI()
44730:08-07 16:23:43.325  9514  9514 V SDL     : AUDIO nativeSetupJNI()
44731:08-07 16:23:43.325  9514  9514 V SDL     : CONTROLLER nativeSetupJNI()
44735:08-07 16:23:43.371  9514  9514 V SDL     : onStart()
44736:08-07 16:23:43.374  9514  9514 V SDL     : onResume()
44747:08-07 16:23:43.429  9514  9514 V SDL     : surfaceCreated()
44748:08-07 16:23:43.429  9514  9514 V SDL     : surfaceChanged()
44750:08-07 16:23:43.430  9514  9514 V SDL     : Window size: 1080x1971
44751:08-07 16:23:43.430  9514  9514 V SDL     : Device size: 1080x2160
44757:08-07 16:23:43.439  9514  9537 V SDL     : Running main function SDL_main from library /data/app/~~KvNPLJtl07hw8hMl2Bxitw==/org.libsdl.app-Ug1Hn5Jo5nGX79hDDToaYg==/lib/arm64/libmain.so
44758:08-07 16:23:43.439  9514  9537 V SDL     : nativeRunMain()
44762:08-07 16:23:43.449  9514  9537 I SDL/APP : SDL_GetNumVideoDisplays(): 1
44763:08-07 16:23:43.449  9514  9537 I SDL/APP : SDL_GetNumDisplayModes: 1
44764:08-07 16:23:43.449  9514  9537 I SDL/APP : Mode 0	bpp 16	SDL_PIXELFORMAT_RGB565	1080 x 2160
44766:08-07 16:23:43.454  9514  9537 V SDL     : setOrientation() requestedOrientation=7 width=1080 height=2160 resizable=false hint=
44770:08-07 16:23:43.458  9514  9537 I SDL/APP : pixel format wanted SDL_PIXELFORMAT_RGBX8888 (2), got SDL_PIXELFORMAT_RGBX8888 (2)
44777:08-07 16:23:43.516  1454  1561 I ActivityTaskManager: Displayed org.libsdl.app/.SDLActivity: +409ms
44779:08-07 16:23:43.553  9514  9514 V SDL     : surfaceChanged()
44780:08-07 16:23:43.553  9514  9514 V SDL     : Window size: 1080x2160
44781:08-07 16:23:43.553  9514  9514 V SDL     : Device size: 1080x2160
44782:08-07 16:23:43.554  9514  9537 I SDL/APP : SDL_GetNumVideoDisplays(): 1
44783:08-07 16:23:43.554  9514  9537 I SDL/APP : SDL_GetNumDisplayModes: 1
44784:08-07 16:23:43.554  9514  9537 I SDL/APP : Mode 0	bpp 24	SDL_PIXELFORMAT_RGBX8888	1080 x 2160
44785:08-07 16:23:43.554  9514  9537 I SDL/APP : Pixel Format == 371595268 SDL_PIXELFORMAT_RGBX8888
44786:08-07 16:23:43.566  9514  9514 V SDL     : onWindowFocusChanged(): true
44787:08-07 16:23:43.566  9514  9514 V SDL     : nativeFocusChanged()

Zamyk avatar Aug 07 '22 14:08 Zamyk

yes, this is true. in fact the variable is by default RGB_565. https://github.com/libsdl-org/SDL/blob/main/src/video/android/SDL_androidvideo.c#L67

When the android window is created (java call surfaceChanged), it asynchronously updates the value. maybe you can wait for an event to have a valid value (maybe SDL_WINDOWEVENT_RESTORED).

some workaround:

1/ If you create yourself the SDL_Renderer, the value should be ok, after SDL_CreateRenderer is called().

2/ there used to be issues on some phone.. and we would always set SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); and so the format would always be 565

1bsyl avatar Aug 24 '22 21:08 1bsyl

Thank you for reply. I tried adding SDL_GL_SetAttribute[...], but it doesn't work for me(pixel format is RGBX888). Maybe I'm doing something wrong. Do you have example that should work? Because having only one pixel format would be very helpful for me. Here I tried with SDL_Renderer(it doesn't work either way), but I would prefer to not use it, because rendering SDL_Surface seems to be faster with SDL_UpdateWindowSurface.

Here is code:

int main(int argc, char* argv[]) {      

  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
      SDL_Log("SDL init failed: %s", SDL_GetError());
      SDL_ClearError();
      return 0;
  }

  int width = 1080;
  int height = 2160;  
  uint32_t flags = 0; // also tried with SDL_WINDOW_OPENGL
#ifdef ANDROID
  flags |= SDL_WINDOW_FULLSCREEN;
#endif 
  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);       
  SDL_Window* window = SDL_CreateWindow("AndroidSdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
  if (!window) {
      SDL_Log("Creating window failed: %s", SDL_GetError());
      SDL_ClearError();
      return 0;
  }      
  SDL_Renderer* rend = SDL_CreateRenderer(window, -1, 0);
  SDL_Delay(300);    // without this delay sometimes (1) and (2) outputs RGB_565
  logDisplayModes(); // (1) outputs RGBX8888
  uint32_t pixelFormat = SDL_GetWindowPixelFormat(window); // (2) outputs RGBX8888
  SDL_Log("Pixel Format == %u %s\n",pixelFormat, SDL_GetPixelFormatName(pixelFormat));   
  SDL_Event event;
  while(true) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        return 0;                        
      }        
    }                      
    //SDL_Surface* screenSurf = SDL_GetWindowSurface(window);
    //if(screenSurf == nullptr) {
    //  SDL_Log("((SDL))screen surface was nullptr");
    //  return 0;
    //}
    //SDL_FillRect(screenSurf, nullptr, 0xff00ff00);
    //if(SDL_UpdateWindowSurface(window) == -1) {
    //  SDL_Log("((SDL))Error during update window surface %s", SDL_GetError());          
    //  if(window == nullptr) {
    //    return  0;
    //  }
    //}    
  }  
  return 0;
}

Zamyk avatar Aug 25 '22 14:08 Zamyk

can you add also :

SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);

after SDL_Init() and before the SDL_CreateWindow(). So the place is corret.

The line interesting for you is: SDL/APP : pixel format wanted SDL_PIXELFORMAT_RGBX8888 (2), got SDL_PIXELFORMAT_RGBX8888 (2) Here, EGL context requests (and got) a 8888 pixel format

Using the SDL_Renderer should be the prefered way. You create your SDL_Texture once, and use them to render. You can also createSDL_Texture with STREAMING access for some operation, if you need to modify them. it's up to you anyway.

1bsyl avatar Aug 28 '22 20:08 1bsyl

I tried adding the SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0), but still EGL requests 8888. I tried it on linux, and pixel format, also doesn't change (it is rgb888 as before).

Zamyk avatar Aug 31 '22 10:08 Zamyk

just to be sure: you added the 4 lines:

SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);

there is a "FAVOR_TRUECOLOR" define: https://github.com/libsdl-org/SDL/blob/main/src/video/SDL_egl.c#L889

can you try to un-activate it ? maybe this promote a 565 to 888 context (please copy paste the "SDL/APP : pixel format wanted" log line)

Eventually, other try: by-pass the code that is meant to find the closest config. https://github.com/libsdl-org/SDL/blob/main/src/video/SDL_egl.c#L833 at this line, just return the first config:

_this->egl_data->egl_config = configs[0];
return 0;

1bsyl avatar Aug 31 '22 20:08 1bsyl

Logs with

SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);

pixel format wanted SDL_PIXELFORMAT_RGBX8888 (2), got SDL_PIXELFORMAT_RGBX8888 (2)

With deactivated FAVOR_TRUECOLOR define:

pixel format wanted SDL_PIXELFORMAT_RGB565 (4), got SDL_PIXELFORMAT_UNKNOWN (277)

With

_this->egl_data->egl_config = configs[0];
return 0;

pixel format wanted SDL_PIXELFORMAT_RGBX8888 (2), got SDL_PIXELFORMAT_RGBX8888 (2)

Zamyk avatar Sep 03 '22 09:09 Zamyk

So it looks like the FAVOR_TRUECOLOR define prevents you to get the the 565 configuration, because it promotes your request as a RGB888 request.

But there is a second thing: when you request 565, it gives you back something unknown. This is the value returned by ANativeWindow_getFormat() in SDL code ( https://developer.android.com/ndk/reference/group/a-native-window#anativewindow_getformat ), and it matches none of the AHARDWAREBUFFER_FORMAT_ enumeration.) ( https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativewindow/include/android/hardware_buffer.h?autodive=0%2F%2F#59 )

But the 277 seems to have some sense anyway, because it is some OEM specific HAL formats https://android.googlesource.com/platform/hardware/qcom/display/+/master/msm8909/gralloc/gralloc_priv.h#127 #define HAL_PIXEL_FORMAT_BGR_565 0x115 maybe we can just make SDL aware of it

1bsyl avatar Sep 03 '22 21:09 1bsyl

Thank you, now it works. :)

Zamyk avatar Sep 04 '22 13:09 Zamyk

ok great ! can you tell which device you're using for the record ?

1bsyl avatar Sep 04 '22 18:09 1bsyl

I'm using asus zenfone max pro m1. Also (I don't know if it matters), I have custom android ROM (lineageos 19, android 12).

Zamyk avatar Sep 05 '22 16:09 Zamyk