1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | |
22 | #include "SDL_internal.h" |
23 | |
24 | #ifndef SDL_kmsdrmvideo_h |
25 | #define SDL_kmsdrmvideo_h |
26 | |
27 | #include "../SDL_sysvideo.h" |
28 | |
29 | #include <fcntl.h> |
30 | #include <unistd.h> |
31 | #include <xf86drm.h> |
32 | #include <xf86drmMode.h> |
33 | #include <gbm.h> |
34 | #include <EGL/egl.h> |
35 | |
36 | #ifndef DRM_FORMAT_MOD_INVALID |
37 | #define DRM_FORMAT_MOD_INVALID 0x00ffffffffffffffULL |
38 | #endif |
39 | |
40 | #ifndef DRM_MODE_FB_MODIFIERS |
41 | #define DRM_MODE_FB_MODIFIERS 2 |
42 | #endif |
43 | |
44 | #ifndef DRM_MODE_PAGE_FLIP_ASYNC |
45 | #define DRM_MODE_PAGE_FLIP_ASYNC 2 |
46 | #endif |
47 | |
48 | #ifndef DRM_MODE_OBJECT_CONNECTOR |
49 | #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 |
50 | #endif |
51 | |
52 | #ifndef DRM_MODE_OBJECT_CRTC |
53 | #define DRM_MODE_OBJECT_CRTC 0xcccccccc |
54 | #endif |
55 | |
56 | #ifndef DRM_CAP_ASYNC_PAGE_FLIP |
57 | #define DRM_CAP_ASYNC_PAGE_FLIP 7 |
58 | #endif |
59 | |
60 | #ifndef DRM_CAP_CURSOR_WIDTH |
61 | #define DRM_CAP_CURSOR_WIDTH 8 |
62 | #endif |
63 | |
64 | #ifndef DRM_CAP_CURSOR_HEIGHT |
65 | #define DRM_CAP_CURSOR_HEIGHT 9 |
66 | #endif |
67 | |
68 | #ifndef GBM_FORMAT_ARGB8888 |
69 | #define GBM_FORMAT_ARGB8888 ((uint32_t)('A') | ((uint32_t)('R') << 8) | ((uint32_t)('2') << 16) | ((uint32_t)('4') << 24)) |
70 | #define GBM_BO_USE_CURSOR (1 << 1) |
71 | #define GBM_BO_USE_WRITE (1 << 3) |
72 | #define GBM_BO_USE_LINEAR (1 << 4) |
73 | #endif |
74 | |
75 | struct SDL_VideoData |
76 | { |
77 | int devindex; // device index that was passed on creation |
78 | int drm_fd; // DRM file desc |
79 | char devpath[32]; // DRM dev path. |
80 | |
81 | struct gbm_device *gbm_dev; |
82 | |
83 | bool video_init; // Has VideoInit succeeded? |
84 | bool vulkan_mode; // Are we in Vulkan mode? One VK window is enough to be. |
85 | bool async_pageflip_support; // Does the hardware support async. pageflips? |
86 | |
87 | SDL_Window **windows; |
88 | int max_windows; |
89 | int num_windows; |
90 | |
91 | /* Even if we have several displays, we only have to |
92 | open 1 FD and create 1 gbm device. */ |
93 | bool gbm_init; |
94 | |
95 | }; |
96 | |
97 | struct SDL_DisplayModeData |
98 | { |
99 | int mode_index; |
100 | }; |
101 | |
102 | struct SDL_DisplayData |
103 | { |
104 | drmModeConnector *connector; |
105 | drmModeCrtc *crtc; |
106 | drmModeModeInfo mode; |
107 | drmModeModeInfo original_mode; |
108 | drmModeModeInfo fullscreen_mode; |
109 | |
110 | drmModeCrtc *saved_crtc; // CRTC to restore on quit |
111 | bool saved_vrr; |
112 | |
113 | /* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's internal struct, |
114 | because setting/unsetting up these is done on window creation/destruction, |
115 | where we may not have an SDL_Cursor at all (so no SDL_Cursor internal). |
116 | There's only one cursor GBM BO because we only support one cursor. */ |
117 | struct gbm_bo *cursor_bo; |
118 | int cursor_bo_drm_fd; |
119 | uint64_t cursor_w, cursor_h; |
120 | |
121 | bool default_cursor_init; |
122 | }; |
123 | |
124 | struct SDL_WindowData |
125 | { |
126 | SDL_VideoData *viddata; |
127 | /* SDL internals expect EGL surface to be here, and in KMSDRM the GBM surface is |
128 | what supports the EGL surface on the driver side, so all these surfaces and buffers |
129 | are expected to be here, in the struct pointed by SDL_Window internal pointer: |
130 | this one. So don't try to move these to dispdata! */ |
131 | struct gbm_surface *gs; |
132 | struct gbm_bo *bo; |
133 | struct gbm_bo *next_bo; |
134 | |
135 | bool waiting_for_flip; |
136 | bool double_buffer; |
137 | |
138 | EGLSurface egl_surface; |
139 | bool egl_surface_dirty; |
140 | }; |
141 | |
142 | typedef struct KMSDRM_FBInfo |
143 | { |
144 | int drm_fd; // DRM file desc |
145 | uint32_t fb_id; // DRM framebuffer ID |
146 | } KMSDRM_FBInfo; |
147 | |
148 | // Helper functions |
149 | extern bool KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window); |
150 | extern KMSDRM_FBInfo *KMSDRM_FBFromBO(SDL_VideoDevice *_this, struct gbm_bo *bo); |
151 | extern KMSDRM_FBInfo *KMSDRM_FBFromBO2(SDL_VideoDevice *_this, struct gbm_bo *bo, int w, int h); |
152 | extern bool KMSDRM_WaitPageflip(SDL_VideoDevice *_this, SDL_WindowData *windata); |
153 | |
154 | /****************************************************************************/ |
155 | // SDL_VideoDevice functions declaration |
156 | /****************************************************************************/ |
157 | |
158 | // Display and window functions |
159 | extern bool KMSDRM_VideoInit(SDL_VideoDevice *_this); |
160 | extern void KMSDRM_VideoQuit(SDL_VideoDevice *_this); |
161 | extern bool KMSDRM_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); |
162 | extern bool KMSDRM_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); |
163 | extern bool KMSDRM_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); |
164 | extern void KMSDRM_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); |
165 | extern bool KMSDRM_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window); |
166 | extern void KMSDRM_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window); |
167 | extern SDL_FullscreenResult KMSDRM_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *_display, SDL_FullscreenOp fullscreen); |
168 | extern void KMSDRM_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window); |
169 | extern void KMSDRM_HideWindow(SDL_VideoDevice *_this, SDL_Window *window); |
170 | extern void KMSDRM_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window); |
171 | extern void KMSDRM_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window); |
172 | extern void KMSDRM_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window); |
173 | extern void KMSDRM_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window); |
174 | extern void KMSDRM_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); |
175 | |
176 | #endif // SDL_kmsdrmvideo_h |
177 | |