mirror of
https://github.com/raysan5/raylib.git
synced 2025-10-05 17:36:26 +00:00
[rlgl] Add Software Rendering Support (#4832)
* add base of rlsw.h * implement state support Also replace the triangle rasterization functions with macros that generate specific functions for each state of the rendering system. Also, add the OpenGL definitions in order to add a binding for rlgl. * branchless float saturation * apply perspective correction to colors * impl line clipping and rasterization + tweak function names * impl face culling * impl color blending * fixes and tweaks * add clear buffer bitmasks * small optimizations / tweaks * review ndc to screen projection * avoid to recalculate MVP when its not needed + tweaks * review the loading and management of textures to be closer to the OpenGL API * texture sampling optimization * review get pixel functions + review unorm/float conversion * add several buffer format support Several depth and color formats have been added for the framebuffer. 8-bit, 16-bit, and 24-bit formats are now available for depth. RGB 8-bit (332), RGB 16-bit (565), and RGB 24-bit (888) formats are now available for color. Alpha support is no longer present for the framebuffer at the moment, but it can easily be restored by adding the formats and reinterpolating the alpha in the areas that do not perform color blending. Additionally, this commit brings performance improvements. * tweaks * impl line width * impl points + point size * fix and improve polygon clipping functions * impl polygone modes * add some not planned functions - `glDepthMask` - `glColorMask` * framebuffer resizing + handle init failure * add quick notes about line clipping algorithms used * start to impl scissor test + review line clipping The support for the scissor test has been implemented for clearing as well as for triangle clipping. The implementation for lines and points is still missing. I also removed the 2D clipping of lines that used the Cohen-Sutherland algorithm, opting instead to always use the Liang-Barsky algorithm in all cases. This simplifies the implementation, and the 2D version would have caused issues when interpolating vertices in the future if we want to implement additional features. * review scissor clear * review `swScissor` * impl line scissor clipping * round screen coordinate (line rasterization) * impl point scissor clipping * remove unused defs * add getter functions * gl binding * add `glHint` and `glShadeModel` macros (not implmented) * binding tweaks * impl copy framebuffer function + glReadPixels * review `swCopyFramebuffer` * update rlgl.h * update rlgl.h * texture copy support * fix typo.. * add get error function * def sw alloc macros * reimpl get color buffer func just in case * remove normal interpolation * review texture wrap * fix ndc projection (viewport/scissor) * impl framebuffer blit function * reduce matrix compuations and memory usage * swBegin tweaks * preventing a possible division by zero * remove useless scissor related data * review color blending system * greatly improve float saturation * tweak lerp vertex function * use opitmized fract function in sw_texture_map * tweak framebuffer functions for better readability * optimized copy/blit functions for each dst format * review framebuffer filling functions * impl specific quad rendering func * use of a single global vertex buffer * fix 'sw_poly_point_render' * added `SW_RESTRICT` and redesigned `sw_lerp_vertex_PNCTH` * tweak the pipeline flow regarding the face culling avoids misprediction, improves vectorization if possible * new rendering path for axis aligned quads * oops, translating some comments * use of `restrict` for blending function parameters * update rlgl.h * adding `GRAPHICS_API_OPENGL_11_SOFTWARE` in `DrawMesh` * add `RL_OPENGL_11_SOFTWARE` enum * temp tweak * build fixes * fix DrawMesh for GL 1.1 * update swClose * review texture format + fix copy * set minimum req vertices to 3 (quads) * check swInit * review pixelformat * tweaks * fix animNormals (DrawMesh) * fallback color/texcoord (swDrawArrays) * review swMultMatrixf * fix texture pool alloc.. * review triangle scanlines increment all data * fix `sw_quad_sort_cw` * impl sdl platform * rm def * increase max clipped polygon vertices * improve triangle rasterization along Y axis improved robustness against numerical errors incremental interpolation along Y simplified function, fewer jumps * review current vertex data + increase max clipped polygon vertices (for extreme cases) * fix and improve polygon clipping Sets the vertex count to zero when the polygon is invalid Stops clipping when the vertex count drops below 3 * fix gradient calculation * cache texture size minus one + comments * tweaks * BGRA copy support * adding software backend option (cmake) * update Makefile * fix face culling * excluse some exemple with the software backend * review SW_CLAMP case in sw_texture_map * review sw_saturate * review line raster * fix sw_quad_is_aligned * review sw_raster_quad_axis_aligned * tweaks * codepoint fix (?) * fix var name... * rcore_drm software renderering * cleanup and tweaks * adding support for `GL_POINT_SIZE` and `GL_LINE_WIDTH` get * fix sampling issue * fix swBlendFunc --------- Co-authored-by: Ray <raysan5@gmail.com>
This commit is contained in:
@@ -8,7 +8,7 @@ if(EMSCRIPTEN)
|
||||
endif()
|
||||
enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL" "Platform to build for.")
|
||||
|
||||
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0" "Force a specific OpenGL Version?")
|
||||
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?")
|
||||
|
||||
# Configuration options
|
||||
option(BUILD_EXAMPLES "Build the examples." ${PROJECT_IS_TOP_LEVEL})
|
||||
|
@@ -158,6 +158,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF")
|
||||
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
|
||||
elseif (${OPENGL_VERSION} MATCHES "ES 3.0")
|
||||
set(GRAPHICS "GRAPHICS_API_OPENGL_ES3")
|
||||
elseif (${OPENGL_VERSION} MATCHES "Software")
|
||||
set(GRAPHICS "GRAPHICS_API_OPENGL_11_SOFTWARE")
|
||||
endif ()
|
||||
if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
|
||||
message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.")
|
||||
|
@@ -105,6 +105,10 @@ elseif ("${PLATFORM}" STREQUAL "DRM")
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/rlgl_standalone.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/raylib_opengl_interop.c)
|
||||
|
||||
elseif ("${OPENGL_VERSION}" STREQUAL "Software")
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/rlgl_standalone.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/raylib_opengl_interop.c)
|
||||
|
||||
elseif (NOT SUPPORT_GESTURES_SYSTEM)
|
||||
# Items requiring gestures system
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/textures/textures_mouse_painting.c)
|
||||
|
18
src/Makefile
18
src/Makefile
@@ -235,20 +235,22 @@ endif
|
||||
# NOTE: By default use OpenGL 3.3 on desktop platforms
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_33
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_33
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_33
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
|
||||
# On DRM OpenGL ES 2.0 must be used
|
||||
|
5230
src/external/rlsw.h
vendored
Normal file
5230
src/external/rlsw.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -63,18 +63,20 @@
|
||||
#include "SDL.h"
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// It seems it does not need to be included to work
|
||||
//#include "SDL_opengles2.h"
|
||||
#else
|
||||
// SDL OpenGL functionality (if required, instead of internal renderer)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL_opengl.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#include "SDL2/SDL_opengl.h"
|
||||
#else
|
||||
#include "SDL_opengl.h"
|
||||
#endif
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// It seems it does not need to be included to work
|
||||
//#include "SDL_opengles2.h"
|
||||
#else
|
||||
// SDL OpenGL functionality (if required, instead of internal renderer)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL_opengl.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#include "SDL2/SDL_opengl.h"
|
||||
#else
|
||||
#include "SDL_opengl.h"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -1229,7 +1231,14 @@ void DisableCursor(void)
|
||||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering
|
||||
SDL_Surface* surface = SDL_GetWindowSurface(platform.window);
|
||||
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels);
|
||||
SDL_UpdateWindowSurface(platform.window);
|
||||
#else
|
||||
SDL_GL_SwapWindow(platform.window);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -1577,13 +1586,15 @@ void PollInputEvents(void)
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||
{
|
||||
// Add character (codepoint) to the queue
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
size_t textLen = strlen(event.text.text);
|
||||
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen);
|
||||
#else
|
||||
#else
|
||||
int codepointSize = 0;
|
||||
int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
|
||||
CORE.Input.Keyboard.charPressedQueueCount++;
|
||||
}
|
||||
@@ -1887,7 +1898,6 @@ int InitPlatform(void)
|
||||
//----------------------------------------------------------------------------
|
||||
unsigned int flags = 0;
|
||||
flags |= SDL_WINDOW_SHOWN;
|
||||
flags |= SDL_WINDOW_OPENGL;
|
||||
flags |= SDL_WINDOW_INPUT_FOCUS;
|
||||
flags |= SDL_WINDOW_MOUSE_FOCUS;
|
||||
flags |= SDL_WINDOW_MOUSE_CAPTURE; // Window has mouse captured
|
||||
@@ -1922,44 +1932,50 @@ int InitPlatform(void)
|
||||
|
||||
// NOTE: Some OpenGL context attributes must be set before window creation
|
||||
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_33)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_43)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context
|
||||
#endif
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
// Add the flag telling the window to use an OpenGL context
|
||||
flags |= SDL_WINDOW_OPENGL;
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_33)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_43)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context
|
||||
#endif
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Init window
|
||||
@@ -1970,10 +1986,12 @@ int InitPlatform(void)
|
||||
#endif
|
||||
|
||||
// Init OpenGL context
|
||||
platform.glContext = SDL_GL_CreateContext(platform.window);
|
||||
if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
|
||||
{
|
||||
platform.glContext = SDL_GL_CreateContext(platform.window);
|
||||
}
|
||||
|
||||
// Check window and glContext have been initialized successfully
|
||||
if ((platform.window != NULL) && (platform.glContext != NULL))
|
||||
if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_11_SOFTWARE) || (platform.glContext != NULL)))
|
||||
{
|
||||
CORE.Window.ready = true;
|
||||
|
||||
@@ -1994,8 +2012,14 @@ int InitPlatform(void)
|
||||
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);
|
||||
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT) SDL_GL_SetSwapInterval(1);
|
||||
else SDL_GL_SetSwapInterval(0);
|
||||
if (platform.glContext != NULL)
|
||||
{
|
||||
SDL_GL_SetSwapInterval((CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0);
|
||||
|
||||
// Load OpenGL extensions
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
rlLoadExtensions(SDL_GL_GetProcAddress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2003,9 +2027,6 @@ int InitPlatform(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load OpenGL extensions
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
rlLoadExtensions(SDL_GL_GetProcAddress);
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize input events system
|
||||
@@ -2077,7 +2098,7 @@ int InitPlatform(void)
|
||||
void ClosePlatform(void)
|
||||
{
|
||||
SDL_FreeCursor(platform.cursor); // Free cursor
|
||||
SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
|
||||
if (platform.glContext != NULL) SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
|
||||
SDL_DestroyWindow(platform.window);
|
||||
SDL_Quit(); // Deinitialize SDL internal global state
|
||||
}
|
||||
|
@@ -65,12 +65,17 @@
|
||||
// so the enum KEY_F12 from raylib is used
|
||||
#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 <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
|
||||
|
||||
#include "EGL/egl.h" // Native platform windowing system interface
|
||||
#include "EGL/eglext.h" // EGL extensions
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#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
|
||||
|
||||
// NOTE: DRM cache enables triple buffered DRM caching
|
||||
#if defined(SUPPORT_DRM_CACHE)
|
||||
@@ -103,15 +108,19 @@ typedef struct {
|
||||
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
|
||||
drmModeCrtc *crtc; // CRT Controller
|
||||
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_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
|
||||
#else
|
||||
uint32_t prevDumbHandle; // Handle to the previous dumb buffer (during frame swapping)
|
||||
#endif
|
||||
|
||||
// Keyboard data
|
||||
int defaultKeyboardMode; // Default keyboard mode
|
||||
@@ -780,6 +789,8 @@ void SwapScreenBuffer()
|
||||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// Hardware rendering buffer swap with EGL
|
||||
eglSwapBuffers(platform.device, platform.surface);
|
||||
|
||||
if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
|
||||
@@ -805,6 +816,209 @@ void SwapScreenBuffer(void)
|
||||
if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
||||
|
||||
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
|
||||
}
|
||||
#endif // SUPPORT_DRM_CACHE
|
||||
|
||||
@@ -950,10 +1164,15 @@ int InitPlatform(void)
|
||||
platform.connector = NULL;
|
||||
platform.modeIndex = -1;
|
||||
platform.crtc = NULL;
|
||||
platform.prevFB = 0;
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
platform.gbmDevice = NULL;
|
||||
platform.gbmSurface = NULL;
|
||||
platform.prevBO = NULL;
|
||||
platform.prevFB = 0;
|
||||
#else
|
||||
platform.prevDumbHandle = 0;
|
||||
#endif
|
||||
|
||||
// Initialize graphic device: display/window and graphic context
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -965,11 +1184,12 @@ int InitPlatform(void)
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully");
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card");
|
||||
platform.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 (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
|
||||
|
||||
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");
|
||||
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
|
||||
@@ -977,10 +1197,19 @@ int InitPlatform(void)
|
||||
|
||||
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");
|
||||
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) || (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
|
||||
|
||||
if (platform.fd == -1)
|
||||
@@ -993,29 +1222,58 @@ int InitPlatform(void)
|
||||
if (!res)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors);
|
||||
|
||||
// Connector detection
|
||||
for (size_t i = 0; i < res->count_connectors; i++)
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i);
|
||||
|
||||
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
|
||||
if (!con)
|
||||
{
|
||||
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");
|
||||
|
||||
// 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))
|
||||
// WARNING: 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)//(con->encoder_id))
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
|
||||
#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;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
}
|
||||
else
|
||||
|
||||
if (!platform.connector)
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)");
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i NOT suitable (deleting)", i);
|
||||
drmModeFreeConnector(con);
|
||||
}
|
||||
}
|
||||
@@ -1024,14 +1282,18 @@ int InitPlatform(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
|
||||
drmModeFreeResources(res);
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
|
||||
if (!enc)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
|
||||
drmModeFreeConnector(platform.connector);
|
||||
drmModeFreeResources(res);
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1040,7 +1302,9 @@ int InitPlatform(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
|
||||
drmModeFreeEncoder(enc);
|
||||
drmModeFreeConnector(platform.connector);
|
||||
drmModeFreeResources(res);
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1055,7 +1319,9 @@ int InitPlatform(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
|
||||
drmModeFreeEncoder(enc);
|
||||
drmModeFreeConnector(platform.connector);
|
||||
drmModeFreeResources(res);
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1064,7 +1330,7 @@ int InitPlatform(void)
|
||||
}
|
||||
|
||||
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
|
||||
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
||||
@@ -1083,7 +1349,9 @@ int InitPlatform(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
|
||||
drmModeFreeEncoder(enc);
|
||||
drmModeFreeConnector(platform.connector);
|
||||
drmModeFreeResources(res);
|
||||
close(platform.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1092,19 +1360,45 @@ int InitPlatform(void)
|
||||
|
||||
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].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||
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
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
|
||||
drmModeFreeEncoder(enc);
|
||||
enc = NULL;
|
||||
|
||||
drmModeFreeResources(res);
|
||||
res = NULL;
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// Hardware rendering initialization with EGL
|
||||
platform.gbmDevice = gbm_create_device(platform.fd);
|
||||
if (!platform.gbmDevice)
|
||||
{
|
||||
@@ -1273,6 +1567,32 @@ int InitPlatform(void)
|
||||
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 graphic device is no properly initialized, we end program
|
||||
@@ -1285,12 +1605,8 @@ int InitPlatform(void)
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
||||
|
||||
// Load OpenGL extensions
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
rlLoadExtensions(eglGetProcAddress);
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize timming system
|
||||
// Initialize timing system
|
||||
//----------------------------------------------------------------------------
|
||||
// NOTE: timming system must be initialized before the input events system
|
||||
InitTimer();
|
||||
@@ -1336,6 +1652,7 @@ void ClosePlatform(void)
|
||||
platform.prevFB = 0;
|
||||
}
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
if (platform.prevBO)
|
||||
{
|
||||
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
|
||||
@@ -1353,6 +1670,7 @@ void ClosePlatform(void)
|
||||
gbm_device_destroy(platform.gbmDevice);
|
||||
platform.gbmDevice = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (platform.crtc)
|
||||
{
|
||||
@@ -1374,6 +1692,7 @@ void ClosePlatform(void)
|
||||
platform.fd = -1;
|
||||
}
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// Close surface, context and display
|
||||
if (platform.device != EGL_NO_DISPLAY)
|
||||
{
|
||||
@@ -1392,6 +1711,7 @@ void ClosePlatform(void)
|
||||
eglTerminate(platform.device);
|
||||
platform.device = EGL_NO_DISPLAY;
|
||||
}
|
||||
#endif
|
||||
|
||||
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
|
||||
|
||||
|
85
src/rlgl.h
85
src/rlgl.h
@@ -149,7 +149,8 @@
|
||||
#endif
|
||||
|
||||
// Security check in case no GRAPHICS_API_OPENGL_* defined
|
||||
#if !defined(GRAPHICS_API_OPENGL_11) && \
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \
|
||||
!defined(GRAPHICS_API_OPENGL_11) && \
|
||||
!defined(GRAPHICS_API_OPENGL_21) && \
|
||||
!defined(GRAPHICS_API_OPENGL_33) && \
|
||||
!defined(GRAPHICS_API_OPENGL_43) && \
|
||||
@@ -159,7 +160,7 @@
|
||||
#endif
|
||||
|
||||
// Security check in case multiple GRAPHICS_API_OPENGL_* defined
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#if defined(GRAPHICS_API_OPENGL_21)
|
||||
#undef GRAPHICS_API_OPENGL_21
|
||||
#endif
|
||||
@@ -174,6 +175,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Software implementation uses OpenGL 1.1 functionality
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#define GRAPHICS_API_OPENGL_11
|
||||
#endif
|
||||
|
||||
// OpenGL 2.1 uses most of OpenGL 3.3 Core functionality
|
||||
// WARNING: Specific parts are checked with #if defines
|
||||
#if defined(GRAPHICS_API_OPENGL_21)
|
||||
@@ -427,7 +433,8 @@ typedef struct rlRenderBatch {
|
||||
|
||||
// OpenGL version
|
||||
typedef enum {
|
||||
RL_OPENGL_11 = 1, // OpenGL 1.1
|
||||
RL_OPENGL_11_SOFTWARE = 0, // Software rendering
|
||||
RL_OPENGL_11, // OpenGL 1.1
|
||||
RL_OPENGL_21, // OpenGL 2.1 (GLSL 120)
|
||||
RL_OPENGL_33, // OpenGL 3.3 (GLSL 330)
|
||||
RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330)
|
||||
@@ -768,6 +775,10 @@ RLAPI unsigned int rlLoadFramebuffer(void); // Loa
|
||||
RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
|
||||
RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete
|
||||
RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
RLAPI void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels);
|
||||
RLAPI void rlResizeFramebuffer(int width, int height);
|
||||
#endif
|
||||
|
||||
// Shaders management
|
||||
RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings
|
||||
@@ -834,24 +845,32 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
|
||||
#include <OpenGL/glext.h> // OpenGL extensions library
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#define RLSW_IMPL
|
||||
#define SW_MALLOC(sz) RL_MALLOC(sz)
|
||||
#define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz)
|
||||
#define SW_FREE(ptr) RL_FREE(ptr)
|
||||
#include "external/rlsw.h" // OpenGL 1.1 software implementation
|
||||
#else
|
||||
// APIENTRY for OpenGL function pointer declarations is required
|
||||
#if !defined(APIENTRY)
|
||||
#if defined(_WIN32)
|
||||
#define APIENTRY __stdcall
|
||||
#else
|
||||
#define APIENTRY
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
|
||||
#include <OpenGL/glext.h> // OpenGL extensions library
|
||||
#else
|
||||
// APIENTRY for OpenGL function pointer declarations is required
|
||||
#if !defined(APIENTRY)
|
||||
#if defined(_WIN32)
|
||||
#define APIENTRY __stdcall
|
||||
#else
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#endif
|
||||
// WINGDIAPI definition. Some Windows OpenGL headers need it
|
||||
#if !defined(WINGDIAPI) && defined(_WIN32)
|
||||
#define WINGDIAPI __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
// WINGDIAPI definition. Some Windows OpenGL headers need it
|
||||
#if !defined(WINGDIAPI) && defined(_WIN32)
|
||||
#define WINGDIAPI __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h> // OpenGL 1.1 library
|
||||
#include <GL/gl.h> // OpenGL 1.1 library
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2337,6 +2356,14 @@ void rlglInit(int width, int height)
|
||||
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
if (!swInit(width, height))
|
||||
{
|
||||
TRACELOG(RL_LOG_ERROR, "RLGL: Software renderer initialization failed!");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Store screen size into global variables
|
||||
RLGL.State.framebufferWidth = width;
|
||||
@@ -2363,6 +2390,10 @@ void rlglClose(void)
|
||||
glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
|
||||
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
swClose();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Load OpenGL extensions
|
||||
@@ -2672,7 +2703,9 @@ void *rlGetProcAddress(const char *procName)
|
||||
int rlGetVersion(void)
|
||||
{
|
||||
int glVersion = 0;
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
glVersion = RL_OPENGL_11_SOFTWARE;
|
||||
#elif defined(GRAPHICS_API_OPENGL_11)
|
||||
glVersion = RL_OPENGL_11;
|
||||
#endif
|
||||
#if defined(GRAPHICS_API_OPENGL_21)
|
||||
@@ -3713,6 +3746,20 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
|
||||
return pixels;
|
||||
}
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels)
|
||||
{
|
||||
unsigned int glInternalFormat, glFormat, glType;
|
||||
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
||||
swCopyFramebuffer(x, y, w, h, glFormat, glType, pixels);
|
||||
}
|
||||
|
||||
void rlResizeFramebuffer(int width, int height)
|
||||
{
|
||||
swResizeFramebuffer(width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Read screen pixel data (color buffer)
|
||||
unsigned char *rlReadScreenPixels(int width, int height)
|
||||
{
|
||||
|
@@ -1429,7 +1429,7 @@ void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int
|
||||
// Draw a 3d mesh with material and transform
|
||||
void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#define GL_VERTEX_ARRAY 0x8074
|
||||
#define GL_NORMAL_ARRAY 0x8075
|
||||
#define GL_COLOR_ARRAY 0x8076
|
||||
|
Reference in New Issue
Block a user