Clone of mesa.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. /*
  2. * Mesa 3-D graphics library
  3. * Version: 7.9
  4. *
  5. * Copyright (C) 2010 LunarG Inc.
  6. * Copyright (C) 2011 VMware Inc. All rights reserved.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included
  16. * in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * Authors:
  27. * Chia-I Wu <olv@lunarg.com>
  28. * Thomas Hellstrom <thellstrom@vmware.com>
  29. */
  30. #include "util/u_memory.h"
  31. #include "util/u_inlines.h"
  32. #include "egllog.h"
  33. #include "native_drm.h"
  34. static boolean
  35. drm_surface_validate(struct native_surface *nsurf, uint attachment_mask,
  36. unsigned int *seq_num, struct pipe_resource **textures,
  37. int *width, int *height)
  38. {
  39. struct drm_surface *drmsurf = drm_surface(nsurf);
  40. if (!resource_surface_add_resources(drmsurf->rsurf, attachment_mask))
  41. return FALSE;
  42. if (textures)
  43. resource_surface_get_resources(drmsurf->rsurf, textures, attachment_mask);
  44. if (seq_num)
  45. *seq_num = drmsurf->sequence_number;
  46. if (width)
  47. *width = drmsurf->width;
  48. if (height)
  49. *height = drmsurf->height;
  50. return TRUE;
  51. }
  52. /**
  53. * Add textures as DRM framebuffers.
  54. */
  55. static boolean
  56. drm_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back)
  57. {
  58. struct drm_surface *drmsurf = drm_surface(nsurf);
  59. struct drm_display *drmdpy = drmsurf->drmdpy;
  60. int num_framebuffers = (need_back) ? 2 : 1;
  61. int i, err;
  62. for (i = 0; i < num_framebuffers; i++) {
  63. struct drm_framebuffer *fb;
  64. enum native_attachment natt;
  65. struct winsys_handle whandle;
  66. uint block_bits;
  67. if (i == 0) {
  68. fb = &drmsurf->front_fb;
  69. natt = NATIVE_ATTACHMENT_FRONT_LEFT;
  70. }
  71. else {
  72. fb = &drmsurf->back_fb;
  73. natt = NATIVE_ATTACHMENT_BACK_LEFT;
  74. }
  75. if (!fb->texture) {
  76. /* make sure the texture has been allocated */
  77. resource_surface_add_resources(drmsurf->rsurf, 1 << natt);
  78. fb->texture =
  79. resource_surface_get_single_resource(drmsurf->rsurf, natt);
  80. if (!fb->texture)
  81. return FALSE;
  82. }
  83. /* already initialized */
  84. if (fb->buffer_id)
  85. continue;
  86. /* TODO detect the real value */
  87. fb->is_passive = TRUE;
  88. memset(&whandle, 0, sizeof(whandle));
  89. whandle.type = DRM_API_HANDLE_TYPE_KMS;
  90. if (!drmdpy->base.screen->resource_get_handle(drmdpy->base.screen,
  91. fb->texture, &whandle))
  92. return FALSE;
  93. block_bits = util_format_get_blocksizebits(drmsurf->color_format);
  94. err = drmModeAddFB(drmdpy->fd, drmsurf->width, drmsurf->height,
  95. block_bits, block_bits, whandle.stride, whandle.handle,
  96. &fb->buffer_id);
  97. if (err) {
  98. fb->buffer_id = 0;
  99. return FALSE;
  100. }
  101. }
  102. return TRUE;
  103. }
  104. static boolean
  105. drm_surface_flush_frontbuffer(struct native_surface *nsurf)
  106. {
  107. #ifdef DRM_MODE_FEATURE_DIRTYFB
  108. struct drm_surface *drmsurf = drm_surface(nsurf);
  109. struct drm_display *drmdpy = drmsurf->drmdpy;
  110. if (drmsurf->front_fb.is_passive)
  111. drmModeDirtyFB(drmdpy->fd, drmsurf->front_fb.buffer_id, NULL, 0);
  112. #endif
  113. return TRUE;
  114. }
  115. static boolean
  116. drm_surface_copy_swap(struct native_surface *nsurf)
  117. {
  118. struct drm_surface *drmsurf = drm_surface(nsurf);
  119. struct drm_display *drmdpy = drmsurf->drmdpy;
  120. (void) resource_surface_throttle(drmsurf->rsurf);
  121. if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base))
  122. return FALSE;
  123. (void) resource_surface_flush(drmsurf->rsurf, &drmdpy->base);
  124. if (!drm_surface_flush_frontbuffer(nsurf))
  125. return FALSE;
  126. drmsurf->sequence_number++;
  127. return TRUE;
  128. }
  129. static boolean
  130. drm_surface_swap_buffers(struct native_surface *nsurf)
  131. {
  132. struct drm_surface *drmsurf = drm_surface(nsurf);
  133. struct drm_crtc *drmcrtc = &drmsurf->current_crtc;
  134. struct drm_display *drmdpy = drmsurf->drmdpy;
  135. struct drm_framebuffer tmp_fb;
  136. int err;
  137. if (!drmsurf->have_pageflip)
  138. return drm_surface_copy_swap(nsurf);
  139. if (!drmsurf->back_fb.buffer_id) {
  140. if (!drm_surface_init_framebuffers(&drmsurf->base, TRUE))
  141. return FALSE;
  142. }
  143. if (drmsurf->is_shown && drmcrtc->crtc) {
  144. err = drmModePageFlip(drmdpy->fd, drmcrtc->crtc->crtc_id,
  145. drmsurf->back_fb.buffer_id, 0, NULL);
  146. if (err) {
  147. drmsurf->have_pageflip = FALSE;
  148. return drm_surface_copy_swap(nsurf);
  149. }
  150. }
  151. /* swap the buffers */
  152. tmp_fb = drmsurf->front_fb;
  153. drmsurf->front_fb = drmsurf->back_fb;
  154. drmsurf->back_fb = tmp_fb;
  155. resource_surface_swap_buffers(drmsurf->rsurf,
  156. NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
  157. /* the front/back textures are swapped */
  158. drmsurf->sequence_number++;
  159. drmdpy->event_handler->invalid_surface(&drmdpy->base,
  160. &drmsurf->base, drmsurf->sequence_number);
  161. return TRUE;
  162. }
  163. static boolean
  164. drm_surface_present(struct native_surface *nsurf,
  165. enum native_attachment natt,
  166. boolean preserve,
  167. uint swap_interval)
  168. {
  169. boolean ret;
  170. if (swap_interval)
  171. return FALSE;
  172. switch (natt) {
  173. case NATIVE_ATTACHMENT_FRONT_LEFT:
  174. ret = drm_surface_flush_frontbuffer(nsurf);
  175. break;
  176. case NATIVE_ATTACHMENT_BACK_LEFT:
  177. if (preserve)
  178. ret = drm_surface_copy_swap(nsurf);
  179. else
  180. ret = drm_surface_swap_buffers(nsurf);
  181. break;
  182. default:
  183. ret = FALSE;
  184. break;
  185. }
  186. return ret;
  187. }
  188. static void
  189. drm_surface_wait(struct native_surface *nsurf)
  190. {
  191. struct drm_surface *drmsurf = drm_surface(nsurf);
  192. resource_surface_wait(drmsurf->rsurf);
  193. }
  194. static void
  195. drm_surface_destroy(struct native_surface *nsurf)
  196. {
  197. struct drm_surface *drmsurf = drm_surface(nsurf);
  198. resource_surface_wait(drmsurf->rsurf);
  199. if (drmsurf->current_crtc.crtc)
  200. drmModeFreeCrtc(drmsurf->current_crtc.crtc);
  201. if (drmsurf->front_fb.buffer_id)
  202. drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->front_fb.buffer_id);
  203. pipe_resource_reference(&drmsurf->front_fb.texture, NULL);
  204. if (drmsurf->back_fb.buffer_id)
  205. drmModeRmFB(drmsurf->drmdpy->fd, drmsurf->back_fb.buffer_id);
  206. pipe_resource_reference(&drmsurf->back_fb.texture, NULL);
  207. resource_surface_destroy(drmsurf->rsurf);
  208. FREE(drmsurf);
  209. }
  210. static struct drm_surface *
  211. drm_display_create_surface(struct native_display *ndpy,
  212. const struct native_config *nconf,
  213. uint width, uint height)
  214. {
  215. struct drm_display *drmdpy = drm_display(ndpy);
  216. struct drm_config *drmconf = drm_config(nconf);
  217. struct drm_surface *drmsurf;
  218. drmsurf = CALLOC_STRUCT(drm_surface);
  219. if (!drmsurf)
  220. return NULL;
  221. drmsurf->drmdpy = drmdpy;
  222. drmsurf->color_format = drmconf->base.color_format;
  223. drmsurf->width = width;
  224. drmsurf->height = height;
  225. drmsurf->have_pageflip = TRUE;
  226. drmsurf->rsurf = resource_surface_create(drmdpy->base.screen,
  227. drmsurf->color_format,
  228. PIPE_BIND_RENDER_TARGET |
  229. PIPE_BIND_SAMPLER_VIEW |
  230. PIPE_BIND_DISPLAY_TARGET |
  231. PIPE_BIND_SCANOUT);
  232. if (!drmsurf->rsurf) {
  233. FREE(drmsurf);
  234. return NULL;
  235. }
  236. resource_surface_set_size(drmsurf->rsurf, drmsurf->width, drmsurf->height);
  237. drmsurf->base.destroy = drm_surface_destroy;
  238. drmsurf->base.present = drm_surface_present;
  239. drmsurf->base.validate = drm_surface_validate;
  240. drmsurf->base.wait = drm_surface_wait;
  241. return drmsurf;
  242. }
  243. /**
  244. * Choose a CRTC that supports all given connectors.
  245. */
  246. static uint32_t
  247. drm_display_choose_crtc(struct native_display *ndpy,
  248. uint32_t *connectors, int num_connectors)
  249. {
  250. struct drm_display *drmdpy = drm_display(ndpy);
  251. int idx;
  252. for (idx = 0; idx < drmdpy->resources->count_crtcs; idx++) {
  253. boolean found_crtc = TRUE;
  254. int i, j;
  255. for (i = 0; i < num_connectors; i++) {
  256. drmModeConnectorPtr connector;
  257. int encoder_idx = -1;
  258. connector = drmModeGetConnector(drmdpy->fd, connectors[i]);
  259. if (!connector) {
  260. found_crtc = FALSE;
  261. break;
  262. }
  263. /* find an encoder the CRTC supports */
  264. for (j = 0; j < connector->count_encoders; j++) {
  265. drmModeEncoderPtr encoder =
  266. drmModeGetEncoder(drmdpy->fd, connector->encoders[j]);
  267. if (encoder->possible_crtcs & (1 << idx)) {
  268. encoder_idx = j;
  269. break;
  270. }
  271. drmModeFreeEncoder(encoder);
  272. }
  273. drmModeFreeConnector(connector);
  274. if (encoder_idx < 0) {
  275. found_crtc = FALSE;
  276. break;
  277. }
  278. }
  279. if (found_crtc)
  280. break;
  281. }
  282. if (idx >= drmdpy->resources->count_crtcs) {
  283. _eglLog(_EGL_WARNING,
  284. "failed to find a CRTC that supports the given %d connectors",
  285. num_connectors);
  286. return 0;
  287. }
  288. return drmdpy->resources->crtcs[idx];
  289. }
  290. /**
  291. * Remember the original CRTC status and set the CRTC
  292. */
  293. static boolean
  294. drm_display_set_crtc(struct native_display *ndpy, int crtc_idx,
  295. uint32_t buffer_id, uint32_t x, uint32_t y,
  296. uint32_t *connectors, int num_connectors,
  297. drmModeModeInfoPtr mode)
  298. {
  299. struct drm_display *drmdpy = drm_display(ndpy);
  300. struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[crtc_idx];
  301. uint32_t crtc_id;
  302. int err;
  303. if (drmcrtc->crtc) {
  304. crtc_id = drmcrtc->crtc->crtc_id;
  305. }
  306. else {
  307. int count = 0, i;
  308. /*
  309. * Choose the CRTC once. It could be more dynamic, but let's keep it
  310. * simple for now.
  311. */
  312. crtc_id = drm_display_choose_crtc(&drmdpy->base,
  313. connectors, num_connectors);
  314. /* save the original CRTC status */
  315. drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id);
  316. if (!drmcrtc->crtc)
  317. return FALSE;
  318. for (i = 0; i < drmdpy->num_connectors; i++) {
  319. struct drm_connector *drmconn = &drmdpy->connectors[i];
  320. drmModeConnectorPtr connector = drmconn->connector;
  321. drmModeEncoderPtr encoder;
  322. encoder = drmModeGetEncoder(drmdpy->fd, connector->encoder_id);
  323. if (encoder) {
  324. if (encoder->crtc_id == crtc_id) {
  325. drmcrtc->connectors[count++] = connector->connector_id;
  326. if (count >= Elements(drmcrtc->connectors))
  327. break;
  328. }
  329. drmModeFreeEncoder(encoder);
  330. }
  331. }
  332. drmcrtc->num_connectors = count;
  333. }
  334. err = drmModeSetCrtc(drmdpy->fd, crtc_id, buffer_id, x, y,
  335. connectors, num_connectors, mode);
  336. if (err) {
  337. drmModeFreeCrtc(drmcrtc->crtc);
  338. drmcrtc->crtc = NULL;
  339. drmcrtc->num_connectors = 0;
  340. return FALSE;
  341. }
  342. return TRUE;
  343. }
  344. static boolean
  345. drm_display_program(struct native_display *ndpy, int crtc_idx,
  346. struct native_surface *nsurf, uint x, uint y,
  347. const struct native_connector **nconns, int num_nconns,
  348. const struct native_mode *nmode)
  349. {
  350. struct drm_display *drmdpy = drm_display(ndpy);
  351. struct drm_surface *drmsurf = drm_surface(nsurf);
  352. const struct drm_mode *drmmode = drm_mode(nmode);
  353. uint32_t connector_ids[32];
  354. uint32_t buffer_id;
  355. drmModeModeInfo mode_tmp, *mode;
  356. int i;
  357. if (num_nconns > Elements(connector_ids)) {
  358. _eglLog(_EGL_WARNING, "too many connectors (%d)", num_nconns);
  359. num_nconns = Elements(connector_ids);
  360. }
  361. if (drmsurf) {
  362. if (!drm_surface_init_framebuffers(&drmsurf->base, FALSE))
  363. return FALSE;
  364. buffer_id = drmsurf->front_fb.buffer_id;
  365. /* the mode argument of drmModeSetCrtc is not constified */
  366. mode_tmp = drmmode->mode;
  367. mode = &mode_tmp;
  368. }
  369. else {
  370. /* disable the CRTC */
  371. buffer_id = 0;
  372. mode = NULL;
  373. num_nconns = 0;
  374. }
  375. for (i = 0; i < num_nconns; i++) {
  376. struct drm_connector *drmconn = drm_connector(nconns[i]);
  377. connector_ids[i] = drmconn->connector->connector_id;
  378. }
  379. if (!drm_display_set_crtc(&drmdpy->base, crtc_idx, buffer_id, x, y,
  380. connector_ids, num_nconns, mode)) {
  381. _eglLog(_EGL_WARNING, "failed to set CRTC %d", crtc_idx);
  382. return FALSE;
  383. }
  384. if (drmdpy->shown_surfaces[crtc_idx])
  385. drmdpy->shown_surfaces[crtc_idx]->is_shown = FALSE;
  386. drmdpy->shown_surfaces[crtc_idx] = drmsurf;
  387. /* remember the settings for buffer swapping */
  388. if (drmsurf) {
  389. uint32_t crtc_id = drmdpy->saved_crtcs[crtc_idx].crtc->crtc_id;
  390. struct drm_crtc *drmcrtc = &drmsurf->current_crtc;
  391. if (drmcrtc->crtc)
  392. drmModeFreeCrtc(drmcrtc->crtc);
  393. drmcrtc->crtc = drmModeGetCrtc(drmdpy->fd, crtc_id);
  394. assert(num_nconns < Elements(drmcrtc->connectors));
  395. memcpy(drmcrtc->connectors, connector_ids,
  396. sizeof(*connector_ids) * num_nconns);
  397. drmcrtc->num_connectors = num_nconns;
  398. drmsurf->is_shown = TRUE;
  399. }
  400. return TRUE;
  401. }
  402. static const struct native_mode **
  403. drm_display_get_modes(struct native_display *ndpy,
  404. const struct native_connector *nconn,
  405. int *num_modes)
  406. {
  407. struct drm_display *drmdpy = drm_display(ndpy);
  408. struct drm_connector *drmconn = drm_connector(nconn);
  409. const struct native_mode **nmodes_return;
  410. int count, i;
  411. /* delete old data */
  412. if (drmconn->connector) {
  413. drmModeFreeConnector(drmconn->connector);
  414. FREE(drmconn->drm_modes);
  415. drmconn->connector = NULL;
  416. drmconn->drm_modes = NULL;
  417. drmconn->num_modes = 0;
  418. }
  419. /* detect again */
  420. drmconn->connector = drmModeGetConnector(drmdpy->fd, drmconn->connector_id);
  421. if (!drmconn->connector)
  422. return NULL;
  423. count = drmconn->connector->count_modes;
  424. drmconn->drm_modes = CALLOC(count, sizeof(*drmconn->drm_modes));
  425. if (!drmconn->drm_modes) {
  426. drmModeFreeConnector(drmconn->connector);
  427. drmconn->connector = NULL;
  428. return NULL;
  429. }
  430. for (i = 0; i < count; i++) {
  431. struct drm_mode *drmmode = &drmconn->drm_modes[i];
  432. drmModeModeInfoPtr mode = &drmconn->connector->modes[i];
  433. drmmode->mode = *mode;
  434. drmmode->base.desc = drmmode->mode.name;
  435. drmmode->base.width = drmmode->mode.hdisplay;
  436. drmmode->base.height = drmmode->mode.vdisplay;
  437. drmmode->base.refresh_rate = drmmode->mode.vrefresh;
  438. /* not all kernels have vrefresh = refresh_rate * 1000 */
  439. if (drmmode->base.refresh_rate < 1000)
  440. drmmode->base.refresh_rate *= 1000;
  441. }
  442. nmodes_return = MALLOC(count * sizeof(*nmodes_return));
  443. if (nmodes_return) {
  444. for (i = 0; i < count; i++)
  445. nmodes_return[i] = &drmconn->drm_modes[i].base;
  446. if (num_modes)
  447. *num_modes = count;
  448. }
  449. return nmodes_return;
  450. }
  451. static const struct native_connector **
  452. drm_display_get_connectors(struct native_display *ndpy, int *num_connectors,
  453. int *num_crtc)
  454. {
  455. struct drm_display *drmdpy = drm_display(ndpy);
  456. const struct native_connector **connectors;
  457. int i;
  458. if (!drmdpy->connectors) {
  459. drmdpy->connectors =
  460. CALLOC(drmdpy->resources->count_connectors, sizeof(*drmdpy->connectors));
  461. if (!drmdpy->connectors)
  462. return NULL;
  463. for (i = 0; i < drmdpy->resources->count_connectors; i++) {
  464. struct drm_connector *drmconn = &drmdpy->connectors[i];
  465. drmconn->connector_id = drmdpy->resources->connectors[i];
  466. /* drmconn->connector is allocated when the modes are asked */
  467. }
  468. drmdpy->num_connectors = drmdpy->resources->count_connectors;
  469. }
  470. connectors = MALLOC(drmdpy->num_connectors * sizeof(*connectors));
  471. if (connectors) {
  472. for (i = 0; i < drmdpy->num_connectors; i++)
  473. connectors[i] = &drmdpy->connectors[i].base;
  474. if (num_connectors)
  475. *num_connectors = drmdpy->num_connectors;
  476. }
  477. if (num_crtc)
  478. *num_crtc = drmdpy->resources->count_crtcs;
  479. return connectors;
  480. }
  481. static struct native_surface *
  482. drm_display_create_scanout_surface(struct native_display *ndpy,
  483. const struct native_config *nconf,
  484. uint width, uint height)
  485. {
  486. struct drm_surface *drmsurf;
  487. drmsurf = drm_display_create_surface(ndpy, nconf, width, height);
  488. return &drmsurf->base;
  489. }
  490. static struct native_display_modeset drm_display_modeset = {
  491. .get_connectors = drm_display_get_connectors,
  492. .get_modes = drm_display_get_modes,
  493. .create_scanout_surface = drm_display_create_scanout_surface,
  494. .program = drm_display_program
  495. };
  496. void
  497. drm_display_fini_modeset(struct native_display *ndpy)
  498. {
  499. struct drm_display *drmdpy = drm_display(ndpy);
  500. int i;
  501. if (drmdpy->connectors) {
  502. for (i = 0; i < drmdpy->num_connectors; i++) {
  503. struct drm_connector *drmconn = &drmdpy->connectors[i];
  504. if (drmconn->connector) {
  505. drmModeFreeConnector(drmconn->connector);
  506. FREE(drmconn->drm_modes);
  507. }
  508. }
  509. FREE(drmdpy->connectors);
  510. }
  511. if (drmdpy->shown_surfaces) {
  512. FREE(drmdpy->shown_surfaces);
  513. drmdpy->shown_surfaces = NULL;
  514. }
  515. if (drmdpy->saved_crtcs) {
  516. for (i = 0; i < drmdpy->resources->count_crtcs; i++) {
  517. struct drm_crtc *drmcrtc = &drmdpy->saved_crtcs[i];
  518. if (drmcrtc->crtc) {
  519. /* restore crtc */
  520. drmModeSetCrtc(drmdpy->fd, drmcrtc->crtc->crtc_id,
  521. drmcrtc->crtc->buffer_id, drmcrtc->crtc->x, drmcrtc->crtc->y,
  522. drmcrtc->connectors, drmcrtc->num_connectors,
  523. &drmcrtc->crtc->mode);
  524. drmModeFreeCrtc(drmcrtc->crtc);
  525. }
  526. }
  527. FREE(drmdpy->saved_crtcs);
  528. }
  529. if (drmdpy->resources) {
  530. drmModeFreeResources(drmdpy->resources);
  531. drmdpy->resources = NULL;
  532. }
  533. drmdpy->base.modeset = NULL;
  534. }
  535. boolean
  536. drm_display_init_modeset(struct native_display *ndpy)
  537. {
  538. struct drm_display *drmdpy = drm_display(ndpy);
  539. /* resources are fixed, unlike crtc, connector, or encoder */
  540. drmdpy->resources = drmModeGetResources(drmdpy->fd);
  541. if (!drmdpy->resources) {
  542. _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset.");
  543. return FALSE;
  544. }
  545. drmdpy->saved_crtcs =
  546. CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->saved_crtcs));
  547. if (!drmdpy->saved_crtcs) {
  548. drm_display_fini_modeset(&drmdpy->base);
  549. return FALSE;
  550. }
  551. drmdpy->shown_surfaces =
  552. CALLOC(drmdpy->resources->count_crtcs, sizeof(*drmdpy->shown_surfaces));
  553. if (!drmdpy->shown_surfaces) {
  554. drm_display_fini_modeset(&drmdpy->base);
  555. return FALSE;
  556. }
  557. drmdpy->base.modeset = &drm_display_modeset;
  558. return TRUE;
  559. }