#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_RPI
#include "../SDL_sysvideo.h"
#include "SDL_version.h"
#include "SDL_syswm.h"
#include "SDL_loadso.h"
#include "SDL_events.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "SDL_hints.h"
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#endif
#include "SDL_rpivideo.h"
#include "SDL_rpievents_c.h"
#include "SDL_rpiopengles.h"
#include "SDL_rpimouse.h"
static void
RPI_Destroy(SDL_VideoDevice * device)
{
SDL_free(device->driverdata);
SDL_free(device);
}
static int
RPI_GetRefreshRate()
{
TV_DISPLAY_STATE_T tvstate;
if (vc_tv_get_display_state( &tvstate ) == 0) {
HDMI_PROPERTY_PARAM_T property;
property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
vc_tv_hdmi_get_property(&property);
return property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ?
tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) :
tvstate.display.hdmi.frame_rate;
}
return 60;
}
static SDL_VideoDevice *
RPI_Create()
{
SDL_VideoDevice *device;
SDL_VideoData *phdata;
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return NULL;
}
phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
if (phdata == NULL) {
SDL_OutOfMemory();
SDL_free(device);
return NULL;
}
device->driverdata = phdata;
device->num_displays = 0;
device->free = RPI_Destroy;
device->VideoInit = RPI_VideoInit;
device->VideoQuit = RPI_VideoQuit;
device->GetDisplayModes = RPI_GetDisplayModes;
device->SetDisplayMode = RPI_SetDisplayMode;
device->CreateSDLWindow = RPI_CreateWindow;
device->CreateSDLWindowFrom = RPI_CreateWindowFrom;
device->SetWindowTitle = RPI_SetWindowTitle;
device->SetWindowIcon = RPI_SetWindowIcon;
device->SetWindowPosition = RPI_SetWindowPosition;
device->SetWindowSize = RPI_SetWindowSize;
device->ShowWindow = RPI_ShowWindow;
device->HideWindow = RPI_HideWindow;
device->RaiseWindow = RPI_RaiseWindow;
device->MaximizeWindow = RPI_MaximizeWindow;
device->MinimizeWindow = RPI_MinimizeWindow;
device->RestoreWindow = RPI_RestoreWindow;
device->DestroyWindow = RPI_DestroyWindow;
#if 0#endif
device->GL_LoadLibrary = RPI_GLES_LoadLibrary;
device->GL_GetProcAddress = RPI_GLES_GetProcAddress;
device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary;
device->GL_CreateContext = RPI_GLES_CreateContext;
device->GL_MakeCurrent = RPI_GLES_MakeCurrent;
device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval;
device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval;
device->GL_SwapWindow = RPI_GLES_SwapWindow;
device->GL_DeleteContext = RPI_GLES_DeleteContext;
device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig;
device->PumpEvents = RPI_PumpEvents;
return device;
}
VideoBootStrap RPI_bootstrap = {
"RPI",
"RPI Video Driver",
RPI_Create
};
static void
AddDispManXDisplay(const int display_id)
{
DISPMANX_MODEINFO_T modeinfo;
DISPMANX_DISPLAY_HANDLE_T handle;
SDL_VideoDisplay display;
SDL_DisplayMode current_mode;
SDL_DisplayData *data;
handle = vc_dispmanx_display_open(display_id);
if (!handle) {
return;
}
if (vc_dispmanx_display_get_info(handle, &modeinfo) < 0) {
vc_dispmanx_display_close(handle);
return;
}
SDL_zero(current_mode);
current_mode.w = modeinfo.width;
current_mode.h = modeinfo.height;
current_mode.refresh_rate = RPI_GetRefreshRate();
current_mode.format = SDL_PIXELFORMAT_ABGR8888;
current_mode.driverdata = NULL;
SDL_zero(display);
display.desktop_mode = current_mode;
display.current_mode = current_mode;
data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
if (data == NULL) {
vc_dispmanx_display_close(handle);
return;
}
data->dispman_display = handle;
display.driverdata = data;
SDL_AddVideoDisplay(&display, SDL_FALSE);
}
int
RPI_VideoInit(_THIS)
{
bcm_host_init();
AddDispManXDisplay(DISPMANX_ID_MAIN_LCD);
AddDispManXDisplay(DISPMANX_ID_FORCE_OTHER);
#ifdef SDL_INPUT_LINUXEV
if (SDL_EVDEV_Init() < 0) {
return -1;
}
#endif
RPI_InitMouse(_this);
return 1;
}
void
RPI_VideoQuit(_THIS)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#endif
}
void
RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_AddDisplayMode(display, &display->current_mode);
}
int
RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
return 0;
}
static void
RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
{
SDL_WindowData *wdata = ((SDL_WindowData *) data);
SDL_LockMutex(wdata->vsync_cond_mutex);
SDL_CondSignal(wdata->vsync_cond);
SDL_UnlockMutex(wdata->vsync_cond_mutex);
}
int
RPI_CreateWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *wdata;
SDL_VideoDisplay *display;
SDL_DisplayData *displaydata;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
VC_DISPMANX_ALPHA_T dispman_alpha;
DISPMANX_UPDATE_HANDLE_T dispman_update;
uint32_t layer = SDL_RPI_VIDEOLAYER;
const char *env;
dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
dispman_alpha.opacity = 0xFF;
dispman_alpha.mask = 0;
wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
if (wdata == NULL) {
return SDL_OutOfMemory();
}
display = SDL_GetDisplayForWindow(window);
displaydata = (SDL_DisplayData *) display->driverdata;
window->w = display->desktop_mode.w;
window->h = display->desktop_mode.h;
window->flags |= SDL_WINDOW_OPENGL;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = window->w;
dst_rect.height = window->h;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = window->w << 16;
src_rect.height = window->h << 16;
env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
if (env) {
layer = SDL_atoi(env);
}
dispman_update = vc_dispmanx_update_start( 0 );
wdata->dispman_window.element = vc_dispmanx_element_add (dispman_update,
displaydata->dispman_display,
layer ,
&dst_rect,
0 ,
&src_rect,
DISPMANX_PROTECTION_NONE,
&dispman_alpha ,
0 ,
0 );
wdata->dispman_window.width = window->w;
wdata->dispman_window.height = window->h;
vc_dispmanx_update_submit_sync(dispman_update);
if (!_this->egl_data) {
if (SDL_GL_LoadLibrary(NULL) < 0) {
return -1;
}
}
wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window);
if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
wdata->double_buffer = SDL_FALSE;
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
wdata->vsync_cond = SDL_CreateCond();
wdata->vsync_cond_mutex = SDL_CreateMutex();
wdata->double_buffer = SDL_TRUE;
vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void*)wdata);
}
window->driverdata = wdata;
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
return 0;
}
void
RPI_DestroyWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
if(data) {
if (data->double_buffer) {
SDL_LockMutex(data->vsync_cond_mutex);
SDL_CondWait(data->vsync_cond, data->vsync_cond_mutex);
SDL_UnlockMutex(data->vsync_cond_mutex);
vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL);
SDL_DestroyCond(data->vsync_cond);
SDL_DestroyMutex(data->vsync_cond_mutex);
}
#if SDL_VIDEO_OPENGL_EGL
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
#endif
SDL_free(data);
window->driverdata = NULL;
}
}
int
RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
return -1;
}
void
RPI_SetWindowTitle(_THIS, SDL_Window * window)
{
}
void
RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
}
void
RPI_SetWindowPosition(_THIS, SDL_Window * window)
{
}
void
RPI_SetWindowSize(_THIS, SDL_Window * window)
{
}
void
RPI_ShowWindow(_THIS, SDL_Window * window)
{
}
void
RPI_HideWindow(_THIS, SDL_Window * window)
{
}
void
RPI_RaiseWindow(_THIS, SDL_Window * window)
{
}
void
RPI_MaximizeWindow(_THIS, SDL_Window * window)
{
}
void
RPI_MinimizeWindow(_THIS, SDL_Window * window)
{
}
void
RPI_RestoreWindow(_THIS, SDL_Window * window)
{
}
#if 0#endif
#endif