WARNING: REDESIGN: Move platform specific data to platform submodules #3313

REVIEWED: Defines, macros, types and tweaks
This commit is contained in:
Ray 2023-10-09 00:41:06 +02:00
commit d445fdaa19
7 changed files with 519 additions and 520 deletions

View file

@ -17,8 +17,10 @@
* - TRACELOG() function is located in raylib [utils] module
*
* CONFIGURATION:
* #define RCORE_DRM_CUSTOM_FLAG
* Custom flag for rcore on PLATFORM_DRM -not used-
* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only)
* Reconfigure standard input to receive key inputs, works with SSH connection.
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other
* running processes orblocking the device if not restored properly. Use with care.
*
* DEPENDENCIES:
* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs)
@ -47,15 +49,93 @@
#include "rcore.h"
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
#include <linux/joystick.h> // Linux: Joystick support library
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
#include "EGL/egl.h" // Native platform windowing system interface
#include "EGL/eglext.h" // EGL extensions
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
#define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...)
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
//...
typedef struct {
pthread_t threadId; // Event reading thread id
int fd; // File descriptor to the device it is assigned to
int eventNum; // Number of 'event<N>' device
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
bool isMouse; // True if device supports relative X Y movements
bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH
bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH
bool isKeyboard; // True if device has letter keycodes
bool isGamepad; // True if device has gamepad buttons
} InputEventWorker;
typedef struct {
// Display data
int fd; // File descriptor for /dev/dri/...
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
drmModeCrtc *crtc; // CRT Controller
int modeIndex; // Index of the used mode of connector->modes
struct gbm_device *gbmDevice; // GBM device
struct gbm_surface *gbmSurface; // GBM surface
struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping)
uint32_t prevFB; // Previous GBM framebufer (during frame swapping)
EGLDisplay device; // Native display device (physical screen connection)
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
EGLContext context; // Graphic context, mode in which drawing can be done
EGLConfig config; // Graphic config
// Input data
InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event<N>"
// Keyboard data
int defaultKeyboardMode; // Default keyboard mode
bool eventKeyboardMode; // Keyboard in event mode
int defaultFileFlags; // Default IO file flags
struct termios defaultSettings; // Default keyboard settings
int keyboardFd; // File descriptor for the evdev keyboard
// Mouse data
Vector2 eventWheelMove; // Registers the event mouse wheel variation
// NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
// Gamepad data
pthread_t gamepadThreadId; // Gamepad reading thread id
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
} PlatformData;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
extern CoreData CORE; // Global CORE state context
extern CoreData CORE; // Global CORE state context
static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
@ -227,67 +307,67 @@ void CloseWindow(void)
timeEndPeriod(1); // Restore time period
#endif
if (CORE.Window.prevFB)
if (platform.prevFB)
{
drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB);
CORE.Window.prevFB = 0;
drmModeRmFB(platform.fd, platform.prevFB);
platform.prevFB = 0;
}
if (CORE.Window.prevBO)
if (platform.prevBO)
{
gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
CORE.Window.prevBO = NULL;
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
platform.prevBO = NULL;
}
if (CORE.Window.gbmSurface)
if (platform.gbmSurface)
{
gbm_surface_destroy(CORE.Window.gbmSurface);
CORE.Window.gbmSurface = NULL;
gbm_surface_destroy(platform.gbmSurface);
platform.gbmSurface = NULL;
}
if (CORE.Window.gbmDevice)
if (platform.gbmDevice)
{
gbm_device_destroy(CORE.Window.gbmDevice);
CORE.Window.gbmDevice = NULL;
gbm_device_destroy(platform.gbmDevice);
platform.gbmDevice = NULL;
}
if (CORE.Window.crtc)
if (platform.crtc)
{
if (CORE.Window.connector)
if (platform.connector)
{
drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, CORE.Window.crtc->buffer_id,
CORE.Window.crtc->x, CORE.Window.crtc->y, &CORE.Window.connector->connector_id, 1, &CORE.Window.crtc->mode);
drmModeFreeConnector(CORE.Window.connector);
CORE.Window.connector = NULL;
drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, platform.crtc->buffer_id,
platform.crtc->x, platform.crtc->y, &platform.connector->connector_id, 1, &platform.crtc->mode);
drmModeFreeConnector(platform.connector);
platform.connector = NULL;
}
drmModeFreeCrtc(CORE.Window.crtc);
CORE.Window.crtc = NULL;
drmModeFreeCrtc(platform.crtc);
platform.crtc = NULL;
}
if (CORE.Window.fd != -1)
if (platform.fd != -1)
{
close(CORE.Window.fd);
CORE.Window.fd = -1;
close(platform.fd);
platform.fd = -1;
}
// Close surface, context and display
if (CORE.Window.device != EGL_NO_DISPLAY)
if (platform.device != EGL_NO_DISPLAY)
{
if (CORE.Window.surface != EGL_NO_SURFACE)
if (platform.surface != EGL_NO_SURFACE)
{
eglDestroySurface(CORE.Window.device, CORE.Window.surface);
CORE.Window.surface = EGL_NO_SURFACE;
eglDestroySurface(platform.device, platform.surface);
platform.surface = EGL_NO_SURFACE;
}
if (CORE.Window.context != EGL_NO_CONTEXT)
if (platform.context != EGL_NO_CONTEXT)
{
eglDestroyContext(CORE.Window.device, CORE.Window.context);
CORE.Window.context = EGL_NO_CONTEXT;
eglDestroyContext(platform.device, platform.context);
platform.context = EGL_NO_CONTEXT;
}
eglTerminate(CORE.Window.device);
CORE.Window.device = EGL_NO_DISPLAY;
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
// Wait for mouse and gamepad threads to finish before closing
@ -297,21 +377,21 @@ void CloseWindow(void)
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
// Close the evdev keyboard
if (CORE.Input.Keyboard.fd != -1)
if (platform.keyboardFd != -1)
{
close(CORE.Input.Keyboard.fd);
CORE.Input.Keyboard.fd = -1;
close(platform.keyboardFd);
platform.keyboardFd = -1;
}
for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i)
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (CORE.Input.eventWorker[i].threadId)
if (platform.eventWorker[i].threadId)
{
pthread_join(CORE.Input.eventWorker[i].threadId, NULL);
pthread_join(platform.eventWorker[i].threadId, NULL);
}
}
if (CORE.Input.Gamepad.threadId) pthread_join(CORE.Input.Gamepad.threadId, NULL);
if (platform.gamepadThreadId) pthread_join(platform.gamepadThreadId, NULL);
#if defined(SUPPORT_EVENTS_AUTOMATION)
RL_FREE(events);
@ -524,9 +604,9 @@ int GetMonitorRefreshRate(int monitor)
{
int refresh = 0;
if ((CORE.Window.connector) && (CORE.Window.modeIndex >= 0))
if ((platform.connector) && (platform.modeIndex >= 0))
{
refresh = CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh;
refresh = platform.connector->modes[platform.modeIndex].vrefresh;
}
return refresh;
@ -659,7 +739,7 @@ const char *GetGamepadName(int gamepad)
if (CORE.Input.Gamepad.ready[gamepad])
{
ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name[gamepad]);
ioctl(platform.gamepadStreamFd[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name[gamepad]);
name = CORE.Input.Gamepad.name[gamepad];
}
@ -670,7 +750,7 @@ const char *GetGamepadName(int gamepad)
int GetGamepadAxisCount(int gamepad)
{
int axisCount = 0;
if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGAXES, &axisCount);
if (CORE.Input.Gamepad.ready[gamepad]) ioctl(platform.gamepadStreamFd[gamepad], JSIOCGAXES, &axisCount);
CORE.Input.Gamepad.axisCount = axisCount;
return CORE.Input.Gamepad.axisCount;
@ -756,31 +836,31 @@ Vector2 GetTouchPosition(int index)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
eglSwapBuffers(CORE.Window.device, CORE.Window.surface);
eglSwapBuffers(platform.device, platform.surface);
if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface);
struct gbm_bo *bo = gbm_surface_lock_front_buffer(platform.gbmSurface);
if (!bo) TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer");
uint32_t fb = 0;
int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb);
int result = drmModeAddFB(platform.fd, platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb);
if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result);
result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]);
result = drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, fb, 0, 0, &platform.connector->connector_id, 1, &platform.connector->modes[platform.modeIndex]);
if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result);
if (CORE.Window.prevFB)
if (platform.prevFB)
{
result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB);
result = drmModeRmFB(platform.fd, platform.prevFB);
if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result);
}
CORE.Window.prevFB = fb;
platform.prevFB = fb;
if (CORE.Window.prevBO) gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
CORE.Window.prevBO = bo;
platform.prevBO = bo;
}
// Register all input events
@ -814,12 +894,12 @@ void PollInputEvents(void)
// Register previous mouse states
CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
CORE.Input.Mouse.currentWheelMove = CORE.Input.Mouse.eventWheelMove;
CORE.Input.Mouse.eventWheelMove = (Vector2){ 0.0f, 0.0f };
CORE.Input.Mouse.currentWheelMove = platform.eventWheelMove;
platform.eventWheelMove = (Vector2){ 0.0f, 0.0f };
for (int i = 0; i < MAX_MOUSE_BUTTONS; i++)
{
CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
CORE.Input.Mouse.currentButtonState[i] = CORE.Input.Mouse.currentButtonStateEvdev[i];
CORE.Input.Mouse.currentButtonState[i] = platform.currentButtonStateEvdev[i];
}
// Register gamepads buttons events
@ -844,7 +924,7 @@ void PollInputEvents(void)
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
if (!CORE.Input.Keyboard.evtMode) ProcessKeyboard();
if (!platform.eventKeyboardMode) ProcessKeyboard();
// NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread()
// NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread()
@ -877,41 +957,41 @@ static bool InitGraphicsDevice(int width, int height)
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
CORE.Window.fd = -1;
CORE.Window.connector = NULL;
CORE.Window.modeIndex = -1;
CORE.Window.crtc = NULL;
CORE.Window.gbmDevice = NULL;
CORE.Window.gbmSurface = NULL;
CORE.Window.prevBO = NULL;
CORE.Window.prevFB = 0;
platform.fd = -1;
platform.connector = NULL;
platform.modeIndex = -1;
platform.crtc = NULL;
platform.gbmDevice = NULL;
platform.gbmSurface = NULL;
platform.prevBO = NULL;
platform.prevFB = 0;
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
CORE.Window.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
#else
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
CORE.Window.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
if ((CORE.Window.fd == -1) || (drmModeGetResources(CORE.Window.fd) == NULL))
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
}
if ((CORE.Window.fd == -1) || (drmModeGetResources(CORE.Window.fd) == NULL))
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
CORE.Window.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
}
#endif
if (CORE.Window.fd == -1)
if (platform.fd == -1)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card");
return false;
}
drmModeRes *res = drmModeGetResources(CORE.Window.fd);
drmModeRes *res = drmModeGetResources(platform.fd);
if (!res)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
@ -924,13 +1004,13 @@ static bool InitGraphicsDevice(int width, int height)
{
TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i);
drmModeConnector *con = drmModeGetConnector(CORE.Window.fd, res->connectors[i]);
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id))
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
CORE.Window.connector = con;
platform.connector = con;
break;
}
else
@ -940,14 +1020,14 @@ static bool InitGraphicsDevice(int width, int height)
}
}
if (!CORE.Window.connector)
if (!platform.connector)
{
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
drmModeFreeResources(res);
return false;
}
drmModeEncoder *enc = drmModeGetEncoder(CORE.Window.fd, CORE.Window.connector->encoder_id);
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
if (!enc)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
@ -955,8 +1035,8 @@ static bool InitGraphicsDevice(int width, int height)
return false;
}
CORE.Window.crtc = drmModeGetCrtc(CORE.Window.fd, enc->crtc_id);
if (!CORE.Window.crtc)
platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id);
if (!platform.crtc)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
drmModeFreeEncoder(enc);
@ -969,9 +1049,9 @@ static bool InitGraphicsDevice(int width, int height)
{
TRACELOG(LOG_TRACE, "DISPLAY: Selecting DRM connector mode for current used mode...");
CORE.Window.modeIndex = FindMatchingConnectorMode(CORE.Window.connector, &CORE.Window.crtc->mode);
platform.modeIndex = FindMatchingConnectorMode(platform.connector, &platform.crtc->mode);
if (CORE.Window.modeIndex < 0)
if (platform.modeIndex < 0)
{
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
drmModeFreeEncoder(enc);
@ -987,19 +1067,19 @@ static bool InitGraphicsDevice(int width, int height)
const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
// Try to find an exact matching mode
CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
// If nothing found, try to find a nearly matching mode
if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
// If nothing found, try to find an exactly matching mode including interlaced
if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
if (platform.modeIndex < 0) platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
// If nothing found, try to find a nearly matching mode including interlaced
if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
// If nothing found, there is no suitable mode
if (CORE.Window.modeIndex < 0)
if (platform.modeIndex < 0)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
drmModeFreeEncoder(enc);
@ -1007,13 +1087,13 @@ static bool InitGraphicsDevice(int width, int height)
return false;
}
CORE.Window.display.width = CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay;
CORE.Window.display.height = CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay;
CORE.Window.display.width = platform.connector->modes[platform.modeIndex].hdisplay;
CORE.Window.display.height = platform.connector->modes[platform.modeIndex].vdisplay;
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name,
CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay,
(CORE.Window.connector->modes[CORE.Window.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh);
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
(platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
platform.connector->modes[platform.modeIndex].vrefresh);
// Use the width and height of the surface for render
CORE.Window.render.width = CORE.Window.screen.width;
@ -1025,16 +1105,16 @@ static bool InitGraphicsDevice(int width, int height)
drmModeFreeResources(res);
res = NULL;
CORE.Window.gbmDevice = gbm_create_device(CORE.Window.fd);
if (!CORE.Window.gbmDevice)
platform.gbmDevice = gbm_create_device(platform.fd);
if (!platform.gbmDevice)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device");
return false;
}
CORE.Window.gbmSurface = gbm_surface_create(CORE.Window.gbmDevice, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay,
CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (!CORE.Window.gbmSurface)
platform.gbmSurface = gbm_surface_create(platform.gbmDevice, platform.connector->modes[platform.modeIndex].hdisplay,
platform.connector->modes[platform.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (!platform.gbmSurface)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface");
return false;
@ -1073,22 +1153,22 @@ static bool InitGraphicsDevice(int width, int height)
EGLint numConfigs = 0;
// Get an EGL device connection
CORE.Window.device = eglGetDisplay((EGLNativeDisplayType)CORE.Window.gbmDevice);
if (CORE.Window.device == EGL_NO_DISPLAY)
platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice);
if (platform.device == EGL_NO_DISPLAY)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
}
// Initialize the EGL device connection
if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE)
if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
}
if (!eglChooseConfig(CORE.Window.device, NULL, NULL, 0, &numConfigs))
if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs))
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError());
return false;
@ -1104,7 +1184,7 @@ static bool InitGraphicsDevice(int width, int height)
}
EGLint matchingNumConfigs = 0;
if (!eglChooseConfig(CORE.Window.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs))
if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs))
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError());
free(configs);
@ -1118,7 +1198,7 @@ static bool InitGraphicsDevice(int width, int height)
for (EGLint i = 0; i < matchingNumConfigs; ++i)
{
EGLint id = 0;
if (!eglGetConfigAttrib(CORE.Window.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config attribute: 0x%x", eglGetError());
continue;
@ -1127,7 +1207,7 @@ static bool InitGraphicsDevice(int width, int height)
if (GBM_FORMAT_ARGB8888 == id)
{
TRACELOG(LOG_TRACE, "DISPLAY: Using EGL config: %d", i);
CORE.Window.config = configs[i];
platform.config = configs[i];
found = 1;
break;
}
@ -1145,8 +1225,8 @@ static bool InitGraphicsDevice(int width, int height)
eglBindAPI(EGL_OPENGL_ES_API);
// Create an EGL rendering context
CORE.Window.context = eglCreateContext(CORE.Window.device, CORE.Window.config, EGL_NO_CONTEXT, contextAttribs);
if (CORE.Window.context == EGL_NO_CONTEXT)
platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs);
if (platform.context == EGL_NO_CONTEXT)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
return false;
@ -1154,8 +1234,8 @@ static bool InitGraphicsDevice(int width, int height)
// Create an EGL window surface
//---------------------------------------------------------------------------------
CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, (EGLNativeWindowType)CORE.Window.gbmSurface, NULL);
if (EGL_NO_SURFACE == CORE.Window.surface)
platform.surface = eglCreateWindowSurface(platform.device, platform.config, (EGLNativeWindowType)platform.gbmSurface, NULL);
if (EGL_NO_SURFACE == platform.surface)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError());
return false;
@ -1169,9 +1249,9 @@ static bool InitGraphicsDevice(int width, int height)
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
// There must be at least one frame displayed before the buffers are swapped
//eglSwapInterval(CORE.Window.device, 1);
//eglSwapInterval(platform.device, 1);
if (eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context) == EGL_FALSE)
if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface");
return false;
@ -1214,11 +1294,11 @@ static void InitKeyboard(void)
// Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE
// Save terminal keyboard settings
tcgetattr(STDIN_FILENO, &CORE.Input.Keyboard.defaultSettings);
tcgetattr(STDIN_FILENO, &platform.defaultSettings);
// Reconfigure terminal with new settings
struct termios keyboardNewSettings = { 0 };
keyboardNewSettings = CORE.Input.Keyboard.defaultSettings;
keyboardNewSettings = platform.defaultSettings;
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
@ -1231,11 +1311,11 @@ static void InitKeyboard(void)
tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
// Save old keyboard mode to restore it at the end
CORE.Input.Keyboard.defaultFileFlags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
fcntl(STDIN_FILENO, F_SETFL, CORE.Input.Keyboard.defaultFileFlags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
platform.defaultFileFlags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
// NOTE: If ioctl() returns -1, it means the call failed for some reason (error code set in errno)
int result = ioctl(STDIN_FILENO, KDGKBMODE, &CORE.Input.Keyboard.defaultMode);
int result = ioctl(STDIN_FILENO, KDGKBMODE, &platform.defaultKeyboardMode);
// In case of failure, it could mean a remote keyboard is used (SSH)
if (result < 0) TRACELOG(LOG_WARNING, "RPI: Failed to change keyboard mode, an SSH keyboard is probably used");
@ -1257,11 +1337,11 @@ static void InitKeyboard(void)
static void RestoreKeyboard(void)
{
// Reset to default keyboard settings
tcsetattr(STDIN_FILENO, TCSANOW, &CORE.Input.Keyboard.defaultSettings);
tcsetattr(STDIN_FILENO, TCSANOW, &platform.defaultSettings);
// Reconfigure keyboard to default mode
fcntl(STDIN_FILENO, F_SETFL, CORE.Input.Keyboard.defaultFileFlags);
ioctl(STDIN_FILENO, KDSKBMODE, CORE.Input.Keyboard.defaultMode);
fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags);
ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode);
}
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
@ -1389,7 +1469,7 @@ static void InitEvdevInput(void)
struct dirent *entity = NULL;
// Initialise keyboard file descriptor
CORE.Input.Keyboard.fd = -1;
platform.keyboardFd = -1;
// Reset variables
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
@ -1451,9 +1531,9 @@ static void ConfigureEvdevDevice(char *device)
// Open the device and allocate worker
//-------------------------------------------------------------------------------------------------------
// Find a free spot in the workers array
for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i)
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (CORE.Input.eventWorker[i].threadId == 0)
if (platform.eventWorker[i].threadId == 0)
{
freeWorkerId = i;
break;
@ -1463,7 +1543,7 @@ static void ConfigureEvdevDevice(char *device)
// Select the free worker from array
if (freeWorkerId >= 0)
{
worker = &(CORE.Input.eventWorker[freeWorkerId]); // Grab a pointer to the worker
worker = &(platform.eventWorker[freeWorkerId]); // Grab a pointer to the worker
memset(worker, 0, sizeof(InputEventWorker)); // Clear the worker
}
else
@ -1574,13 +1654,13 @@ static void ConfigureEvdevDevice(char *device)
// Decide what to do with the device
//-------------------------------------------------------------------------------------------------------
if (worker->isKeyboard && (CORE.Input.Keyboard.fd == -1))
if (worker->isKeyboard && (platform.keyboardFd == -1))
{
// Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a
// keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate
// threads so that they don't drop events when the frame rate is slow.
TRACELOG(LOG_INFO, "RPI: Opening keyboard device: %s", device);
CORE.Input.Keyboard.fd = worker->fd;
platform.keyboardFd = worker->fd;
}
else if (worker->isTouch || worker->isMouse)
{
@ -1604,21 +1684,21 @@ static void ConfigureEvdevDevice(char *device)
// Find touchscreen with the highest index
int maxTouchNumber = -1;
for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i)
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = CORE.Input.eventWorker[i].eventNum;
if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = platform.eventWorker[i].eventNum;
}
// Find touchscreens with lower indexes
for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i)
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum < maxTouchNumber))
if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum < maxTouchNumber))
{
if (CORE.Input.eventWorker[i].threadId != 0)
if (platform.eventWorker[i].threadId != 0)
{
TRACELOG(LOG_WARNING, "RPI: Found duplicate touchscreen, killing touchscreen on event: %d", i);
pthread_cancel(CORE.Input.eventWorker[i].threadId);
close(CORE.Input.eventWorker[i].fd);
pthread_cancel(platform.eventWorker[i].threadId);
close(platform.eventWorker[i].fd);
}
}
}
@ -1652,7 +1732,7 @@ static void PollKeyboardEvents(void)
243, 244, 245, 246, 247, 248, 0, 0, 0, 0, 0, 0, 0
};
int fd = CORE.Input.Keyboard.fd;
int fd = platform.keyboardFd;
if (fd == -1) return;
struct input_event event = { 0 };
@ -1666,7 +1746,7 @@ static void PollKeyboardEvents(void)
{
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
// Change keyboard mode to events
CORE.Input.Keyboard.evtMode = true;
platform.eventKeyboardMode = true;
#endif
// Keyboard button parsing
if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255
@ -1739,7 +1819,7 @@ static void *EventThread(void *arg)
gestureUpdate = true;
}
if (event.code == REL_WHEEL) CORE.Input.Mouse.eventWheelMove.y += event.value;
if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
}
// Absolute movement parsing
@ -1790,11 +1870,11 @@ static void *EventThread(void *arg)
// Touchscreen tap
if (event.code == ABS_PRESSURE)
{
int previousMouseLeftButtonState = CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
if (!event.value && previousMouseLeftButtonState)
{
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
touchAction = 0; // TOUCH_ACTION_UP
gestureUpdate = true;
@ -1802,7 +1882,7 @@ static void *EventThread(void *arg)
if (event.value && !previousMouseLeftButtonState)
{
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
touchAction = 1; // TOUCH_ACTION_DOWN
gestureUpdate = true;
@ -1817,19 +1897,19 @@ static void *EventThread(void *arg)
// Mouse button parsing
if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT))
{
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
else touchAction = 0; // TOUCH_ACTION_UP
gestureUpdate = true;
}
if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
if (event.code == BTN_MIDDLE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
if (event.code == BTN_SIDE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
if (event.code == BTN_EXTRA) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
if (event.code == BTN_FORWARD) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
if (event.code == BTN_BACK) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
}
// Screen confinement
@ -1885,7 +1965,7 @@ static void InitGamepad(void)
{
sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i);
if ((CORE.Input.Gamepad.streamId[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0)
if ((platform.gamepadStreamFd[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0)
{
// NOTE: Only show message for first gamepad
if (i == 0) TRACELOG(LOG_WARNING, "RPI: Failed to open Gamepad device, no gamepad available");
@ -1897,7 +1977,7 @@ static void InitGamepad(void)
// NOTE: Only create one thread
if (i == 0)
{
int error = pthread_create(&CORE.Input.Gamepad.threadId, NULL, &GamepadThread, NULL);
int error = pthread_create(&platform.gamepadThreadId, NULL, &GamepadThread, NULL);
if (error != 0) TRACELOG(LOG_WARNING, "RPI: Failed to create gamepad input event thread");
else TRACELOG(LOG_INFO, "RPI: Gamepad device initialized successfully");
@ -1927,7 +2007,7 @@ static void *GamepadThread(void *arg)
{
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (read(CORE.Input.Gamepad.streamId[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event))
if (read(platform.gamepadStreamFd[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event))
{
gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events
@ -1977,7 +2057,7 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i])) return i;
if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i;
}
return -1;
@ -1992,9 +2072,9 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width,
if (NULL == connector) return -1;
for (int i = 0; i < CORE.Window.connector->count_modes; i++)
for (int i = 0; i < platform.connector->count_modes; i++)
{
const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i];
const drmModeModeInfo *const mode = &platform.connector->modes[i];
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
@ -2015,9 +2095,9 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
if (NULL == connector) return -1;
int nearestIndex = -1;
for (int i = 0; i < CORE.Window.connector->count_modes; i++)
for (int i = 0; i < platform.connector->count_modes; i++)
{
const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i];
const drmModeModeInfo *const mode = &platform.connector->modes[i];
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
(mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
@ -2044,9 +2124,9 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
const int heightDiff = abs(mode->vdisplay - height);
const int fpsDiff = abs(mode->vrefresh - fps);
const int nearestWidthDiff = abs(CORE.Window.connector->modes[nearestIndex].hdisplay - width);
const int nearestHeightDiff = abs(CORE.Window.connector->modes[nearestIndex].vdisplay - height);
const int nearestFpsDiff = abs(CORE.Window.connector->modes[nearestIndex].vrefresh - fps);
const int nearestWidthDiff = abs(platform.connector->modes[nearestIndex].hdisplay - width);
const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height);
const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps);
if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) {
nearestIndex = i;