rcore_drm software renderering
This commit is contained in:
parent
e2d10420a7
commit
954cde5b60
|
|
@ -64,12 +64,17 @@
|
||||||
// so the enum KEY_F12 from raylib is used
|
// so the enum KEY_F12 from raylib is used
|
||||||
#undef KEY_F12
|
#undef KEY_F12
|
||||||
|
|
||||||
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
|
||||||
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
|
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
|
||||||
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
|
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
|
||||||
|
|
||||||
#include "EGL/egl.h" // Native platform windowing system interface
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
#include "EGL/eglext.h" // EGL extensions
|
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
||||||
|
#include "EGL/egl.h" // Native platform windowing system interface
|
||||||
|
#include "EGL/eglext.h" // EGL extensions
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h> // For mmap when copying to the dumb buffer
|
||||||
|
#include <errno.h> // For the conversion of certain error messages
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EGL_OPENGL_ES3_BIT
|
#ifndef EGL_OPENGL_ES3_BIT
|
||||||
#define EGL_OPENGL_ES3_BIT 0x40
|
#define EGL_OPENGL_ES3_BIT 0x40
|
||||||
|
|
@ -96,15 +101,19 @@ typedef struct {
|
||||||
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
|
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
|
||||||
drmModeCrtc *crtc; // CRT Controller
|
drmModeCrtc *crtc; // CRT Controller
|
||||||
int modeIndex; // Index of the used mode of connector->modes
|
int modeIndex; // Index of the used mode of connector->modes
|
||||||
|
uint32_t prevFB; // Previous DRM framebufer (during frame swapping)
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
struct gbm_device *gbmDevice; // GBM device
|
struct gbm_device *gbmDevice; // GBM device
|
||||||
struct gbm_surface *gbmSurface; // GBM surface
|
struct gbm_surface *gbmSurface; // GBM surface
|
||||||
struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping)
|
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)
|
EGLDisplay device; // Native display device (physical screen connection)
|
||||||
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
||||||
EGLContext context; // Graphic context, mode in which drawing can be done
|
EGLContext context; // Graphic context, mode in which drawing can be done
|
||||||
EGLConfig config; // Graphic config
|
EGLConfig config; // Graphic config
|
||||||
|
#else
|
||||||
|
uint32_t prevDumbHandle; // Handle to the previous dumb buffer (during frame swapping)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Keyboard data
|
// Keyboard data
|
||||||
int defaultKeyboardMode; // Default keyboard mode
|
int defaultKeyboardMode; // Default keyboard mode
|
||||||
|
|
@ -554,6 +563,8 @@ void DisableCursor(void)
|
||||||
// Swap back buffer with front buffer (screen drawing)
|
// Swap back buffer with front buffer (screen drawing)
|
||||||
void SwapScreenBuffer(void)
|
void SwapScreenBuffer(void)
|
||||||
{
|
{
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
|
// Hardware rendering buffer swap with EGL
|
||||||
eglSwapBuffers(platform.device, platform.surface);
|
eglSwapBuffers(platform.device, platform.surface);
|
||||||
|
|
||||||
if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.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");
|
||||||
|
|
@ -579,6 +590,209 @@ void SwapScreenBuffer(void)
|
||||||
if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
||||||
|
|
||||||
platform.prevBO = bo;
|
platform.prevBO = bo;
|
||||||
|
#else
|
||||||
|
// Software rendering buffer swap
|
||||||
|
if ((-1 == platform.fd) || !platform.connector || (platform.modeIndex < 0))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the software rendered color buffer
|
||||||
|
int bufferWidth, bufferHeight;
|
||||||
|
void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
|
||||||
|
if (!colorBuffer)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieving the dimensions of the display mode used
|
||||||
|
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
|
||||||
|
uint32_t width = mode->hdisplay;
|
||||||
|
uint32_t height = mode->vdisplay;
|
||||||
|
|
||||||
|
// Dumb buffers use a fixed format based on bpp
|
||||||
|
#if SW_COLOR_BUFFER_BITS == 24
|
||||||
|
const uint32_t bpp = 32; // 32 bits per pixel (XRGB8888 format)
|
||||||
|
const uint32_t depth = 24; // Color depth, here only 24 bits, alpha is not used
|
||||||
|
#else
|
||||||
|
// REVIEW: Not sure how it will be interpreted (RGB or RGBA?)
|
||||||
|
const uint32_t bpp = SW_COLOR_BUFFER_BITS;
|
||||||
|
const uint32_t depth = SW_COLOR_BUFFER_BITS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create a dumb buffer for software rendering
|
||||||
|
struct drm_mode_create_dumb creq = {0};
|
||||||
|
creq.width = width;
|
||||||
|
creq.height = height;
|
||||||
|
creq.bpp = bpp;
|
||||||
|
|
||||||
|
int result = drmIoctl(platform.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to create dumb buffer: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create framebuffer with the correct format
|
||||||
|
uint32_t fb = 0;
|
||||||
|
result = drmModeAddFB(platform.fd,
|
||||||
|
width, height,
|
||||||
|
depth, bpp, creq.pitch,
|
||||||
|
creq.handle, &fb);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno));
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the dumb buffer to copy our software rendered buffer
|
||||||
|
struct drm_mode_map_dumb mreq = {0};
|
||||||
|
mreq.handle = creq.handle;
|
||||||
|
result = drmIoctl(platform.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to map dumb buffer: %s", strerror(errno));
|
||||||
|
drmModeRmFB(platform.fd, fb);
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the buffer into userspace
|
||||||
|
void *dumbBuffer = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, platform.fd, mreq.offset);
|
||||||
|
if (dumbBuffer == MAP_FAILED)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to mmap dumb buffer: %s", strerror(errno));
|
||||||
|
drmModeRmFB(platform.fd, fb);
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the software rendered buffer to the dumb buffer with scaling if needed
|
||||||
|
if (bufferWidth == width && bufferHeight == height)
|
||||||
|
{
|
||||||
|
// Direct copy if sizes match
|
||||||
|
swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Scale the software buffer to match the display mode
|
||||||
|
swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap the buffer
|
||||||
|
munmap(dumbBuffer, creq.size);
|
||||||
|
|
||||||
|
// Find a CRTC compatible with the connector
|
||||||
|
uint32_t crtcId = 0;
|
||||||
|
if (platform.crtc)
|
||||||
|
{
|
||||||
|
crtcId = platform.crtc->crtc_id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find a CRTC that's compatible with this connector
|
||||||
|
drmModeRes *res = drmModeGetResources(platform.fd);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources");
|
||||||
|
drmModeRmFB(platform.fd, fb);
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check which CRTCs are compatible with this connector
|
||||||
|
drmModeEncoder *encoder = NULL;
|
||||||
|
if (platform.connector->encoder_id)
|
||||||
|
{
|
||||||
|
encoder = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder && encoder->crtc_id)
|
||||||
|
{
|
||||||
|
crtcId = encoder->crtc_id;
|
||||||
|
platform.crtc = drmModeGetCrtc(platform.fd, crtcId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find a free CRTC
|
||||||
|
for (int i = 0; i < res->count_crtcs; i++)
|
||||||
|
{
|
||||||
|
drmModeCrtc *crtc = drmModeGetCrtc(platform.fd, res->crtcs[i]);
|
||||||
|
if (crtc && !crtc->buffer_id) // CRTC is free
|
||||||
|
{
|
||||||
|
crtcId = res->crtcs[i];
|
||||||
|
if (platform.crtc) drmModeFreeCrtc(platform.crtc);
|
||||||
|
platform.crtc = crtc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (crtc) drmModeFreeCrtc(crtc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder) drmModeFreeEncoder(encoder);
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
|
||||||
|
if (!crtcId)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found");
|
||||||
|
drmModeRmFB(platform.fd, fb);
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set CRTC with better error handling
|
||||||
|
result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0,
|
||||||
|
&platform.connector->connector_id, 1,
|
||||||
|
mode);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno));
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: CRTC ID: %u, FB ID: %u, Connector ID: %u", crtcId, fb, platform.connector->connector_id);
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
|
||||||
|
|
||||||
|
drmModeRmFB(platform.fd, fb);
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = creq.handle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up previous framebuffer
|
||||||
|
if (platform.prevFB)
|
||||||
|
{
|
||||||
|
result = drmModeRmFB(platform.fd, platform.prevFB);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "DISPLAY: drmModeRmFB() failed with result: %d", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.prevFB = fb;
|
||||||
|
|
||||||
|
// Clean up previous dumb buffer
|
||||||
|
if (platform.prevDumbHandle)
|
||||||
|
{
|
||||||
|
struct drm_mode_destroy_dumb dreq = {0};
|
||||||
|
dreq.handle = platform.prevDumbHandle;
|
||||||
|
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.prevDumbHandle = creq.handle;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -723,10 +937,15 @@ int InitPlatform(void)
|
||||||
platform.connector = NULL;
|
platform.connector = NULL;
|
||||||
platform.modeIndex = -1;
|
platform.modeIndex = -1;
|
||||||
platform.crtc = NULL;
|
platform.crtc = NULL;
|
||||||
|
platform.prevFB = 0;
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
platform.gbmDevice = NULL;
|
platform.gbmDevice = NULL;
|
||||||
platform.gbmSurface = NULL;
|
platform.gbmSurface = NULL;
|
||||||
platform.prevBO = NULL;
|
platform.prevBO = NULL;
|
||||||
platform.prevFB = 0;
|
#else
|
||||||
|
platform.prevDumbHandle = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize graphic device: display/window and graphic context
|
// Initialize graphic device: display/window and graphic context
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -743,6 +962,7 @@ int InitPlatform(void)
|
||||||
|
|
||||||
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
||||||
{
|
{
|
||||||
|
if (platform.fd != -1) close(platform.fd);
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
|
||||||
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
|
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
|
||||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
|
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
|
||||||
|
|
@ -750,10 +970,19 @@ int InitPlatform(void)
|
||||||
|
|
||||||
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
||||||
{
|
{
|
||||||
|
if (platform.fd != -1) close(platform.fd);
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
|
||||||
platform.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)
|
||||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
|
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
||||||
|
{
|
||||||
|
if (platform.fd != -1) close(platform.fd);
|
||||||
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card0, trying card2");
|
||||||
|
platform.fd = open("/dev/dri/card2", O_RDWR);
|
||||||
|
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card2 opened successfully");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (platform.fd == -1)
|
if (platform.fd == -1)
|
||||||
|
|
@ -766,29 +995,57 @@ int InitPlatform(void)
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors);
|
TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors);
|
||||||
|
|
||||||
|
// Connector detection
|
||||||
for (size_t i = 0; i < res->count_connectors; i++)
|
for (size_t i = 0; i < res->count_connectors; i++)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i);
|
TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i);
|
||||||
|
|
||||||
drmModeConnector *con = drmModeGetConnector(platform.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)
|
||||||
|
|
||||||
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected.
|
|
||||||
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output.
|
|
||||||
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id))
|
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get connector %i", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
|
||||||
|
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
|
||||||
|
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
|
||||||
|
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
|
||||||
|
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
|
||||||
|
|
||||||
|
// Accept CONNECTED, UNKNOWN and even those without encoder_id connectors for software mode
|
||||||
|
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) &&
|
||||||
|
(con->count_modes > 0))
|
||||||
|
{
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
|
// For hardware rendering, we need an encoder_id
|
||||||
|
if (con->encoder_id)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected with encoder", i);
|
||||||
platform.connector = con;
|
platform.connector = con;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)");
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// For software rendering, we can accept even without encoder_id
|
||||||
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i);
|
||||||
|
platform.connector = con;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!platform.connector)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i NOT suitable (deleting)", i);
|
||||||
drmModeFreeConnector(con);
|
drmModeFreeConnector(con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -797,14 +1054,18 @@ int InitPlatform(void)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
|
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
|
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
|
||||||
if (!enc)
|
if (!enc)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
|
||||||
|
drmModeFreeConnector(platform.connector);
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -813,7 +1074,9 @@ int InitPlatform(void)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
|
||||||
drmModeFreeEncoder(enc);
|
drmModeFreeEncoder(enc);
|
||||||
|
drmModeFreeConnector(platform.connector);
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -828,7 +1091,9 @@ int InitPlatform(void)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
|
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
|
||||||
drmModeFreeEncoder(enc);
|
drmModeFreeEncoder(enc);
|
||||||
|
drmModeFreeConnector(platform.connector);
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -837,7 +1102,7 @@ int InitPlatform(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
||||||
const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
|
const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60;
|
||||||
|
|
||||||
// Try to find an exact matching mode
|
// Try to find an exact matching mode
|
||||||
platform.modeIndex = FindExactConnectorMode(platform.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);
|
||||||
|
|
@ -856,7 +1121,9 @@ int InitPlatform(void)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
|
||||||
drmModeFreeEncoder(enc);
|
drmModeFreeEncoder(enc);
|
||||||
|
drmModeFreeConnector(platform.connector);
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -865,19 +1132,45 @@ int InitPlatform(void)
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
|
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].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
|
||||||
(platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
|
(platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||||
platform.connector->modes[platform.modeIndex].vrefresh);
|
platform.connector->modes[platform.modeIndex].vrefresh);
|
||||||
|
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
enc = NULL;
|
||||||
|
#else
|
||||||
|
// For software rendering, the first available mode can be used
|
||||||
|
if (platform.connector->count_modes > 0)
|
||||||
|
{
|
||||||
|
platform.modeIndex = 0;
|
||||||
|
CORE.Window.display.width = platform.connector->modes[0].hdisplay;
|
||||||
|
CORE.Window.display.height = platform.connector->modes[0].vdisplay;
|
||||||
|
|
||||||
|
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
|
||||||
|
platform.connector->modes[0].name,
|
||||||
|
platform.connector->modes[0].hdisplay,
|
||||||
|
platform.connector->modes[0].vdisplay,
|
||||||
|
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||||
|
platform.connector->modes[0].vrefresh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "DISPLAY: No modes available for connector");
|
||||||
|
drmModeFreeConnector(platform.connector);
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
close(platform.fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Use the width and height of the surface for render
|
// Use the width and height of the surface for render
|
||||||
CORE.Window.render.width = CORE.Window.screen.width;
|
CORE.Window.render.width = CORE.Window.screen.width;
|
||||||
CORE.Window.render.height = CORE.Window.screen.height;
|
CORE.Window.render.height = CORE.Window.screen.height;
|
||||||
|
|
||||||
drmModeFreeEncoder(enc);
|
|
||||||
enc = NULL;
|
|
||||||
|
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
|
// Hardware rendering initialization with EGL
|
||||||
platform.gbmDevice = gbm_create_device(platform.fd);
|
platform.gbmDevice = gbm_create_device(platform.fd);
|
||||||
if (!platform.gbmDevice)
|
if (!platform.gbmDevice)
|
||||||
{
|
{
|
||||||
|
|
@ -1046,6 +1339,32 @@ int InitPlatform(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load OpenGL extensions
|
||||||
|
// NOTE: GL procedures address loader is required to load extensions
|
||||||
|
rlLoadExtensions(eglGetProcAddress);
|
||||||
|
#else
|
||||||
|
// At this point we need to manage render size vs screen size
|
||||||
|
// NOTE: This function use and modify global module variables:
|
||||||
|
// -> CORE.Window.screen.width/CORE.Window.screen.height
|
||||||
|
// -> CORE.Window.render.width/CORE.Window.render.height
|
||||||
|
// -> CORE.Window.screenScale
|
||||||
|
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
|
||||||
|
|
||||||
|
// Setup window ready state for software rendering
|
||||||
|
CORE.Window.ready = true;
|
||||||
|
|
||||||
|
CORE.Window.render.width = CORE.Window.screen.width;
|
||||||
|
CORE.Window.render.height = CORE.Window.screen.height;
|
||||||
|
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||||
|
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||||
|
|
||||||
|
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully (Software Rendering)");
|
||||||
|
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||||
|
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||||
|
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||||
|
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
||||||
|
|
||||||
// If graphic device is no properly initialized, we end program
|
// If graphic device is no properly initialized, we end program
|
||||||
|
|
@ -1058,12 +1377,8 @@ int InitPlatform(void)
|
||||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
||||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
||||||
|
|
||||||
// Load OpenGL extensions
|
|
||||||
// NOTE: GL procedures address loader is required to load extensions
|
|
||||||
rlLoadExtensions(eglGetProcAddress);
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
// Initialize timing system
|
||||||
// Initialize timming system
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// NOTE: timming system must be initialized before the input events system
|
// NOTE: timming system must be initialized before the input events system
|
||||||
InitTimer();
|
InitTimer();
|
||||||
|
|
@ -1097,6 +1412,7 @@ void ClosePlatform(void)
|
||||||
platform.prevFB = 0;
|
platform.prevFB = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
if (platform.prevBO)
|
if (platform.prevBO)
|
||||||
{
|
{
|
||||||
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
||||||
|
|
@ -1114,6 +1430,7 @@ void ClosePlatform(void)
|
||||||
gbm_device_destroy(platform.gbmDevice);
|
gbm_device_destroy(platform.gbmDevice);
|
||||||
platform.gbmDevice = NULL;
|
platform.gbmDevice = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (platform.crtc)
|
if (platform.crtc)
|
||||||
{
|
{
|
||||||
|
|
@ -1135,6 +1452,7 @@ void ClosePlatform(void)
|
||||||
platform.fd = -1;
|
platform.fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||||
// Close surface, context and display
|
// Close surface, context and display
|
||||||
if (platform.device != EGL_NO_DISPLAY)
|
if (platform.device != EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
|
@ -1153,6 +1471,7 @@ void ClosePlatform(void)
|
||||||
eglTerminate(platform.device);
|
eglTerminate(platform.device);
|
||||||
platform.device = EGL_NO_DISPLAY;
|
platform.device = EGL_NO_DISPLAY;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
|
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user