SDL_kmsdrmvideo.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #if SDL_VIDEO_DRIVER_KMSDRM
  20. /* SDL internals */
  21. #include "../SDL_sysvideo.h"
  22. #include "SDL_syswm.h"
  23. #include "SDL_hints.h"
  24. #include "../../events/SDL_events_c.h"
  25. #include "../../events/SDL_mouse_c.h"
  26. #include "../../events/SDL_keyboard_c.h"
  27. #ifdef SDL_INPUT_LINUXEV
  28. #include "../../core/linux/SDL_evdev.h"
  29. #endif
  30. /* KMS/DRM declarations */
  31. #include "SDL_kmsdrmvideo.h"
  32. #include "SDL_kmsdrmevents.h"
  33. #include "SDL_kmsdrmopengles.h"
  34. #include "SDL_kmsdrmmouse.h"
  35. #include "SDL_kmsdrmdyn.h"
  36. #include <sys/stat.h>
  37. #include <dirent.h>
  38. #include <errno.h>
  39. #include <poll.h>
  40. #define KMSDRM_DRI_PATH "/dev/dri/"
  41. static int
  42. check_modesetting(int devindex)
  43. {
  44. SDL_bool available = SDL_FALSE;
  45. char device[512];
  46. int drm_fd;
  47. SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex);
  48. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "check_modesetting: probing \"%s\"", device);
  49. drm_fd = open(device, O_RDWR | O_CLOEXEC);
  50. if (drm_fd >= 0) {
  51. if (SDL_KMSDRM_LoadSymbols()) {
  52. drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
  53. if (resources) {
  54. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d",
  55. KMSDRM_DRI_PATH, devindex,
  56. resources->count_connectors, resources->count_encoders, resources->count_crtcs);
  57. if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) {
  58. for (int i = 0; i < resources->count_connectors; i++) {
  59. drmModeConnector *conn = KMSDRM_drmModeGetConnector(drm_fd, resources->connectors[i]);
  60. if (!conn) {
  61. continue;
  62. }
  63. if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
  64. available = SDL_TRUE;
  65. }
  66. KMSDRM_drmModeFreeConnector(conn);
  67. if (available) {
  68. break;
  69. }
  70. }
  71. }
  72. KMSDRM_drmModeFreeResources(resources);
  73. }
  74. SDL_KMSDRM_UnloadSymbols();
  75. }
  76. close(drm_fd);
  77. }
  78. return available;
  79. }
  80. static int get_dricount(void)
  81. {
  82. int devcount = 0;
  83. struct dirent *res;
  84. struct stat sb;
  85. DIR *folder;
  86. if (!(stat(KMSDRM_DRI_PATH, &sb) == 0
  87. && S_ISDIR(sb.st_mode))) {
  88. printf("The path %s cannot be opened or is not available\n",
  89. KMSDRM_DRI_PATH);
  90. return 0;
  91. }
  92. if (access(KMSDRM_DRI_PATH, F_OK) == -1) {
  93. printf("The path %s cannot be opened\n",
  94. KMSDRM_DRI_PATH);
  95. return 0;
  96. }
  97. folder = opendir(KMSDRM_DRI_PATH);
  98. if (folder) {
  99. while ((res = readdir(folder))) {
  100. int len = SDL_strlen(res->d_name);
  101. if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) {
  102. devcount++;
  103. }
  104. }
  105. closedir(folder);
  106. }
  107. return devcount;
  108. }
  109. static int
  110. get_driindex(void)
  111. {
  112. const int devcount = get_dricount();
  113. int i;
  114. for (i = 0; i < devcount; i++) {
  115. if (check_modesetting(i)) {
  116. return i;
  117. }
  118. }
  119. return -ENOENT;
  120. }
  121. /*********************************/
  122. /* Atomic helper functions block */
  123. /*********************************/
  124. #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
  125. #if 0
  126. static int add_connector_property(drmModeAtomicReq *req, struct connector *connector,
  127. const char *name, uint64_t value)
  128. {
  129. unsigned int i;
  130. int prop_id = 0;
  131. for (i = 0 ; i < connector->props->count_props ; i++) {
  132. if (strcmp(connector->props_info[i]->name, name) == 0) {
  133. prop_id = connector->props_info[i]->prop_id;
  134. break;
  135. }
  136. }
  137. if (prop_id < 0) {
  138. printf("no connector property: %s\n", name);
  139. return -EINVAL;
  140. }
  141. return KMSDRM_drmModeAtomicAddProperty(req, connector->connector->connector_id, prop_id, value);
  142. }
  143. #endif
  144. static int add_crtc_property(drmModeAtomicReq *req, struct crtc *crtc,
  145. const char *name, uint64_t value)
  146. {
  147. unsigned int i;
  148. int prop_id = -1;
  149. for (i = 0 ; i < crtc->props->count_props ; i++) {
  150. if (strcmp(crtc->props_info[i]->name, name) == 0) {
  151. prop_id = crtc->props_info[i]->prop_id;
  152. break;
  153. }
  154. }
  155. if (prop_id < 0) {
  156. printf("no crtc property: %s\n", name);
  157. return -EINVAL;
  158. }
  159. return KMSDRM_drmModeAtomicAddProperty(req, crtc->crtc->crtc_id, prop_id, value);
  160. }
  161. int add_plane_property(drmModeAtomicReq *req, struct plane *plane,
  162. const char *name, uint64_t value)
  163. {
  164. unsigned int i;
  165. int prop_id = -1;
  166. for (i = 0 ; i < plane->props->count_props ; i++) {
  167. if (strcmp(plane->props_info[i]->name, name) == 0) {
  168. prop_id = plane->props_info[i]->prop_id;
  169. break;
  170. }
  171. }
  172. if (prop_id < 0) {
  173. printf("no plane property: %s\n", name);
  174. return -EINVAL;
  175. }
  176. return KMSDRM_drmModeAtomicAddProperty(req, plane->plane->plane_id, prop_id, value);
  177. }
  178. #if 0
  179. void print_plane_info(_THIS, drmModePlanePtr plane)
  180. {
  181. char *plane_type;
  182. drmModeRes *resources;
  183. uint32_t type = 0;
  184. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  185. drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
  186. plane->plane_id, DRM_MODE_OBJECT_PLANE);
  187. /* Search the plane props for the plane type. */
  188. for (int j = 0; j < props->count_props; j++) {
  189. drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd, props->props[j]);
  190. if ((strcmp(p->name, "type") == 0)) {
  191. type = props->prop_values[j];
  192. }
  193. KMSDRM_drmModeFreeProperty(p);
  194. }
  195. switch (type) {
  196. case DRM_PLANE_TYPE_OVERLAY:
  197. plane_type = "overlay";
  198. break;
  199. case DRM_PLANE_TYPE_PRIMARY:
  200. plane_type = "primary";
  201. break;
  202. case DRM_PLANE_TYPE_CURSOR:
  203. plane_type = "cursor";
  204. break;
  205. }
  206. /* Remember that to present a plane on screen, it has to be
  207. connected to a CRTC so the CRTC scans it,
  208. scales it, etc... and presents it on screen. */
  209. /* Now we look for the CRTCs supported by the plane. */
  210. resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
  211. if (!resources)
  212. return;
  213. printf("--PLANE ID: %d\nPLANE TYPE: %s\nCRTC READING THIS PLANE: %d\nCRTCS SUPPORTED BY THIS PLANE: ", plane->plane_id, plane_type, plane->crtc_id);
  214. for (int i = 0; i < resources->count_crtcs; i++) {
  215. if (plane->possible_crtcs & (1 << i)) {
  216. uint32_t crtc_id = resources->crtcs[i];
  217. printf ("%d", crtc_id);
  218. break;
  219. }
  220. }
  221. printf ("\n\n");
  222. }
  223. void get_planes_info(_THIS)
  224. {
  225. drmModePlaneResPtr plane_resources;
  226. uint32_t i;
  227. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  228. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  229. plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd);
  230. if (!plane_resources) {
  231. printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
  232. return;
  233. }
  234. printf("--Number of planes found: %d-- \n", plane_resources->count_planes);
  235. printf("--Usable CRTC that we have chosen: %d-- \n", dispdata->crtc->crtc->crtc_id);
  236. /* Iterate on all the available planes. */
  237. for (i = 0; (i < plane_resources->count_planes); i++) {
  238. uint32_t plane_id = plane_resources->planes[i];
  239. drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id);
  240. if (!plane) {
  241. printf("drmModeGetPlane(%u) failed: %s\n", plane_id, strerror(errno));
  242. continue;
  243. }
  244. /* Print plane info. */
  245. print_plane_info(_this, plane);
  246. KMSDRM_drmModeFreePlane(plane);
  247. }
  248. KMSDRM_drmModeFreePlaneResources(plane_resources);
  249. }
  250. #endif
  251. /* Get the plane_id of a plane that is of the specified plane type (primary,
  252. overlay, cursor...) and can use the CRTC we have chosen previously. */
  253. static uint32_t get_plane_id(_THIS, uint32_t plane_type)
  254. {
  255. drmModeRes *resources = NULL;
  256. drmModePlaneResPtr plane_resources = NULL;
  257. uint32_t i, j;
  258. uint32_t crtc_index = 0;
  259. uint32_t ret = -EINVAL;
  260. int found = 0;
  261. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  262. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  263. resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
  264. /* Get the crtc_index for the current CRTC.
  265. It's needed to find out if a plane supports the CRTC. */
  266. for (i = 0; i < resources->count_crtcs; i++) {
  267. if (resources->crtcs[i] == dispdata->crtc->crtc->crtc_id) {
  268. crtc_index = i;
  269. break;
  270. }
  271. }
  272. plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd);
  273. if (!plane_resources) {
  274. return SDL_SetError("drmModeGetPlaneResources failed.");
  275. }
  276. /* Iterate on all the available planes. */
  277. for (i = 0; (i < plane_resources->count_planes) && !found; i++) {
  278. uint32_t plane_id = plane_resources->planes[i];
  279. drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id);
  280. if (!plane) {
  281. continue;
  282. }
  283. /* See if the current CRTC is available for this plane. */
  284. if (plane->possible_crtcs & (1 << crtc_index)) {
  285. drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
  286. plane_id, DRM_MODE_OBJECT_PLANE);
  287. ret = plane_id;
  288. /* Iterate on the plane props to find the type of the plane,
  289. to see if it's of the type we want. */
  290. for (j = 0; j < props->count_props; j++) {
  291. drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd,
  292. props->props[j]);
  293. if ((strcmp(p->name, "type") == 0) &&
  294. (props->prop_values[j] == plane_type)) {
  295. /* found our plane, use that: */
  296. found = 1;
  297. }
  298. KMSDRM_drmModeFreeProperty(p);
  299. }
  300. KMSDRM_drmModeFreeObjectProperties(props);
  301. }
  302. KMSDRM_drmModeFreePlane(plane);
  303. }
  304. KMSDRM_drmModeFreePlaneResources(plane_resources);
  305. KMSDRM_drmModeFreeResources(resources);
  306. return ret;
  307. }
  308. /* Setup cursor plane and it's props. */
  309. int
  310. setup_plane(_THIS, struct plane **plane, uint32_t plane_type)
  311. {
  312. uint32_t plane_id;
  313. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  314. *plane = SDL_calloc(1, sizeof(*plane));
  315. /* Get plane ID. */
  316. plane_id = get_plane_id(_this, plane_type);
  317. if (!plane_id) {
  318. goto cleanup;
  319. }
  320. /* Get the DRM plane itself. */
  321. (*plane)->plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id);
  322. /* Get the DRM plane properties. */
  323. if ((*plane)->plane) {
  324. (*plane)->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
  325. (*plane)->plane->plane_id, DRM_MODE_OBJECT_PLANE);
  326. (*plane)->props_info = SDL_calloc((*plane)->props->count_props,
  327. sizeof((*plane)->props_info));
  328. for (int i = 0; i < (*plane)->props->count_props; i++) {
  329. (*plane)->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
  330. (*plane)->props->props[i]);
  331. }
  332. }
  333. return 0;
  334. cleanup:
  335. SDL_free(*plane);
  336. *plane = NULL;
  337. return -1;
  338. }
  339. /* Free a plane and it's props. */
  340. void
  341. free_plane(struct plane **plane)
  342. {
  343. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  344. if (dispdata && (*plane)) {
  345. if ((*plane)->plane) {
  346. KMSDRM_drmModeFreePlane((*plane)->plane);
  347. (*plane)->plane = NULL;
  348. }
  349. if ((*plane)->props_info) {
  350. SDL_free((*plane)->props_info);
  351. (*plane)->props_info = NULL;
  352. }
  353. SDL_free(*plane);
  354. *plane = NULL;
  355. }
  356. }
  357. /**********************************************************************************/
  358. /* The most important ATOMIC fn of the backend. */
  359. /* A PLANE reads a BUFFER, and a CRTC reads a PLANE and sends it's contents */
  360. /* over to a CONNECTOR->ENCODER system. */
  361. /* Think of a plane as a "frame" sorrounding a picture, where the "picture" */
  362. /* is the buffer, and we move the "frame" from a picture to another, */
  363. /* and the one that has the "frame" is the one sent over to the screen */
  364. /* via the CONNECTOR->ENCODER system. */
  365. /* Think of a PLANE as being "in the middle", it's the CENTRAL part */
  366. /* bewteen the CRTC and the BUFFER that is shown on screen. */
  367. /* What we do here is connect a PLANE to a CRTC and a BUFFER. */
  368. /* -ALWAYS set the CRTC_ID and FB_ID attribs of a plane at the same time, */
  369. /* meaning IN THE SAME atomic request. */
  370. /* -And NEVER destroy a GBM surface whose buffers are being read by a plane: */
  371. /* first, move the plane away from those buffers and ONLY THEN destroy the */
  372. /* buffers and/or the GBM surface containig them. */
  373. /**********************************************************************************/
  374. void
  375. drm_atomic_setbuffer(_THIS, struct plane *plane, uint32_t fb_id, uint32_t crtc_id)
  376. {
  377. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  378. /* Do we have a set of changes already in the making? If not, allocate a new one. */
  379. if (!dispdata->atomic_req)
  380. dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
  381. add_plane_property(dispdata->atomic_req, plane, "FB_ID", fb_id);
  382. add_plane_property(dispdata->atomic_req, plane, "CRTC_ID", crtc_id);
  383. add_plane_property(dispdata->atomic_req, plane, "SRC_W", dispdata->mode.hdisplay << 16);
  384. add_plane_property(dispdata->atomic_req, plane, "SRC_H", dispdata->mode.vdisplay << 16);
  385. add_plane_property(dispdata->atomic_req, plane, "SRC_X", 0);
  386. add_plane_property(dispdata->atomic_req, plane, "SRC_Y", 0);
  387. add_plane_property(dispdata->atomic_req, plane, "CRTC_W", dispdata->mode.hdisplay);
  388. add_plane_property(dispdata->atomic_req, plane, "CRTC_H", dispdata->mode.vdisplay);
  389. add_plane_property(dispdata->atomic_req, plane, "CRTC_X", 0);
  390. add_plane_property(dispdata->atomic_req, plane, "CRTC_Y", 0);
  391. if (dispdata->kms_in_fence_fd != -1) {
  392. add_crtc_property(dispdata->atomic_req, dispdata->crtc, "OUT_FENCE_PTR",
  393. VOID2U64(&dispdata->kms_out_fence_fd));
  394. add_plane_property(dispdata->atomic_req, plane, "IN_FENCE_FD", dispdata->kms_in_fence_fd);
  395. }
  396. }
  397. int drm_atomic_commit(_THIS, SDL_bool blocking)
  398. {
  399. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  400. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  401. int ret;
  402. if (!blocking)
  403. dispdata->atomic_flags |= DRM_MODE_ATOMIC_NONBLOCK;
  404. /* Never issue a new atomic commit if previous has not yet completed, or it will error. */
  405. drm_atomic_waitpending(_this);
  406. ret = KMSDRM_drmModeAtomicCommit(viddata->drm_fd, dispdata->atomic_req, dispdata->atomic_flags, NULL);
  407. if (ret) {
  408. //SDL_SetError("Atomic commit failed, returned %d.", ret);
  409. printf("ATOMIC COMMIT FAILED: %d.\n", ret);
  410. goto out;
  411. }
  412. if (dispdata->kms_in_fence_fd != -1) {
  413. close(dispdata->kms_in_fence_fd);
  414. dispdata->kms_in_fence_fd = -1;
  415. }
  416. out:
  417. KMSDRM_drmModeAtomicFree(dispdata->atomic_req);
  418. dispdata->atomic_req = NULL;
  419. dispdata->atomic_flags = 0;
  420. return ret;
  421. }
  422. void
  423. drm_atomic_waitpending(_THIS)
  424. {
  425. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  426. /* Will return immediately if we have already destroyed the fence, because we NULL-ify it just after.
  427. Also, will return immediately in double-buffer mode, because kms_fence will alsawys be NULL. */
  428. if (dispdata->kms_fence) {
  429. EGLint status;
  430. do {
  431. status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display,
  432. dispdata->kms_fence, 0, EGL_FOREVER_KHR);
  433. } while (status != EGL_CONDITION_SATISFIED_KHR);
  434. _this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence);
  435. dispdata->kms_fence = NULL;
  436. }
  437. }
  438. /***************************************/
  439. /* End of Atomic helper functions block*/
  440. /***************************************/
  441. static int
  442. KMSDRM_Available(void)
  443. {
  444. int ret = -ENOENT;
  445. ret = get_driindex();
  446. if (ret >= 0)
  447. return 1;
  448. return ret;
  449. }
  450. static void
  451. KMSDRM_DeleteDevice(SDL_VideoDevice * device)
  452. {
  453. if (device->driverdata) {
  454. SDL_free(device->driverdata);
  455. device->driverdata = NULL;
  456. }
  457. SDL_free(device);
  458. SDL_KMSDRM_UnloadSymbols();
  459. }
  460. static SDL_VideoDevice *
  461. KMSDRM_CreateDevice(int devindex)
  462. {
  463. SDL_VideoDevice *device;
  464. SDL_VideoData *viddata;
  465. if (!KMSDRM_Available()) {
  466. return NULL;
  467. }
  468. if (!devindex || (devindex > 99)) {
  469. devindex = get_driindex();
  470. }
  471. if (devindex < 0) {
  472. SDL_SetError("devindex (%d) must be between 0 and 99.", devindex);
  473. return NULL;
  474. }
  475. if (!SDL_KMSDRM_LoadSymbols()) {
  476. return NULL;
  477. }
  478. device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
  479. if (!device) {
  480. SDL_OutOfMemory();
  481. return NULL;
  482. }
  483. viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
  484. if (!viddata) {
  485. SDL_OutOfMemory();
  486. goto cleanup;
  487. }
  488. viddata->devindex = devindex;
  489. viddata->drm_fd = -1;
  490. device->driverdata = viddata;
  491. /* Setup all functions that can be handled from this backend. */
  492. device->VideoInit = KMSDRM_VideoInit;
  493. device->VideoQuit = KMSDRM_VideoQuit;
  494. device->GetDisplayModes = KMSDRM_GetDisplayModes;
  495. device->SetDisplayMode = KMSDRM_SetDisplayMode;
  496. device->CreateSDLWindow = KMSDRM_CreateWindow;
  497. device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom;
  498. device->SetWindowTitle = KMSDRM_SetWindowTitle;
  499. device->SetWindowIcon = KMSDRM_SetWindowIcon;
  500. device->SetWindowPosition = KMSDRM_SetWindowPosition;
  501. device->SetWindowSize = KMSDRM_SetWindowSize;
  502. device->ShowWindow = KMSDRM_ShowWindow;
  503. device->HideWindow = KMSDRM_HideWindow;
  504. device->RaiseWindow = KMSDRM_RaiseWindow;
  505. device->MaximizeWindow = KMSDRM_MaximizeWindow;
  506. device->MinimizeWindow = KMSDRM_MinimizeWindow;
  507. device->RestoreWindow = KMSDRM_RestoreWindow;
  508. device->SetWindowGrab = KMSDRM_SetWindowGrab;
  509. device->DestroyWindow = KMSDRM_DestroyWindow;
  510. device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
  511. #if SDL_VIDEO_OPENGL_EGL
  512. device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
  513. device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
  514. device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
  515. device->GL_CreateContext = KMSDRM_GLES_CreateContext;
  516. device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
  517. device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
  518. device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
  519. if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE))
  520. device->GL_SwapWindow = KMSDRM_GLES_SwapWindowDB;
  521. else
  522. device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
  523. device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
  524. #endif
  525. device->PumpEvents = KMSDRM_PumpEvents;
  526. device->free = KMSDRM_DeleteDevice;
  527. return device;
  528. cleanup:
  529. if (device)
  530. SDL_free(device);
  531. if (viddata)
  532. SDL_free(viddata);
  533. return NULL;
  534. }
  535. VideoBootStrap KMSDRM_bootstrap = {
  536. "KMSDRM",
  537. "KMS/DRM Video Driver",
  538. KMSDRM_CreateDevice
  539. };
  540. static void
  541. KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
  542. {
  543. KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
  544. if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
  545. KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
  546. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
  547. }
  548. SDL_free(fb_info);
  549. }
  550. KMSDRM_FBInfo *
  551. KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
  552. {
  553. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  554. unsigned width, height;
  555. uint32_t format, strides[4] = {0}, handles[4] = {0}, offsets[4] = {0};
  556. const int num_planes = KMSDRM_gbm_bo_get_plane_count(bo);
  557. int ret;
  558. /* Check for an existing framebuffer */
  559. KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
  560. if (fb_info) {
  561. return fb_info;
  562. }
  563. /* Create a structure that contains the info about framebuffer
  564. that we need to use it. */
  565. fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
  566. if (!fb_info) {
  567. SDL_OutOfMemory();
  568. return NULL;
  569. }
  570. fb_info->drm_fd = viddata->drm_fd;
  571. width = KMSDRM_gbm_bo_get_width(bo);
  572. height = KMSDRM_gbm_bo_get_height(bo);
  573. format = KMSDRM_gbm_bo_get_format(bo);
  574. for (int i = 0; i < num_planes; i++) {
  575. strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i);
  576. handles[i] = KMSDRM_gbm_bo_get_handle(bo).u32;
  577. offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i);
  578. }
  579. /* Create framebuffer object for the buffer.
  580. It's VERY important to note that fb_id is what we ise to set the FB_ID prop of a plane
  581. when using the ATOMIC interface, and we get fb_id it here. */
  582. ret = KMSDRM_drmModeAddFB2(viddata->drm_fd, width, height, format,
  583. handles, strides, offsets, &fb_info->fb_id, 0);
  584. if (ret) {
  585. SDL_free(fb_info);
  586. return NULL;
  587. }
  588. /* Set the userdata pointer. This pointer is used to store custom data that we need
  589. to access in the future, so we store the fb_id here for later use, because fb_id is
  590. what we need to set the FB_ID property of a plane when using the ATOMIC interface. */
  591. KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
  592. return fb_info;
  593. }
  594. /*****************************************************************************/
  595. /* SDL Video and Display initialization/handling functions */
  596. /* _this is a SDL_VideoDevice * */
  597. /*****************************************************************************/
  598. static void
  599. KMSDRM_DestroySurfaces(_THIS, SDL_Window * window)
  600. {
  601. SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
  602. SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  603. /* CAUTION: Before destroying the GBM ane EGL surfaces, we must disconnect
  604. the display plane from the GBM surface buffer it's reading by setting
  605. it's CRTC_ID and FB_ID props to 0.
  606. */
  607. drm_atomic_setbuffer(_this, dispdata->display_plane, 0, 0);
  608. drm_atomic_commit(_this, SDL_TRUE);
  609. if (windata->bo) {
  610. KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
  611. windata->bo = NULL;
  612. }
  613. if (windata->next_bo) {
  614. KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo);
  615. windata->next_bo = NULL;
  616. }
  617. #if SDL_VIDEO_OPENGL_EGL
  618. SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  619. if (windata->egl_surface != EGL_NO_SURFACE) {
  620. SDL_EGL_DestroySurface(_this, windata->egl_surface);
  621. windata->egl_surface = EGL_NO_SURFACE;
  622. }
  623. #endif
  624. if (windata->gs) {
  625. KMSDRM_gbm_surface_destroy(windata->gs);
  626. windata->gs = NULL;
  627. }
  628. }
  629. int
  630. KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
  631. {
  632. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  633. SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
  634. SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  635. Uint32 width = dispdata->mode.hdisplay;
  636. Uint32 height = dispdata->mode.vdisplay;
  637. Uint32 surface_fmt = GBM_FORMAT_ARGB8888;
  638. Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
  639. #if SDL_VIDEO_OPENGL_EGL
  640. EGLContext egl_context;
  641. #endif
  642. /* Always try to destroy previous surfaces before creating new ones. */
  643. KMSDRM_DestroySurfaces(_this, window);
  644. if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) {
  645. SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
  646. }
  647. #if SDL_VIDEO_OPENGL_EGL
  648. SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
  649. egl_context = (EGLContext)SDL_GL_GetCurrentContext();
  650. #endif
  651. windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags);
  652. if (!windata->gs) {
  653. return SDL_SetError("Could not create GBM surface");
  654. }
  655. #if SDL_VIDEO_OPENGL_EGL
  656. windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
  657. if (windata->egl_surface == EGL_NO_SURFACE) {
  658. return SDL_SetError("Could not create EGL window surface");
  659. }
  660. SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
  661. #endif
  662. return 0;
  663. }
  664. int
  665. KMSDRM_VideoInit(_THIS)
  666. {
  667. int ret = 0;
  668. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  669. SDL_DisplayData *dispdata = NULL;
  670. drmModeRes *resources = NULL;
  671. drmModeEncoder *encoder = NULL;
  672. char devname[32];
  673. SDL_VideoDisplay display = {0};
  674. dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
  675. dispdata->display_plane = calloc(1, sizeof(*dispdata->display_plane));
  676. dispdata->crtc = calloc(1, sizeof(*dispdata->crtc));
  677. dispdata->connector = calloc(1, sizeof(*dispdata->connector));
  678. dispdata->atomic_flags = 0;
  679. dispdata->atomic_req = NULL;
  680. dispdata->kms_fence = NULL;
  681. dispdata->gpu_fence = NULL;
  682. dispdata->kms_out_fence_fd = -1;
  683. dispdata->kms_in_fence_fd = -1;
  684. if (!dispdata) {
  685. return SDL_OutOfMemory();
  686. }
  687. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
  688. /* Open /dev/dri/cardNN */
  689. SDL_snprintf(devname, sizeof(devname), "/dev/dri/card%d", viddata->devindex);
  690. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname);
  691. viddata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
  692. if (viddata->drm_fd < 0) {
  693. ret = SDL_SetError("Could not open %s", devname);
  694. goto cleanup;
  695. }
  696. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
  697. viddata->gbm_dev = KMSDRM_gbm_create_device(viddata->drm_fd);
  698. if (!viddata->gbm_dev) {
  699. ret = SDL_SetError("Couldn't create gbm device.");
  700. goto cleanup;
  701. }
  702. /* Get all of the available connectors / devices / crtcs */
  703. resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
  704. if (!resources) {
  705. ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
  706. goto cleanup;
  707. }
  708. /* Iterate on the available connectors to find a connected connector. */
  709. for (int i = 0; i < resources->count_connectors; i++) {
  710. drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]);
  711. if (!conn) {
  712. continue;
  713. }
  714. if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
  715. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
  716. conn->connector_id, conn->count_modes);
  717. dispdata->connector->connector = conn;
  718. break;
  719. }
  720. KMSDRM_drmModeFreeConnector(conn);
  721. }
  722. if (!dispdata->connector->connector) {
  723. ret = SDL_SetError("No currently active connector found.");
  724. goto cleanup;
  725. }
  726. /* Try to find the connector's current encoder */
  727. for (int i = 0; i < resources->count_encoders; i++) {
  728. encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
  729. if (!encoder) {
  730. continue;
  731. }
  732. if (encoder->encoder_id == dispdata->connector->connector->encoder_id) {
  733. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
  734. break;
  735. }
  736. KMSDRM_drmModeFreeEncoder(encoder);
  737. encoder = NULL;
  738. }
  739. if (!encoder) {
  740. /* No encoder was connected, find the first supported one */
  741. for (int i = 0, j; i < resources->count_encoders; i++) {
  742. encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
  743. if (!encoder) {
  744. continue;
  745. }
  746. for (j = 0; j < dispdata->connector->connector->count_encoders; j++) {
  747. if (dispdata->connector->connector->encoders[j] == encoder->encoder_id) {
  748. break;
  749. }
  750. }
  751. if (j != dispdata->connector->connector->count_encoders) {
  752. break;
  753. }
  754. KMSDRM_drmModeFreeEncoder(encoder);
  755. encoder = NULL;
  756. }
  757. }
  758. if (!encoder) {
  759. ret = SDL_SetError("No connected encoder found.");
  760. goto cleanup;
  761. }
  762. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
  763. /* Try to find a CRTC connected to this encoder */
  764. dispdata->crtc->crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
  765. /* If no CRTC was connected to the encoder, find the first CRTC that is supported by the encoder, and use that. */
  766. if (!dispdata->crtc->crtc) {
  767. for (int i = 0; i < resources->count_crtcs; i++) {
  768. if (encoder->possible_crtcs & (1 << i)) {
  769. encoder->crtc_id = resources->crtcs[i];
  770. dispdata->crtc->crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
  771. break;
  772. }
  773. }
  774. }
  775. if (!dispdata->crtc->crtc) {
  776. ret = SDL_SetError("No CRTC found.");
  777. goto cleanup;
  778. }
  779. /* Figure out the default mode to be set. If the current CRTC's mode isn't
  780. valid, select the first mode supported by the connector
  781. FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */
  782. dispdata->mode = dispdata->crtc->crtc->mode;
  783. if (dispdata->crtc->crtc->mode_valid == 0) {
  784. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
  785. "Current mode is invalid, selecting connector's mode #0.");
  786. dispdata->mode = dispdata->connector->connector->modes[0];
  787. }
  788. /* Setup the single display that's available */
  789. display.desktop_mode.w = dispdata->mode.hdisplay;
  790. display.desktop_mode.h = dispdata->mode.vdisplay;
  791. display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
  792. #if 1
  793. display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
  794. #else
  795. /* FIXME */
  796. drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->crtc->buffer_id);
  797. display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
  798. drmModeFreeFB(fb);
  799. #endif
  800. display.current_mode = display.desktop_mode;
  801. display.driverdata = dispdata;
  802. SDL_AddVideoDisplay(&display);
  803. /****************/
  804. /* Atomic block */
  805. /****************/
  806. ret = KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
  807. if (ret) {
  808. ret = SDL_SetError("no atomic modesetting support.");
  809. goto cleanup;
  810. }
  811. ret = KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  812. if (ret) {
  813. ret = SDL_SetError("no universal planes support.");
  814. goto cleanup;
  815. }
  816. /* Use this if you ever need to see info on all available planes. */
  817. #if 0
  818. get_planes_info(_this);
  819. #endif
  820. /* Setup display plane */
  821. ret = setup_plane(_this, &(dispdata->display_plane), DRM_PLANE_TYPE_PRIMARY);
  822. if (ret) {
  823. ret = SDL_SetError("can't find suitable display plane.");
  824. goto cleanup;
  825. }
  826. /* Get CRTC properties */
  827. dispdata->crtc->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
  828. dispdata->crtc->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
  829. dispdata->crtc->props_info = SDL_calloc(dispdata->crtc->props->count_props,
  830. sizeof(dispdata->crtc->props_info));
  831. for (int i = 0; i < dispdata->crtc->props->count_props; i++) {
  832. dispdata->crtc->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
  833. dispdata->crtc->props->props[i]);
  834. }
  835. /* Get connector properties */
  836. dispdata->connector->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
  837. dispdata->connector->connector->connector_id, DRM_MODE_OBJECT_CONNECTOR);
  838. dispdata->connector->props_info = SDL_calloc(dispdata->connector->props->count_props,
  839. sizeof(dispdata->connector->props_info));
  840. for (int i = 0; i < dispdata->connector->props->count_props; i++) {
  841. dispdata->connector->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
  842. dispdata->connector->props->props[i]);
  843. }
  844. /*********************/
  845. /* Atomic block ends */
  846. /*********************/
  847. #ifdef SDL_INPUT_LINUXEV
  848. SDL_EVDEV_Init();
  849. #endif
  850. KMSDRM_InitMouse(_this);
  851. cleanup:
  852. if (encoder)
  853. KMSDRM_drmModeFreeEncoder(encoder);
  854. if (resources)
  855. KMSDRM_drmModeFreeResources(resources);
  856. if (ret != 0) {
  857. /* Error (complete) cleanup */
  858. if (dispdata->connector->connector) {
  859. KMSDRM_drmModeFreeConnector(dispdata->connector->connector);
  860. dispdata->connector = NULL;
  861. }
  862. if (dispdata->crtc->crtc) {
  863. KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc);
  864. dispdata->crtc = NULL;
  865. }
  866. if (viddata->gbm_dev) {
  867. KMSDRM_gbm_device_destroy(viddata->gbm_dev);
  868. viddata->gbm_dev = NULL;
  869. }
  870. if (viddata->drm_fd >= 0) {
  871. close(viddata->drm_fd);
  872. viddata->drm_fd = -1;
  873. }
  874. SDL_free(dispdata);
  875. }
  876. return ret;
  877. }
  878. /* The driverdata pointers, like dispdata, viddata, etc...
  879. are freed by SDL internals, so not our job. */
  880. void
  881. KMSDRM_VideoQuit(_THIS)
  882. {
  883. SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
  884. SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
  885. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
  886. /* Clear out the window list */
  887. SDL_free(viddata->windows);
  888. viddata->windows = NULL;
  889. viddata->max_windows = 0;
  890. viddata->num_windows = 0;
  891. if (_this->gl_config.driver_loaded) {
  892. SDL_GL_UnloadLibrary();
  893. }
  894. /* Free connector */
  895. if (dispdata && dispdata->connector) {
  896. if (dispdata->connector->connector) {
  897. KMSDRM_drmModeFreeConnector(dispdata->connector->connector);
  898. dispdata->connector->connector = NULL;
  899. }
  900. if (dispdata->connector->props_info) {
  901. SDL_free(dispdata->connector->props_info);
  902. dispdata->connector->props_info = NULL;
  903. }
  904. SDL_free(dispdata->connector);
  905. dispdata->connector = NULL;
  906. }
  907. /* Free CRTC */
  908. if (dispdata && dispdata->crtc) {
  909. if (dispdata->crtc->crtc) {
  910. KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc);
  911. dispdata->crtc->crtc = NULL;
  912. }
  913. if (dispdata->crtc->props_info) {
  914. SDL_free(dispdata->crtc->props_info);
  915. dispdata->crtc->props_info = NULL;
  916. }
  917. SDL_free(dispdata->crtc);
  918. dispdata->crtc = NULL;
  919. }
  920. /* Free display plane */
  921. free_plane(&dispdata->display_plane);
  922. /* Free cursor plane (if still not freed) */
  923. free_plane(&dispdata->cursor_plane);
  924. /* Destroy GBM device. GBM surface is destroyed by DestroySurfaces(). */
  925. if (viddata->gbm_dev) {
  926. KMSDRM_gbm_device_destroy(viddata->gbm_dev);
  927. viddata->gbm_dev = NULL;
  928. }
  929. if (viddata->drm_fd >= 0) {
  930. close(viddata->drm_fd);
  931. SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", viddata->drm_fd);
  932. viddata->drm_fd = -1;
  933. }
  934. #ifdef SDL_INPUT_LINUXEV
  935. SDL_EVDEV_Quit();
  936. #endif
  937. }
  938. void
  939. KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
  940. {
  941. /* Only one display mode available: the current one */
  942. SDL_AddDisplayMode(display, &display->current_mode);
  943. }
  944. int
  945. KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
  946. {
  947. return 0;
  948. }
  949. int
  950. KMSDRM_CreateWindow(_THIS, SDL_Window * window)
  951. {
  952. SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
  953. SDL_VideoDisplay *display = NULL;
  954. SDL_WindowData *windata = NULL;
  955. #if SDL_VIDEO_OPENGL_EGL
  956. if (!_this->egl_data) {
  957. if (SDL_GL_LoadLibrary(NULL) < 0) {
  958. goto error;
  959. }
  960. }
  961. #endif
  962. /* Allocate window internal data */
  963. windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
  964. display = SDL_GetDisplayForWindow(window);
  965. /* Windows have one size for now */
  966. window->w = display->desktop_mode.w;
  967. window->h = display->desktop_mode.h;
  968. /* Don't force fullscreen on all windows: it confuses programs that try
  969. to set a window fullscreen after creating it as non-fullscreen (sm64ex) */
  970. // window->flags |= SDL_WINDOW_FULLSCREEN;
  971. /* Setup driver data for this window */
  972. windata->viddata = viddata;
  973. window->driverdata = windata;
  974. if (KMSDRM_CreateSurfaces(_this, window)) {
  975. goto error;
  976. }
  977. /* Add window to the internal list of tracked windows. Note, while it may
  978. seem odd to support multiple fullscreen windows, some apps create an
  979. extra window as a dummy surface when working with multiple contexts */
  980. if (viddata->num_windows >= viddata->max_windows) {
  981. int new_max_windows = viddata->max_windows + 1;
  982. viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows,
  983. new_max_windows * sizeof(SDL_Window *));
  984. viddata->max_windows = new_max_windows;
  985. if (!viddata->windows) {
  986. SDL_OutOfMemory();
  987. goto error;
  988. }
  989. }
  990. viddata->windows[viddata->num_windows++] = window;
  991. /* Focus on the newly created window */
  992. SDL_SetMouseFocus(window);
  993. SDL_SetKeyboardFocus(window);
  994. return 0;
  995. error:
  996. KMSDRM_DestroyWindow(_this, window);
  997. return -1;
  998. }
  999. void
  1000. KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
  1001. {
  1002. SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1003. SDL_VideoData *viddata;
  1004. if (!windata) {
  1005. return;
  1006. }
  1007. /* Remove from the internal window list */
  1008. viddata = windata->viddata;
  1009. for (int i = 0; i < viddata->num_windows; i++) {
  1010. if (viddata->windows[i] == window) {
  1011. viddata->num_windows--;
  1012. for (int j = i; j < viddata->num_windows; j++) {
  1013. viddata->windows[j] = viddata->windows[j + 1];
  1014. }
  1015. break;
  1016. }
  1017. }
  1018. KMSDRM_DestroySurfaces(_this, window);
  1019. window->driverdata = NULL;
  1020. SDL_free(windata);
  1021. }
  1022. int
  1023. KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
  1024. {
  1025. return -1;
  1026. }
  1027. void
  1028. KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
  1029. {
  1030. }
  1031. void
  1032. KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
  1033. {
  1034. }
  1035. void
  1036. KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
  1037. {
  1038. }
  1039. void
  1040. KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
  1041. {
  1042. }
  1043. void
  1044. KMSDRM_ShowWindow(_THIS, SDL_Window * window)
  1045. {
  1046. }
  1047. void
  1048. KMSDRM_HideWindow(_THIS, SDL_Window * window)
  1049. {
  1050. }
  1051. void
  1052. KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
  1053. {
  1054. }
  1055. void
  1056. KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
  1057. {
  1058. }
  1059. void
  1060. KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
  1061. {
  1062. }
  1063. void
  1064. KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
  1065. {
  1066. }
  1067. void
  1068. KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1069. {
  1070. }
  1071. /*****************************************************************************/
  1072. /* SDL Window Manager function */
  1073. /*****************************************************************************/
  1074. SDL_bool
  1075. KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
  1076. {
  1077. if (info->version.major <= SDL_MAJOR_VERSION) {
  1078. return SDL_TRUE;
  1079. } else {
  1080. SDL_SetError("application not compiled with SDL %d.%d\n",
  1081. SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1082. return SDL_FALSE;
  1083. }
  1084. /* Failed to get window manager information */
  1085. return SDL_FALSE;
  1086. }
  1087. #endif /* SDL_VIDEO_DRIVER_KMSDRM */
  1088. /* vi: set ts=4 sw=4 expandtab: */