sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_rpivideo.c (13375B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 
     22 #include "../../SDL_internal.h"
     23 
     24 #if SDL_VIDEO_DRIVER_RPI
     25 
     26 /* References
     27  * http://elinux.org/RPi_VideoCore_APIs
     28  * https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle/triangle.c
     29  * http://cgit.freedesktop.org/wayland/weston/tree/src/rpi-renderer.c
     30  * http://cgit.freedesktop.org/wayland/weston/tree/src/compositor-rpi.c
     31  */
     32 
     33 /* SDL internals */
     34 #include "../SDL_sysvideo.h"
     35 #include "SDL_version.h"
     36 #include "SDL_syswm.h"
     37 #include "SDL_loadso.h"
     38 #include "SDL_events.h"
     39 #include "../../events/SDL_mouse_c.h"
     40 #include "../../events/SDL_keyboard_c.h"
     41 #include "SDL_hints.h"
     42 
     43 #ifdef SDL_INPUT_LINUXEV
     44 #include "../../core/linux/SDL_evdev.h"
     45 #endif
     46 
     47 /* RPI declarations */
     48 #include "SDL_rpivideo.h"
     49 #include "SDL_rpievents_c.h"
     50 #include "SDL_rpiopengles.h"
     51 #include "SDL_rpimouse.h"
     52 
     53 static void
     54 RPI_Destroy(SDL_VideoDevice * device)
     55 {
     56     SDL_free(device->driverdata);
     57     SDL_free(device);
     58 }
     59 
     60 static int 
     61 RPI_GetRefreshRate()
     62 {
     63     TV_DISPLAY_STATE_T tvstate;
     64     if (vc_tv_get_display_state( &tvstate ) == 0) {
     65         //The width/height parameters are in the same position in the union
     66         //for HDMI and SDTV
     67         HDMI_PROPERTY_PARAM_T property;
     68         property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
     69         vc_tv_hdmi_get_property(&property);
     70         return property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? 
     71             tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) : 
     72             tvstate.display.hdmi.frame_rate;
     73     } 
     74     return 60;  /* Failed to get display state, default to 60 */
     75 }
     76 
     77 static SDL_VideoDevice *
     78 RPI_Create()
     79 {
     80     SDL_VideoDevice *device;
     81     SDL_VideoData *phdata;
     82 
     83     /* Initialize SDL_VideoDevice structure */
     84     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
     85     if (device == NULL) {
     86         SDL_OutOfMemory();
     87         return NULL;
     88     }
     89 
     90     /* Initialize internal data */
     91     phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
     92     if (phdata == NULL) {
     93         SDL_OutOfMemory();
     94         SDL_free(device);
     95         return NULL;
     96     }
     97 
     98     device->driverdata = phdata;
     99 
    100     /* Setup amount of available displays */
    101     device->num_displays = 0;
    102 
    103     /* Set device free function */
    104     device->free = RPI_Destroy;
    105 
    106     /* Setup all functions which we can handle */
    107     device->VideoInit = RPI_VideoInit;
    108     device->VideoQuit = RPI_VideoQuit;
    109     device->GetDisplayModes = RPI_GetDisplayModes;
    110     device->SetDisplayMode = RPI_SetDisplayMode;
    111     device->CreateSDLWindow = RPI_CreateWindow;
    112     device->CreateSDLWindowFrom = RPI_CreateWindowFrom;
    113     device->SetWindowTitle = RPI_SetWindowTitle;
    114     device->SetWindowIcon = RPI_SetWindowIcon;
    115     device->SetWindowPosition = RPI_SetWindowPosition;
    116     device->SetWindowSize = RPI_SetWindowSize;
    117     device->ShowWindow = RPI_ShowWindow;
    118     device->HideWindow = RPI_HideWindow;
    119     device->RaiseWindow = RPI_RaiseWindow;
    120     device->MaximizeWindow = RPI_MaximizeWindow;
    121     device->MinimizeWindow = RPI_MinimizeWindow;
    122     device->RestoreWindow = RPI_RestoreWindow;
    123     device->SetWindowGrab = RPI_SetWindowGrab;
    124     device->DestroyWindow = RPI_DestroyWindow;
    125 #if 0
    126     device->GetWindowWMInfo = RPI_GetWindowWMInfo;
    127 #endif
    128     device->GL_LoadLibrary = RPI_GLES_LoadLibrary;
    129     device->GL_GetProcAddress = RPI_GLES_GetProcAddress;
    130     device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary;
    131     device->GL_CreateContext = RPI_GLES_CreateContext;
    132     device->GL_MakeCurrent = RPI_GLES_MakeCurrent;
    133     device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval;
    134     device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval;
    135     device->GL_SwapWindow = RPI_GLES_SwapWindow;
    136     device->GL_DeleteContext = RPI_GLES_DeleteContext;
    137     device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig;
    138 
    139     device->PumpEvents = RPI_PumpEvents;
    140 
    141     return device;
    142 }
    143 
    144 VideoBootStrap RPI_bootstrap = {
    145     "RPI",
    146     "RPI Video Driver",
    147     RPI_Create
    148 };
    149 
    150 
    151 /*****************************************************************************/
    152 /* SDL Video and Display initialization/handling functions                   */
    153 /*****************************************************************************/
    154 
    155 static void
    156 AddDispManXDisplay(const int display_id)
    157 {
    158     DISPMANX_MODEINFO_T modeinfo;
    159     DISPMANX_DISPLAY_HANDLE_T handle;
    160     SDL_VideoDisplay display;
    161     SDL_DisplayMode current_mode;
    162     SDL_DisplayData *data;
    163 
    164     handle = vc_dispmanx_display_open(display_id);
    165     if (!handle) {
    166         return;  /* this display isn't available */
    167     }
    168 
    169     if (vc_dispmanx_display_get_info(handle, &modeinfo) < 0) {
    170         vc_dispmanx_display_close(handle);
    171         return;
    172     }
    173 
    174     /* RPI_GetRefreshRate() doesn't distinguish between displays. I'm not sure the hardware distinguishes either */
    175     SDL_zero(current_mode);
    176     current_mode.w = modeinfo.width;
    177     current_mode.h = modeinfo.height;
    178     current_mode.refresh_rate = RPI_GetRefreshRate();
    179     /* 32 bpp for default */
    180     current_mode.format = SDL_PIXELFORMAT_ABGR8888;
    181 
    182     current_mode.driverdata = NULL;
    183 
    184     SDL_zero(display);
    185     display.desktop_mode = current_mode;
    186     display.current_mode = current_mode;
    187 
    188     /* Allocate display internal data */
    189     data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
    190     if (data == NULL) {
    191         vc_dispmanx_display_close(handle);
    192         return;  /* oh well */
    193     }
    194 
    195     data->dispman_display = handle;
    196 
    197     display.driverdata = data;
    198 
    199     SDL_AddVideoDisplay(&display, SDL_FALSE);
    200 }
    201 
    202 int
    203 RPI_VideoInit(_THIS)
    204 {
    205     /* Initialize BCM Host */
    206     bcm_host_init();
    207 
    208     AddDispManXDisplay(DISPMANX_ID_MAIN_LCD);  /* your default display */
    209     AddDispManXDisplay(DISPMANX_ID_FORCE_OTHER);  /* an "other" display...maybe DSI-connected screen while HDMI is your main */
    210 
    211 #ifdef SDL_INPUT_LINUXEV    
    212     if (SDL_EVDEV_Init() < 0) {
    213         return -1;
    214     }
    215 #endif    
    216     
    217     RPI_InitMouse(_this);
    218 
    219     return 1;
    220 }
    221 
    222 void
    223 RPI_VideoQuit(_THIS)
    224 {
    225 #ifdef SDL_INPUT_LINUXEV    
    226     SDL_EVDEV_Quit();
    227 #endif    
    228 }
    229 
    230 void
    231 RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
    232 {
    233     /* Only one display mode available, the current one */
    234     SDL_AddDisplayMode(display, &display->current_mode);
    235 }
    236 
    237 int
    238 RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
    239 {
    240     return 0;
    241 }
    242 
    243 static void
    244 RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
    245 {
    246    SDL_WindowData *wdata = ((SDL_WindowData *) data);
    247 
    248    SDL_LockMutex(wdata->vsync_cond_mutex);
    249    SDL_CondSignal(wdata->vsync_cond);
    250    SDL_UnlockMutex(wdata->vsync_cond_mutex);
    251 }
    252 
    253 int
    254 RPI_CreateWindow(_THIS, SDL_Window * window)
    255 {
    256     SDL_WindowData *wdata;
    257     SDL_VideoDisplay *display;
    258     SDL_DisplayData *displaydata;
    259     VC_RECT_T dst_rect;
    260     VC_RECT_T src_rect;
    261     VC_DISPMANX_ALPHA_T         dispman_alpha;
    262     DISPMANX_UPDATE_HANDLE_T dispman_update;
    263     uint32_t layer = SDL_RPI_VIDEOLAYER;
    264     const char *env;
    265 
    266     /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */
    267     dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; 
    268     dispman_alpha.opacity = 0xFF; 
    269     dispman_alpha.mask = 0;
    270 
    271     /* Allocate window internal data */
    272     wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
    273     if (wdata == NULL) {
    274         return SDL_OutOfMemory();
    275     }
    276     display = SDL_GetDisplayForWindow(window);
    277     displaydata = (SDL_DisplayData *) display->driverdata;
    278 
    279     /* Windows have one size for now */
    280     window->w = display->desktop_mode.w;
    281     window->h = display->desktop_mode.h;
    282 
    283     /* OpenGL ES is the law here, buddy */
    284     window->flags |= SDL_WINDOW_OPENGL;
    285 
    286     /* Create a dispman element and associate a window to it */
    287     dst_rect.x = 0;
    288     dst_rect.y = 0;
    289     dst_rect.width = window->w;
    290     dst_rect.height = window->h;
    291 
    292     src_rect.x = 0;
    293     src_rect.y = 0;
    294     src_rect.width = window->w << 16;
    295     src_rect.height = window->h << 16;
    296 
    297     env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
    298     if (env) {
    299         layer = SDL_atoi(env);
    300     }
    301 
    302     dispman_update = vc_dispmanx_update_start( 0 );
    303     wdata->dispman_window.element = vc_dispmanx_element_add (dispman_update,
    304                                                              displaydata->dispman_display,
    305                                                              layer /* layer */,
    306                                                              &dst_rect,
    307                                                              0 /*src*/,
    308                                                              &src_rect,
    309                                                              DISPMANX_PROTECTION_NONE,
    310                                                              &dispman_alpha /*alpha*/,
    311                                                              0 /*clamp*/,
    312                                                              0 /*transform*/);
    313     wdata->dispman_window.width = window->w;
    314     wdata->dispman_window.height = window->h;
    315     vc_dispmanx_update_submit_sync(dispman_update);
    316     
    317     if (!_this->egl_data) {
    318         if (SDL_GL_LoadLibrary(NULL) < 0) {
    319             return -1;
    320         }
    321     }
    322     wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window);
    323 
    324     if (wdata->egl_surface == EGL_NO_SURFACE) {
    325         return SDL_SetError("Could not create GLES window surface");
    326     }
    327 
    328     /* Start generating vsync callbacks if necesary */
    329     wdata->double_buffer = SDL_FALSE;
    330     if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
    331         wdata->vsync_cond = SDL_CreateCond();
    332         wdata->vsync_cond_mutex = SDL_CreateMutex();
    333         wdata->double_buffer = SDL_TRUE;
    334         vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void*)wdata);
    335     }
    336 
    337     /* Setup driver data for this window */
    338     window->driverdata = wdata;
    339 
    340     /* One window, it always has focus */
    341     SDL_SetMouseFocus(window);
    342     SDL_SetKeyboardFocus(window);
    343 
    344     /* Window has been successfully created */
    345     return 0;
    346 }
    347 
    348 void
    349 RPI_DestroyWindow(_THIS, SDL_Window * window)
    350 {
    351     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    352     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    353     SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
    354 
    355     if(data) {
    356         if (data->double_buffer) {
    357             /* Wait for vsync, and then stop vsync callbacks and destroy related stuff, if needed */
    358             SDL_LockMutex(data->vsync_cond_mutex);
    359             SDL_CondWait(data->vsync_cond, data->vsync_cond_mutex);
    360             SDL_UnlockMutex(data->vsync_cond_mutex);
    361 
    362             vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL);
    363 
    364             SDL_DestroyCond(data->vsync_cond);
    365             SDL_DestroyMutex(data->vsync_cond_mutex);
    366         }
    367 
    368 #if SDL_VIDEO_OPENGL_EGL
    369         if (data->egl_surface != EGL_NO_SURFACE) {
    370             SDL_EGL_DestroySurface(_this, data->egl_surface);
    371         }
    372 #endif
    373         SDL_free(data);
    374         window->driverdata = NULL;
    375     }
    376 }
    377 
    378 int
    379 RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
    380 {
    381     return -1;
    382 }
    383 
    384 void
    385 RPI_SetWindowTitle(_THIS, SDL_Window * window)
    386 {
    387 }
    388 void
    389 RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
    390 {
    391 }
    392 void
    393 RPI_SetWindowPosition(_THIS, SDL_Window * window)
    394 {
    395 }
    396 void
    397 RPI_SetWindowSize(_THIS, SDL_Window * window)
    398 {
    399 }
    400 void
    401 RPI_ShowWindow(_THIS, SDL_Window * window)
    402 {
    403 }
    404 void
    405 RPI_HideWindow(_THIS, SDL_Window * window)
    406 {
    407 }
    408 void
    409 RPI_RaiseWindow(_THIS, SDL_Window * window)
    410 {
    411 }
    412 void
    413 RPI_MaximizeWindow(_THIS, SDL_Window * window)
    414 {
    415 }
    416 void
    417 RPI_MinimizeWindow(_THIS, SDL_Window * window)
    418 {
    419 }
    420 void
    421 RPI_RestoreWindow(_THIS, SDL_Window * window)
    422 {
    423 }
    424 void
    425 RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
    426 {
    427 
    428 }
    429 
    430 /*****************************************************************************/
    431 /* SDL Window Manager function                                               */
    432 /*****************************************************************************/
    433 #if 0
    434 SDL_bool
    435 RPI_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
    436 {
    437     if (info->version.major <= SDL_MAJOR_VERSION) {
    438         return SDL_TRUE;
    439     } else {
    440         SDL_SetError("application not compiled with SDL %d.%d",
    441                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
    442         return SDL_FALSE;
    443     }
    444 
    445     /* Failed to get window manager information */
    446     return SDL_FALSE;
    447 }
    448 #endif
    449 
    450 #endif /* SDL_VIDEO_DRIVER_RPI */
    451 
    452 /* vi: set ts=4 sw=4 expandtab: */