0036-egl-add-null-platform.patch 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488
  1. From 7f4c353e7d2778fff8d728c1aed247900610b725 Mon Sep 17 00:00:00 2001
  2. From: Frank Binns <francisbinns@gmail.com>
  3. Date: Sun, 5 Jun 2016 12:04:40 +0100
  4. Subject: [PATCH] egl: add "null" platform
  5. ---
  6. meson.build | 25 +-
  7. meson_options.txt | 2 +-
  8. src/egl/drivers/dri2/egl_dri2.c | 11 +-
  9. src/egl/drivers/dri2/egl_dri2.h | 57 +-
  10. src/egl/drivers/dri2/platform_null.c | 1179 ++++++++++++++++++++++++++
  11. src/egl/main/eglapi.c | 5 +-
  12. src/egl/main/egldisplay.c | 1 +
  13. src/egl/main/egldisplay.h | 1 +
  14. src/egl/meson.build | 5 +
  15. 9 files changed, 1277 insertions(+), 9 deletions(-)
  16. create mode 100644 src/egl/drivers/dri2/platform_null.c
  17. diff --git a/meson.build b/meson.build
  18. index 3d9d345..2018562 100644
  19. --- a/meson.build
  20. +++ b/meson.build
  21. @@ -340,7 +340,7 @@ endif
  22. _platforms = get_option('platforms')
  23. if _platforms.contains('auto')
  24. if system_has_kms_drm
  25. - _platforms = ['x11', 'wayland']
  26. + _platforms = ['x11', 'wayland', 'null']
  27. elif ['darwin', 'cygwin'].contains(host_machine.system())
  28. _platforms = ['x11']
  29. elif ['haiku'].contains(host_machine.system())
  30. @@ -359,6 +359,7 @@ with_platform_wayland = _platforms.contains('wayland')
  31. with_platform_haiku = _platforms.contains('haiku')
  32. with_platform_windows = _platforms.contains('windows')
  33. with_platform_tizen = _platforms.contains('tizen')
  34. +with_platform_null = _platforms.contains('null')
  35. if with_platform_tizen and _platforms.length() != 1
  36. error('tizen cannot be enabled at the same time as other platforms')
  37. @@ -958,6 +959,26 @@ if with_platform_tizen
  38. ]
  39. pre_args += '-DHAVE_TIZEN_PLATFORM'
  40. endif
  41. +if with_platform_null
  42. + pre_args += '-DHAVE_NULL_PLATFORM'
  43. +endif
  44. +if with_platform_android
  45. + dep_android = [
  46. + dependency('cutils'),
  47. + dependency('hardware'),
  48. + dependency('sync'),
  49. + ]
  50. + if with_gallium
  51. + dep_android += dependency('backtrace')
  52. + endif
  53. + if get_option('platform-sdk-version') >= 26
  54. + dep_android += dependency('nativewindow')
  55. + endif
  56. + pre_args += '-DHAVE_ANDROID_PLATFORM'
  57. +endif
  58. +if with_platform_haiku
  59. + pre_args += '-DHAVE_HAIKU_PLATFORM'
  60. +endif
  61. prog_python = import('python').find_installation('python3')
  62. has_mako = run_command(
  63. @@ -1583,7 +1604,7 @@ dep_libdrm = dependency(
  64. 'libdrm', version : '>=' + _drm_ver,
  65. # GNU/Hurd includes egl_dri2, without drm.
  66. required : (with_dri2 and host_machine.system() != 'gnu') or with_dri3 or
  67. - with_platform_tizen
  68. + with_platform_tizen or with_platform_null
  69. )
  70. if dep_libdrm.found()
  71. pre_args += '-DHAVE_LIBDRM'
  72. diff --git a/meson_options.txt b/meson_options.txt
  73. index 8230db9..d90a25f 100644
  74. --- a/meson_options.txt
  75. +++ b/meson_options.txt
  76. @@ -23,7 +23,7 @@ option(
  77. type : 'array',
  78. value : ['auto'],
  79. choices : [
  80. - 'auto', 'x11', 'wayland', 'haiku', 'android', 'windows', 'tizen',
  81. + 'auto', 'x11', 'wayland', 'haiku', 'android', 'windows', 'tizen', 'null',
  82. ],
  83. description : 'window systems to support. If this is set to `auto`, all platforms applicable will be enabled.'
  84. )
  85. diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
  86. index d511d73..2f8414e 100644
  87. --- a/src/egl/drivers/dri2/egl_dri2.c
  88. +++ b/src/egl/drivers/dri2/egl_dri2.c
  89. @@ -1253,6 +1253,9 @@ dri2_initialize(_EGLDisplay *disp)
  90. case _EGL_PLATFORM_DEVICE:
  91. ret = dri2_initialize_device(disp);
  92. break;
  93. + case _EGL_PLATFORM_NULL:
  94. + ret = dri2_initialize_null(disp);
  95. + break;
  96. case _EGL_PLATFORM_X11:
  97. case _EGL_PLATFORM_XCB:
  98. ret = dri2_initialize_x11(disp);
  99. @@ -1318,8 +1321,6 @@ dri2_display_destroy(_EGLDisplay *disp)
  100. dri2_dpy->vtbl->close_screen_notify(disp);
  101. dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
  102. }
  103. - if (dri2_dpy->fd >= 0)
  104. - close(dri2_dpy->fd);
  105. /* Don't dlclose the driver when building with the address sanitizer, so you
  106. * get good symbols from the leak reports.
  107. @@ -1355,11 +1356,17 @@ dri2_display_destroy(_EGLDisplay *disp)
  108. tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy);
  109. break;
  110. #endif
  111. + case _EGL_PLATFORM_NULL:
  112. + dri2_teardown_null(dri2_dpy);
  113. + break;
  114. default:
  115. /* TODO: add teardown for other platforms */
  116. break;
  117. }
  118. + if (dri2_dpy->fd >= 0)
  119. + close(dri2_dpy->fd);
  120. +
  121. /* The drm platform does not create the screen/driver_configs but reuses
  122. * the ones from the gbm device. As such the gbm itself is responsible
  123. * for the cleanup.
  124. diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
  125. index f41f32c..eb2127e 100644
  126. --- a/src/egl/drivers/dri2/egl_dri2.h
  127. +++ b/src/egl/drivers/dri2/egl_dri2.h
  128. @@ -81,6 +81,10 @@ struct zwp_linux_dmabuf_v1;
  129. #include <tbm_surface_internal.h>
  130. #endif
  131. +#ifdef HAVE_NULL_PLATFORM
  132. +#include <xf86drmMode.h>
  133. +#endif
  134. +
  135. #include "eglconfig.h"
  136. #include "eglcontext.h"
  137. #include "egldevice.h"
  138. @@ -99,6 +103,22 @@ struct zwp_linux_dmabuf_v1;
  139. struct wl_buffer;
  140. +#ifdef HAVE_NULL_PLATFORM
  141. +struct display_output {
  142. + bool in_use;
  143. + uint32_t connector_id;
  144. + drmModePropertyRes **connector_prop_res;
  145. + uint32_t crtc_id;
  146. + drmModePropertyRes **crtc_prop_res;
  147. + uint32_t plane_id;
  148. + drmModePropertyRes **plane_prop_res;
  149. + drmModeModeInfo mode;
  150. + uint32_t mode_blob_id;
  151. + unsigned formats;
  152. + drmModeAtomicReq *atomic_state;
  153. +};
  154. +#endif
  155. +
  156. struct dri2_egl_display_vtbl {
  157. /* mandatory on Wayland, unused otherwise */
  158. int (*authenticate)(_EGLDisplay *disp, uint32_t id);
  159. @@ -257,6 +277,11 @@ struct dri2_egl_display
  160. char *device_name;
  161. #endif
  162. +#ifdef HAVE_NULL_PLATFORM
  163. + bool atomic_enabled;
  164. + struct display_output output;
  165. +#endif
  166. +
  167. #ifdef HAVE_ANDROID_PLATFORM
  168. const gralloc_module_t *gralloc;
  169. /* gralloc vendor usage bit for front rendering */
  170. @@ -332,7 +357,10 @@ struct dri2_egl_surface
  171. struct wl_display *wl_dpy_wrapper;
  172. struct wl_drm *wl_drm_wrapper;
  173. struct wl_callback *throttle_callback;
  174. - int format;
  175. +#endif
  176. +
  177. +#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_NULL_PLATFORM)
  178. + int format;
  179. #endif
  180. #ifdef HAVE_DRM_PLATFORM
  181. @@ -358,9 +386,10 @@ struct dri2_egl_surface
  182. __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT];
  183. #if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) || \
  184. - defined(HAVE_TIZEN_PLATFORM)
  185. + defined(HAVE_TIZEN_PLATFORM) || defined(HAVE_NULL_PLATFORM)
  186. struct {
  187. -#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_TIZEN_PLATFORM)
  188. +#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_TIZEN_PLATFORM) || \
  189. + defined(HAVE_NULL_PLATFORM)
  190. __DRIimage *dri_image;
  191. #endif
  192. #ifdef HAVE_WAYLAND_PLATFORM
  193. @@ -377,6 +406,9 @@ struct dri2_egl_surface
  194. #endif
  195. #ifdef HAVE_TIZEN_PLATFORM
  196. tbm_surface_h tbm_surf;
  197. +#endif
  198. +#ifdef HAVE_NULL_PLATFORM
  199. + uint32_t fb_id;
  200. #endif
  201. bool locked;
  202. int age;
  203. @@ -409,6 +441,10 @@ struct dri2_egl_surface
  204. void *swrast_front;
  205. #endif
  206. +#ifdef HAVE_NULL_PLATFORM
  207. + uint32_t front_fb_id;
  208. +#endif
  209. +
  210. int out_fence_fd;
  211. EGLBoolean enable_out_fence;
  212. @@ -589,6 +625,21 @@ EGLBoolean
  213. dri2_initialize_tizen(_EGLDisplay *disp);
  214. #endif
  215. +#ifdef HAVE_NULL_PLATFORM
  216. +EGLBoolean
  217. +dri2_initialize_null(_EGLDisplay *disp);
  218. +void
  219. +dri2_teardown_null(struct dri2_egl_display *dri2_dpy);
  220. +#else
  221. +static inline EGLBoolean
  222. +dri2_initialize_null(_EGLDisplay *disp)
  223. +{
  224. + return _eglError(EGL_NOT_INITIALIZED, "Null platform not built");
  225. +}
  226. +static inline void
  227. +dri2_teardown_null(struct dri2_egl_display *dri2_dpy) {}
  228. +#endif
  229. +
  230. EGLBoolean
  231. dri2_initialize_device(_EGLDisplay *disp);
  232. static inline void
  233. diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
  234. new file mode 100644
  235. index 0000000..fb03ecc
  236. --- /dev/null
  237. +++ b/src/egl/drivers/dri2/platform_null.c
  238. @@ -0,0 +1,1179 @@
  239. +/*
  240. + * Copyright (c) Imagination Technologies Ltd.
  241. + *
  242. + * Parts based on platform_wayland, which has:
  243. + *
  244. + * Copyright © 2011-2012 Intel Corporation
  245. + * Copyright © 2012 Collabora, Ltd.
  246. + *
  247. + * Permission is hereby granted, free of charge, to any person obtaining a
  248. + * copy of this software and associated documentation files (the "Software"),
  249. + * to deal in the Software without restriction, including without limitation
  250. + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  251. + * and/or sell copies of the Software, and to permit persons to whom the
  252. + * Software is furnished to do so, subject to the following conditions:
  253. + *
  254. + * The above copyright notice and this permission notice (including the next
  255. + * paragraph) shall be included in all copies or substantial portions of the
  256. + * Software.
  257. + *
  258. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  259. + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  260. + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  261. + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  262. + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  263. + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  264. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  265. + * DEALINGS IN THE SOFTWARE.
  266. + */
  267. +
  268. +#include <dlfcn.h>
  269. +#include <drm_fourcc.h>
  270. +#include <fcntl.h>
  271. +#include <poll.h>
  272. +#include <stdbool.h>
  273. +#include <stdint.h>
  274. +#include <stdlib.h>
  275. +#include <stdio.h>
  276. +#include <string.h>
  277. +#include <sys/types.h>
  278. +#include <sys/stat.h>
  279. +#include <unistd.h>
  280. +#include <xf86drm.h>
  281. +
  282. +#include "egl_dri2.h"
  283. +#include "loader.h"
  284. +
  285. +#define NULL_CARD_MINOR_MAX 63U
  286. +
  287. +/*
  288. + * Need at least version 4 for __DRI_IMAGE_ATTRIB_WIDTH and
  289. + * __DRI_IMAGE_ATTRIB_HEIGHT
  290. + */
  291. +#define NULL_IMAGE_EXTENSION_VERSION_MIN 4
  292. +
  293. +struct object_property {
  294. + uint32_t object_id;
  295. + uint32_t prop_id;
  296. + uint64_t prop_value;
  297. +};
  298. +
  299. +#define object_property_set_named(output, object_type, prop_name, value) \
  300. + { \
  301. + .object_id = (output)->object_type##_id, \
  302. + .prop_id = property_id_get_for_name((output)->object_type##_prop_res, \
  303. + prop_name), \
  304. + .prop_value = value, \
  305. + }
  306. +
  307. +/*
  308. + * The index of entries in this table is used as a bitmask in
  309. + * dri2_dpy->formats, which tracks the formats supported by the display.
  310. + */
  311. +static const struct dri2_null_format {
  312. + uint32_t drm_format;
  313. + int dri_image_format;
  314. + int rgba_shifts[4];
  315. + unsigned int rgba_sizes[4];
  316. +} dri2_null_formats[] = {
  317. + {
  318. + .drm_format = DRM_FORMAT_XRGB8888,
  319. + .dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888,
  320. + .rgba_shifts = { 16, 8, 0, -1 },
  321. + .rgba_sizes = { 8, 8, 8, 0 },
  322. + },
  323. + {
  324. + .drm_format = DRM_FORMAT_ARGB8888,
  325. + .dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888,
  326. + .rgba_shifts = { 16, 8, 0, 24 },
  327. + .rgba_sizes = { 8, 8, 8, 8 },
  328. + },
  329. + {
  330. + .drm_format = DRM_FORMAT_RGB565,
  331. + .dri_image_format = __DRI_IMAGE_FORMAT_RGB565,
  332. + .rgba_shifts = { 11, 5, 0, -1 },
  333. + .rgba_sizes = { 5, 6, 5, 0 },
  334. + },
  335. +};
  336. +
  337. +
  338. +static int
  339. +format_idx_get_from_config(struct dri2_egl_display *dri2_dpy,
  340. + const __DRIconfig *config)
  341. +{
  342. + int shifts[4];
  343. + unsigned int sizes[4];
  344. +
  345. + dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
  346. +
  347. + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++) {
  348. + const struct dri2_null_format *format = &dri2_null_formats[i];
  349. +
  350. + if (shifts[0] == format->rgba_shifts[0] &&
  351. + shifts[1] == format->rgba_shifts[1] &&
  352. + shifts[2] == format->rgba_shifts[2] &&
  353. + shifts[3] == format->rgba_shifts[3] &&
  354. + sizes[0] == format->rgba_sizes[0] &&
  355. + sizes[1] == format->rgba_sizes[1] &&
  356. + sizes[2] == format->rgba_sizes[2] &&
  357. + sizes[3] == format->rgba_sizes[3]) {
  358. + return i;
  359. + }
  360. + }
  361. +
  362. + return -1;
  363. +}
  364. +
  365. +static int
  366. +format_idx_get_from_dri_image_format(uint32_t dri_image_format)
  367. +{
  368. + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++)
  369. + if (dri2_null_formats[i].dri_image_format == dri_image_format)
  370. + return i;
  371. +
  372. + return -1;
  373. +}
  374. +
  375. +static int
  376. +format_idx_get_from_drm_format(uint32_t drm_format)
  377. +{
  378. + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++)
  379. + if (dri2_null_formats[i].drm_format == drm_format)
  380. + return i;
  381. +
  382. + return -1;
  383. +}
  384. +
  385. +static int
  386. +atomic_state_add_object_properties(drmModeAtomicReq *atomic_state,
  387. + const struct object_property *props,
  388. + const unsigned prop_count)
  389. +{
  390. + for (unsigned i = 0; i < prop_count; i++) {
  391. + int err;
  392. +
  393. + if (props[i].prop_id == 0)
  394. + return -EINVAL;
  395. +
  396. + err = drmModeAtomicAddProperty(atomic_state, props[i].object_id,
  397. + props[i].prop_id, props[i].prop_value);
  398. + if (err < 0)
  399. + return err;
  400. + }
  401. +
  402. + return 0;
  403. +}
  404. +
  405. +
  406. +static uint32_t
  407. +property_id_get_for_name(drmModePropertyRes **prop_res, const char *prop_name)
  408. +{
  409. + if (prop_res)
  410. + for (unsigned i = 0; prop_res[i]; i++)
  411. + if (!strcmp(prop_res[i]->name, prop_name))
  412. + return prop_res[i]->prop_id;
  413. +
  414. + return 0;
  415. +}
  416. +
  417. +static void
  418. +flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
  419. + unsigned int tv_usec, void *user_data)
  420. +{
  421. + bool *plocked = user_data;
  422. +
  423. + if (plocked)
  424. + *plocked = false;
  425. +}
  426. +
  427. +static bool
  428. +flip_process(int fd)
  429. +{
  430. + static drmEventContext evctx =
  431. + {.version = 2, .page_flip_handler = flip_handler};
  432. + struct pollfd pfd = {.fd = fd, .events = POLLIN};
  433. + int ret;
  434. +
  435. + do {
  436. + ret = poll(&pfd, 1, -1);
  437. + } while (ret > 0 && pfd.revents != pfd.events);
  438. +
  439. + if (ret <= 0)
  440. + return false;
  441. +
  442. + drmHandleEvent(fd, &evctx);
  443. +
  444. + return true;
  445. +}
  446. +
  447. +static drmModePropertyRes **
  448. +object_get_property_resources(int fd, uint32_t object_id, uint32_t object_type)
  449. +{
  450. + drmModeObjectProperties *props;
  451. + drmModePropertyRes **prop_res;
  452. +
  453. + props = drmModeObjectGetProperties(fd, object_id, object_type);
  454. + if (!props)
  455. + return NULL;
  456. +
  457. + prop_res = malloc((props->count_props + 1) * sizeof(*prop_res));
  458. + if (prop_res) {
  459. + prop_res[props->count_props] = NULL;
  460. +
  461. + for (unsigned i = 0; i < props->count_props; i++) {
  462. + prop_res[i] = drmModeGetProperty(fd, props->props[i]);
  463. + if (!prop_res[i]) {
  464. + while (i--) {
  465. + drmModeFreeProperty(prop_res[i]);
  466. + free(prop_res);
  467. + prop_res = NULL;
  468. + }
  469. + break;
  470. + }
  471. + }
  472. + }
  473. +
  474. + drmModeFreeObjectProperties(props);
  475. +
  476. + return prop_res;
  477. +}
  478. +
  479. +static void
  480. +object_free_property_resources(int fd, drmModePropertyRes **prop_res)
  481. +{
  482. + for (unsigned i = 0; prop_res[i]; i++)
  483. + drmModeFreeProperty(prop_res[i]);
  484. + free(prop_res);
  485. +}
  486. +
  487. +static bool
  488. +object_property_value_for_name(int fd, uint32_t object_id, uint32_t object_type,
  489. + const char *prop_name, uint64_t *value_out)
  490. +{
  491. + drmModeObjectProperties *plane_props;
  492. + bool found = false;
  493. +
  494. + plane_props = drmModeObjectGetProperties(fd, object_id, object_type);
  495. + if (!plane_props)
  496. + return false;
  497. +
  498. + for (unsigned i = 0; i < plane_props->count_props; i++) {
  499. + drmModePropertyRes *prop;
  500. +
  501. + prop = drmModeGetProperty(fd, plane_props->props[i]);
  502. + if (!prop)
  503. + continue;
  504. +
  505. + found = !strcmp(prop->name, prop_name);
  506. + drmModeFreeProperty(prop);
  507. + if (found) {
  508. + *value_out = plane_props->prop_values[i];
  509. + break;
  510. + }
  511. + }
  512. +
  513. + drmModeFreeObjectProperties(plane_props);
  514. +
  515. + return found;
  516. +}
  517. +
  518. +static int
  519. +connector_choose_mode(drmModeConnector *connector)
  520. +{
  521. + if (!connector->count_modes)
  522. + return -1;
  523. +
  524. + for (unsigned i = 0; i < connector->count_modes; i++) {
  525. + if (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)
  526. + continue;
  527. +
  528. + if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED)
  529. + return i;
  530. + }
  531. +
  532. + return 0;
  533. +}
  534. +
  535. +static drmModeConnector *
  536. +connector_get(int fd, drmModeRes *resources)
  537. +{
  538. + /* Find the first connected connector */
  539. + for (unsigned i = 0; i < resources->count_connectors; i++) {
  540. + drmModeConnector *connector;
  541. +
  542. + connector = drmModeGetConnector(fd, resources->connectors[i]);
  543. + if (!connector)
  544. + continue;
  545. +
  546. + if (connector->connection == DRM_MODE_CONNECTED)
  547. + return connector;
  548. +
  549. + drmModeFreeConnector(connector);
  550. + }
  551. +
  552. + return NULL;
  553. +}
  554. +
  555. +static drmModeCrtc *
  556. +crtc_get_for_connector(int fd, drmModeRes *resources,
  557. + drmModeConnector *connector)
  558. +{
  559. + for (unsigned i = 0; i < connector->count_encoders; i++) {
  560. + drmModeEncoder *encoder;
  561. +
  562. + encoder = drmModeGetEncoder(fd, connector->encoders[i]);
  563. + if (!encoder)
  564. + continue;
  565. +
  566. + for (unsigned j = 0; j < resources->count_crtcs; j++) {
  567. + if (encoder->possible_crtcs & (1 << j)) {
  568. + drmModeCrtc *crtc;
  569. +
  570. + crtc = drmModeGetCrtc(fd, resources->crtcs[j]);
  571. + if (crtc) {
  572. + drmModeFreeEncoder(encoder);
  573. + return crtc;
  574. + }
  575. + }
  576. + }
  577. +
  578. + drmModeFreeEncoder(encoder);
  579. + }
  580. +
  581. + return NULL;
  582. +}
  583. +
  584. +static drmModePlane *
  585. +primary_plane_get_for_crtc(int fd, drmModeRes *resources, drmModeCrtc *crtc)
  586. +{
  587. + drmModePlaneRes *plane_resources;
  588. + unsigned crtc_idx;
  589. +
  590. + plane_resources = drmModeGetPlaneResources(fd);
  591. + if (!plane_resources)
  592. + return NULL;
  593. +
  594. + for (crtc_idx = 0; crtc_idx < resources->count_crtcs; crtc_idx++)
  595. + if (resources->crtcs[crtc_idx] == crtc->crtc_id)
  596. + break;
  597. + assert(crtc_idx != resources->count_crtcs);
  598. +
  599. + for (unsigned i = 0; i < plane_resources->count_planes; i++) {
  600. + const uint32_t crtc_bit = 1 << crtc_idx;
  601. + drmModePlane *plane;
  602. +
  603. + plane = drmModeGetPlane(fd, plane_resources->planes[i]);
  604. + if (!plane)
  605. + continue;
  606. +
  607. + if (plane->possible_crtcs & crtc_bit) {
  608. + uint64_t type;
  609. + bool res;
  610. +
  611. + res = object_property_value_for_name(fd, plane->plane_id,
  612. + DRM_MODE_OBJECT_PLANE,
  613. + "type", &type);
  614. + if (res && type == DRM_PLANE_TYPE_PRIMARY) {
  615. + drmModeFreePlaneResources(plane_resources);
  616. + return plane;
  617. + }
  618. + }
  619. +
  620. + drmModeFreePlane(plane);
  621. + }
  622. +
  623. + drmModeFreePlaneResources(plane_resources);
  624. +
  625. + return NULL;
  626. +}
  627. +
  628. +static bool
  629. +display_output_atomic_init(int fd, struct display_output *output)
  630. +{
  631. + drmModePropertyRes **connector_prop_res;
  632. + drmModePropertyRes **crtc_prop_res;
  633. + drmModePropertyRes **plane_prop_res;
  634. + int err;
  635. +
  636. + connector_prop_res = object_get_property_resources(fd, output->connector_id,
  637. + DRM_MODE_OBJECT_CONNECTOR);
  638. + if (!connector_prop_res)
  639. + return false;
  640. +
  641. + crtc_prop_res = object_get_property_resources(fd, output->crtc_id,
  642. + DRM_MODE_OBJECT_CRTC);
  643. + if (!crtc_prop_res)
  644. + goto err_free_connector_prop_res;
  645. +
  646. + plane_prop_res = object_get_property_resources(fd, output->plane_id,
  647. + DRM_MODE_OBJECT_PLANE);
  648. + if (!plane_prop_res)
  649. + goto err_free_crtc_prop_res;
  650. +
  651. + err = drmModeCreatePropertyBlob(fd, &output->mode, sizeof(output->mode),
  652. + &output->mode_blob_id);
  653. + if (err)
  654. + goto err_free_plane_prop_res;
  655. +
  656. + output->atomic_state = drmModeAtomicAlloc();
  657. + if (!output->atomic_state)
  658. + goto err_destroy_mode_prop_blob;
  659. +
  660. + output->connector_prop_res = connector_prop_res;
  661. + output->crtc_prop_res = crtc_prop_res;
  662. + output->plane_prop_res = plane_prop_res;
  663. +
  664. + return true;
  665. +
  666. +err_destroy_mode_prop_blob:
  667. + drmModeDestroyPropertyBlob(fd, output->mode_blob_id);
  668. +err_free_plane_prop_res:
  669. + object_free_property_resources(fd, plane_prop_res);
  670. +err_free_crtc_prop_res:
  671. + object_free_property_resources(fd, crtc_prop_res);
  672. +err_free_connector_prop_res:
  673. + object_free_property_resources(fd, connector_prop_res);
  674. + return false;
  675. +}
  676. +
  677. +static int
  678. +display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id,
  679. + uint32_t flags, void *flip_data)
  680. +{
  681. + const struct object_property obj_props[] = {
  682. + object_property_set_named(output, plane, "FB_ID", fb_id),
  683. + };
  684. + int err;
  685. +
  686. + /* Reset atomic state */
  687. + drmModeAtomicSetCursor(output->atomic_state, 0);
  688. +
  689. + err = atomic_state_add_object_properties(output->atomic_state, obj_props,
  690. + ARRAY_SIZE(obj_props));
  691. + if (err)
  692. + return err;
  693. +
  694. + /*
  695. + * Don't block - like drmModePageFlip, drmModeAtomicCommit will return
  696. + * -EBUSY if the commit can't be queued in the kernel.
  697. + */
  698. + flags |= DRM_MODE_ATOMIC_NONBLOCK;
  699. +
  700. + return drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data);
  701. +}
  702. +
  703. +static int
  704. +display_output_atomic_modeset(int fd, struct display_output *output, uint32_t fb_id)
  705. +{
  706. + /* SRC_W and SRC_H in 16.16 fixed point */
  707. + const struct object_property obj_props[] = {
  708. + object_property_set_named(output, connector, "CRTC_ID", output->crtc_id),
  709. + object_property_set_named(output, crtc, "ACTIVE", 1),
  710. + object_property_set_named(output, crtc, "MODE_ID", output->mode_blob_id),
  711. + object_property_set_named(output, plane, "FB_ID", fb_id),
  712. + object_property_set_named(output, plane, "CRTC_ID", output->crtc_id),
  713. + object_property_set_named(output, plane, "CRTC_X", 0),
  714. + object_property_set_named(output, plane, "CRTC_Y", 0),
  715. + object_property_set_named(output, plane, "CRTC_W", output->mode.hdisplay),
  716. + object_property_set_named(output, plane, "CRTC_H", output->mode.vdisplay),
  717. + object_property_set_named(output, plane, "SRC_X", 0),
  718. + object_property_set_named(output, plane, "SRC_Y", 0),
  719. + object_property_set_named(output, plane, "SRC_W", output->mode.hdisplay << 16),
  720. + object_property_set_named(output, plane, "SRC_H", output->mode.vdisplay << 16),
  721. + };
  722. + int err;
  723. +
  724. + /* Reset atomic state */
  725. + drmModeAtomicSetCursor(output->atomic_state, 0);
  726. +
  727. + err = atomic_state_add_object_properties(output->atomic_state, obj_props,
  728. + ARRAY_SIZE(obj_props));
  729. + if (err)
  730. + return false;
  731. +
  732. + return drmModeAtomicCommit(fd, output->atomic_state,
  733. + DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  734. +}
  735. +
  736. +static bool
  737. +display_output_init(int fd, struct display_output *output, bool use_atomic)
  738. +{
  739. + drmModeRes *resources;
  740. + drmModeConnector *connector;
  741. + drmModeCrtc *crtc;
  742. + drmModePlane *plane;
  743. + unsigned mode_idx;
  744. +
  745. + resources = drmModeGetResources(fd);
  746. + if (!resources)
  747. + return false;
  748. +
  749. + connector = connector_get(fd, resources);
  750. + if (!connector)
  751. + goto err_free_resources;
  752. +
  753. + crtc = crtc_get_for_connector(fd, resources, connector);
  754. + if (!crtc)
  755. + goto err_free_connector;
  756. +
  757. + plane = primary_plane_get_for_crtc(fd, resources, crtc);
  758. + if (!plane)
  759. + goto err_free_crtc;
  760. +
  761. + mode_idx = connector_choose_mode(connector);
  762. + if (mode_idx < 0)
  763. + goto err_free_plane;
  764. + output->mode = connector->modes[mode_idx];
  765. +
  766. + /* Record the display supported formats */
  767. + for (unsigned i = 0; i < plane->count_formats; i++) {
  768. + int format_idx;
  769. +
  770. + format_idx = format_idx_get_from_drm_format(plane->formats[i]);
  771. + if (format_idx == -1)
  772. + continue;
  773. +
  774. + output->formats |= (1 << format_idx);
  775. + }
  776. + if (!output->formats)
  777. + goto err_free_plane;
  778. +
  779. + output->connector_id = connector->connector_id;
  780. + output->crtc_id = crtc->crtc_id;
  781. + output->plane_id = plane->plane_id;
  782. +
  783. + drmModeFreePlane(plane);
  784. + drmModeFreeCrtc(crtc);
  785. + drmModeFreeConnector(connector);
  786. + drmModeFreeResources(resources);
  787. +
  788. + if (use_atomic) {
  789. + if (!display_output_atomic_init(fd, output)) {
  790. + _eglLog(_EGL_DEBUG,
  791. + "failed to initialise atomic support (using legacy mode)");
  792. + }
  793. + }
  794. +
  795. + return true;
  796. +
  797. +err_free_plane:
  798. + drmModeFreePlane(plane);
  799. +err_free_crtc:
  800. + drmModeFreeCrtc(crtc);
  801. +err_free_connector:
  802. + drmModeFreeConnector(connector);
  803. +err_free_resources:
  804. + drmModeFreeResources(resources);
  805. + return false;
  806. +}
  807. +
  808. +static int
  809. +display_output_flip(int fd, struct display_output *output, uint32_t fb_id,
  810. + uint32_t flags, void *flip_data)
  811. +{
  812. + if (output->atomic_state)
  813. + return display_output_atomic_flip(fd, output, fb_id, flags, flip_data);
  814. +
  815. + return drmModePageFlip(fd, output->crtc_id, fb_id, flags, flip_data);
  816. +}
  817. +
  818. +static int
  819. +display_output_modeset(int fd, struct display_output *output, uint32_t fb_id)
  820. +{
  821. + if (output->atomic_state)
  822. + return display_output_atomic_modeset(fd, output, fb_id);
  823. +
  824. + return drmModeSetCrtc(fd, output->crtc_id, fb_id, 0, 0,
  825. + &output->connector_id, 1, &output->mode);
  826. +}
  827. +
  828. +static bool
  829. +add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image,
  830. + uint32_t *fb_id_out)
  831. +{
  832. + uint32_t handles[4] = {0};
  833. + uint32_t pitches[4] = {0};
  834. + uint32_t offsets[4] = {0};
  835. + int handle, stride, width, height, format;
  836. + int format_idx;
  837. +
  838. + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &handle);
  839. + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
  840. + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
  841. + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
  842. + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
  843. +
  844. + handles[0] = (uint32_t) handle;
  845. + pitches[0] = (uint32_t) stride;
  846. +
  847. + format_idx = format_idx_get_from_dri_image_format(format);
  848. + assert(format_idx != -1);
  849. +
  850. + return !drmModeAddFB2(dri2_dpy->fd, width, height,
  851. + dri2_null_formats[format_idx].drm_format,
  852. + handles, pitches, offsets, fb_id_out, 0);
  853. +}
  854. +
  855. +static bool
  856. +get_front_bo(struct dri2_egl_surface *dri2_surf)
  857. +{
  858. + struct dri2_egl_display *dri2_dpy =
  859. + dri2_egl_display(dri2_surf->base.Resource.Display);
  860. + unsigned int use = 0;
  861. +
  862. + if (dri2_surf->base.Type == EGL_WINDOW_BIT)
  863. + use |= __DRI_IMAGE_USE_SCANOUT;
  864. +
  865. + dri2_surf->front = dri2_dpy->image->createImage(dri2_dpy->dri_screen,
  866. + dri2_surf->base.Width,
  867. + dri2_surf->base.Height,
  868. + dri2_surf->format,
  869. + use,
  870. + NULL);
  871. + if (!dri2_surf->front)
  872. + return false;
  873. +
  874. + if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
  875. + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front,
  876. + &dri2_surf->front_fb_id)) {
  877. + dri2_dpy->image->destroyImage(dri2_surf->front);
  878. + dri2_surf->front = NULL;
  879. + return false;
  880. + }
  881. + }
  882. +
  883. + return true;
  884. +}
  885. +
  886. +static bool
  887. +get_back_bo(struct dri2_egl_surface *dri2_surf)
  888. +{
  889. + struct dri2_egl_display *dri2_dpy =
  890. + dri2_egl_display(dri2_surf->base.Resource.Display);
  891. +
  892. + if (!dri2_surf->back) {
  893. + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  894. + if (!dri2_surf->color_buffers[i].locked) {
  895. + dri2_surf->back = &dri2_surf->color_buffers[i];
  896. + break;
  897. + }
  898. + }
  899. + if (!dri2_surf->back)
  900. + return false;
  901. + }
  902. +
  903. + if (!dri2_surf->back->dri_image) {
  904. + dri2_surf->back->dri_image =
  905. + dri2_dpy->image->createImage(dri2_dpy->dri_screen,
  906. + dri2_surf->base.Width,
  907. + dri2_surf->base.Height,
  908. + dri2_surf->format,
  909. + __DRI_IMAGE_USE_SCANOUT,
  910. + NULL);
  911. + if (!dri2_surf->back->dri_image)
  912. + return false;
  913. + }
  914. +
  915. + if (!dri2_surf->back->fb_id) {
  916. + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->back->dri_image,
  917. + &dri2_surf->back->fb_id)) {
  918. + return false;
  919. + }
  920. + }
  921. +
  922. + dri2_surf->back->locked = 1;
  923. +
  924. + return true;
  925. +}
  926. +
  927. +static _EGLSurface *
  928. +create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
  929. + const EGLint *attrib_list)
  930. +{
  931. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  932. + struct dri2_egl_config *dri2_config = dri2_egl_config(config);
  933. + struct dri2_egl_surface *dri2_surf;
  934. + const __DRIconfig *dri_config;
  935. + _EGLSurface *surf;
  936. + int format_idx;
  937. +
  938. + dri2_surf = calloc(1, sizeof(*dri2_surf));
  939. + if (!dri2_surf) {
  940. + _eglError(EGL_BAD_ALLOC, "failed to create surface");
  941. + return NULL;
  942. + }
  943. + surf = &dri2_surf->base;
  944. +
  945. + if (!dri2_init_surface(surf, disp, type, config, attrib_list, false, NULL))
  946. + goto err_free_surface;
  947. +
  948. + dri_config = dri2_get_dri_config(dri2_config, type,
  949. + dri2_surf->base.GLColorspace);
  950. + if (!dri_config) {
  951. + _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
  952. + goto err_free_surface;
  953. + }
  954. +
  955. + dri2_surf->dri_drawable =
  956. + dri2_dpy->image_driver->createNewDrawable(dri2_dpy->dri_screen,
  957. + dri_config, dri2_surf);
  958. + if (!dri2_surf->dri_drawable) {
  959. + _eglError(EGL_BAD_ALLOC, "failed to create drawable");
  960. + goto err_free_surface;
  961. + }
  962. +
  963. + format_idx = format_idx_get_from_config(dri2_dpy, dri_config);
  964. + assert(format_idx != -1);
  965. +
  966. + dri2_surf->format = dri2_null_formats[format_idx].dri_image_format;
  967. +
  968. + return surf;
  969. +
  970. +err_free_surface:
  971. + free(dri2_surf);
  972. + return NULL;
  973. +}
  974. +
  975. +static void
  976. +destroy_surface(_EGLSurface *surf)
  977. +{
  978. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(surf->Resource.Display);
  979. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
  980. +
  981. + dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
  982. + dri2_fini_surface(surf);
  983. + free(surf);
  984. +}
  985. +
  986. +static EGLBoolean
  987. +dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf);
  988. +
  989. +static _EGLSurface *
  990. +dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config,
  991. + void *native_window, const EGLint *attrib_list)
  992. +{
  993. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  994. + struct dri2_egl_surface *dri2_surf;
  995. + _EGLSurface *surf;
  996. + int err;
  997. +
  998. + if (dri2_dpy->output.in_use) {
  999. + _eglError(EGL_BAD_NATIVE_WINDOW, "window in use");
  1000. + return NULL;
  1001. + }
  1002. +
  1003. + surf = create_surface(disp, config, EGL_WINDOW_BIT, attrib_list);
  1004. + if (!surf)
  1005. + return NULL;
  1006. + dri2_surf = dri2_egl_surface(surf);
  1007. +
  1008. + dri2_surf->base.Width = dri2_dpy->output.mode.hdisplay;
  1009. + dri2_surf->base.Height = dri2_dpy->output.mode.vdisplay;
  1010. +
  1011. + if (!get_front_bo(dri2_surf)) {
  1012. + _eglError(EGL_BAD_NATIVE_WINDOW, "window get buffer");
  1013. + goto err_destroy_surface;
  1014. + }
  1015. +
  1016. + err = display_output_modeset(dri2_dpy->fd, &dri2_dpy->output,
  1017. + dri2_surf->front_fb_id);
  1018. + if (err) {
  1019. + _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode");
  1020. + goto err_destroy_surface;
  1021. + }
  1022. +
  1023. + dri2_dpy->output.in_use = true;
  1024. +
  1025. + return surf;
  1026. +
  1027. +err_destroy_surface:
  1028. + dri2_null_destroy_surface(disp, surf);
  1029. + return NULL;
  1030. +}
  1031. +
  1032. +static _EGLSurface *
  1033. +dri2_null_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *config,
  1034. + const EGLint *attrib_list)
  1035. +{
  1036. + return create_surface(disp, config, EGL_PBUFFER_BIT, attrib_list);
  1037. +}
  1038. +
  1039. +static EGLBoolean
  1040. +dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
  1041. +{
  1042. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  1043. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
  1044. + EGLint type = surf->Type;
  1045. +
  1046. + /* If there's a current surface then a page flip has been performed, so make
  1047. + * sure we process the flip event.
  1048. + */
  1049. + if (dri2_surf->current)
  1050. + flip_process(dri2_dpy->fd);
  1051. +
  1052. + if (dri2_surf->front)
  1053. + dri2_dpy->image->destroyImage(dri2_surf->front);
  1054. +
  1055. + if (dri2_surf->front_fb_id)
  1056. + drmModeRmFB(dri2_dpy->fd, dri2_surf->front_fb_id);
  1057. +
  1058. + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  1059. + if (dri2_surf->color_buffers[i].fb_id)
  1060. + drmModeRmFB(dri2_dpy->fd, dri2_surf->color_buffers[i].fb_id);
  1061. + if (dri2_surf->color_buffers[i].dri_image)
  1062. + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
  1063. + }
  1064. +
  1065. + destroy_surface(surf);
  1066. +
  1067. + if (type == EGL_WINDOW_BIT)
  1068. + dri2_dpy->output.in_use = false;
  1069. +
  1070. + return EGL_TRUE;
  1071. +}
  1072. +
  1073. +static EGLBoolean
  1074. +dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
  1075. +{
  1076. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  1077. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  1078. + bool *plocked = NULL;
  1079. + uint32_t flags;
  1080. + int err;
  1081. +
  1082. + if (dri2_surf->base.Type != EGL_WINDOW_BIT)
  1083. + return EGL_TRUE;
  1084. +
  1085. + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
  1086. + if (dri2_surf->color_buffers[i].age > 0)
  1087. + dri2_surf->color_buffers[i].age++;
  1088. +
  1089. + /* Make sure we have a back buffer in case we're swapping without
  1090. + * ever rendering. */
  1091. + if (!get_back_bo(dri2_surf)) {
  1092. + _eglError(EGL_BAD_ALLOC, "dri2_null_swap_buffers");
  1093. + return EGL_FALSE;
  1094. + }
  1095. +
  1096. + dri2_flush_drawable_for_swapbuffers(disp, draw);
  1097. + dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
  1098. +
  1099. + if (dri2_surf->current) {
  1100. + /* Wait for the previous flip to happen so the next one can be queued */
  1101. + if (!flip_process(dri2_dpy->fd)) {
  1102. + _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers process");
  1103. + return EGL_FALSE;
  1104. + }
  1105. +
  1106. + plocked = &dri2_surf->current->locked;
  1107. + }
  1108. +
  1109. + flags = DRM_MODE_PAGE_FLIP_EVENT;
  1110. + if (draw->SwapInterval == 0)
  1111. + flags |= DRM_MODE_PAGE_FLIP_ASYNC;
  1112. +
  1113. + do {
  1114. + err = display_output_flip(dri2_dpy->fd, &dri2_dpy->output,
  1115. + dri2_surf->back->fb_id, flags, plocked);
  1116. + } while (err == -EBUSY);
  1117. +
  1118. + if (err) {
  1119. + _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers flip");
  1120. + dri2_surf->back->locked = false;
  1121. + dri2_surf->back = NULL;
  1122. + return EGL_FALSE;
  1123. + }
  1124. +
  1125. + dri2_surf->back->age = 1;
  1126. + dri2_surf->current = dri2_surf->back;
  1127. + dri2_surf->back = NULL;
  1128. +
  1129. + return EGL_TRUE;
  1130. +}
  1131. +
  1132. +static EGLint
  1133. +dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
  1134. +{
  1135. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
  1136. +
  1137. + if (!get_back_bo(dri2_surf)) {
  1138. + _eglError(EGL_BAD_ALLOC, "failed to get back buffer to query age");
  1139. + return -1;
  1140. + }
  1141. +
  1142. + return dri2_surf->back->age;
  1143. +}
  1144. +
  1145. +static struct dri2_egl_display_vtbl dri2_null_display_vtbl = {
  1146. + .create_window_surface = dri2_null_create_window_surface,
  1147. + .create_pbuffer_surface = dri2_null_create_pbuffer_surface,
  1148. + .destroy_surface = dri2_null_destroy_surface,
  1149. + .create_image = dri2_create_image_khr,
  1150. + .swap_buffers = dri2_null_swap_buffers,
  1151. + .query_buffer_age = dri2_null_query_buffer_age,
  1152. + .get_dri_drawable = dri2_surface_get_dri_drawable,
  1153. +};
  1154. +
  1155. +static int
  1156. +dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
  1157. + uint32_t *stamp, void *loaderPrivate,
  1158. + uint32_t buffer_mask, struct __DRIimageList *buffers)
  1159. +{
  1160. + struct dri2_egl_surface *dri2_surf = loaderPrivate;
  1161. +
  1162. + buffers->image_mask = 0;
  1163. + buffers->back = NULL;
  1164. + buffers->front = NULL;
  1165. +
  1166. + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT)
  1167. + if (!get_front_bo(dri2_surf))
  1168. + return 0;
  1169. +
  1170. + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK)
  1171. + if (!get_back_bo(dri2_surf))
  1172. + return 0;
  1173. +
  1174. + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
  1175. + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
  1176. + buffers->front = dri2_surf->front;
  1177. + }
  1178. +
  1179. + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
  1180. + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
  1181. + buffers->back = dri2_surf->back->dri_image;
  1182. + }
  1183. +
  1184. + return 1;
  1185. +}
  1186. +
  1187. +static void
  1188. +dri2_null_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
  1189. +{
  1190. + (void) driDrawable;
  1191. + (void) loaderPrivate;
  1192. +}
  1193. +
  1194. +static const __DRIimageLoaderExtension image_loader_extension = {
  1195. + .base = { __DRI_IMAGE_LOADER, 1 },
  1196. +
  1197. + .getBuffers = dri2_null_image_get_buffers,
  1198. + .flushFrontBuffer = dri2_null_flush_front_buffer,
  1199. +};
  1200. +
  1201. +static const __DRIextension *image_loader_extensions[] = {
  1202. + &image_loader_extension.base,
  1203. + &image_lookup_extension.base,
  1204. + &use_invalidate.base,
  1205. + NULL,
  1206. +};
  1207. +
  1208. +static bool
  1209. +dri2_null_device_is_kms(int fd)
  1210. +{
  1211. + drmModeRes *resources;
  1212. + bool is_kms;
  1213. +
  1214. + resources = drmModeGetResources(fd);
  1215. + if (!resources)
  1216. + return false;
  1217. +
  1218. + is_kms = resources->count_crtcs != 0 &&
  1219. + resources->count_connectors != 0 &&
  1220. + resources->count_encoders != 0;
  1221. +
  1222. + drmModeFreeResources(resources);
  1223. +
  1224. + return is_kms;
  1225. +}
  1226. +
  1227. +static bool
  1228. +dri2_null_probe_device(_EGLDisplay *disp)
  1229. +{
  1230. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  1231. +
  1232. + dri2_dpy->fd = -1;
  1233. +
  1234. + for (unsigned i = 0; i <= NULL_CARD_MINOR_MAX; i++) {
  1235. + char *card_path;
  1236. +
  1237. + if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, i) < 0)
  1238. + continue;
  1239. +
  1240. + dri2_dpy->fd = loader_open_device(card_path);
  1241. + free(card_path);
  1242. + if (dri2_dpy->fd < 0)
  1243. + continue;
  1244. +
  1245. + if (dri2_null_device_is_kms(dri2_dpy->fd)) {
  1246. + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
  1247. + if (dri2_dpy->driver_name) {
  1248. + if (dri2_load_driver_dri3(disp)) {
  1249. + _EGLDevice *dev = _eglAddDevice(dri2_dpy->fd, false);
  1250. + if (!dev) {
  1251. + dlclose(dri2_dpy->driver);
  1252. + _eglLog(_EGL_WARNING, "DRI2: failed to find EGLDevice");
  1253. + } else {
  1254. + dri2_dpy->loader_extensions = image_loader_extensions;
  1255. + dri2_dpy->own_device = 1;
  1256. + disp->Device = dev;
  1257. + return true;
  1258. + }
  1259. + }
  1260. + free(dri2_dpy->driver_name);
  1261. + dri2_dpy->driver_name = NULL;
  1262. + }
  1263. + }
  1264. +
  1265. + close(dri2_dpy->fd);
  1266. + dri2_dpy->fd = -1;
  1267. + }
  1268. +
  1269. + return false;
  1270. +}
  1271. +
  1272. +static EGLBoolean
  1273. +dri2_null_add_configs_for_formats(_EGLDisplay *disp)
  1274. +{
  1275. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  1276. + unsigned int count = 0;
  1277. +
  1278. + for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
  1279. + struct dri2_egl_config *dri2_conf;
  1280. + int format_idx;
  1281. +
  1282. + format_idx = format_idx_get_from_config(dri2_dpy,
  1283. + dri2_dpy->driver_configs[i]);
  1284. + if (format_idx == -1)
  1285. + continue;
  1286. +
  1287. + if (!(dri2_dpy->output.formats & (1 << format_idx))) {
  1288. + _eglLog(_EGL_DEBUG, "unsupported drm format 0x%04x",
  1289. + dri2_null_formats[format_idx].drm_format);
  1290. + continue;
  1291. + }
  1292. +
  1293. + dri2_conf = dri2_add_config(disp,
  1294. + dri2_dpy->driver_configs[i], count + 1,
  1295. + EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
  1296. + NULL, NULL, NULL);
  1297. + if (dri2_conf)
  1298. + count++;
  1299. + }
  1300. +
  1301. + return count != 0;
  1302. +}
  1303. +
  1304. +EGLBoolean
  1305. +dri2_initialize_null(_EGLDisplay *disp)
  1306. +{
  1307. + struct dri2_egl_display *dri2_dpy;
  1308. + uint64_t value;
  1309. + int err;
  1310. +
  1311. + dri2_dpy = calloc(1, sizeof(*dri2_dpy));
  1312. + if (!dri2_dpy)
  1313. + return _eglError(EGL_BAD_ALLOC, "eglInitialize");
  1314. +
  1315. + disp->DriverData = (void *) dri2_dpy;
  1316. +
  1317. + if (!dri2_null_probe_device(disp)) {
  1318. + _eglError(EGL_NOT_INITIALIZED, "failed to load driver");
  1319. + goto cleanup;
  1320. + }
  1321. +
  1322. + /*
  1323. + * Try to use atomic modesetting if available and fallback to legacy kernel
  1324. + * modesetting if not. If this succeeds then universal planes will also have
  1325. + * been enabled.
  1326. + */
  1327. + err = drmSetClientCap(dri2_dpy->fd, DRM_CLIENT_CAP_ATOMIC, 1);
  1328. + dri2_dpy->atomic_enabled = !err;
  1329. +
  1330. + if (!dri2_dpy->atomic_enabled) {
  1331. + /*
  1332. + * Enable universal planes so that we can get the pixel formats for the
  1333. + * primary plane
  1334. + */
  1335. + err = drmSetClientCap(dri2_dpy->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  1336. + if (err) {
  1337. + _eglError(EGL_NOT_INITIALIZED, "failed to enable universal planes");
  1338. + goto cleanup;
  1339. + }
  1340. +
  1341. + dri2_dpy->atomic_enabled = false;
  1342. + }
  1343. +
  1344. + if (!dri2_create_screen(disp)) {
  1345. + _eglError(EGL_NOT_INITIALIZED, "failed to create screen");
  1346. + goto cleanup;
  1347. + }
  1348. +
  1349. + if (!dri2_setup_extensions(disp)) {
  1350. + _eglError(EGL_NOT_INITIALIZED, "failed to find required DRI extensions");
  1351. + goto cleanup;
  1352. + }
  1353. +
  1354. + dri2_setup_screen(disp);
  1355. + dri2_setup_swap_interval(disp, 1);
  1356. +
  1357. + err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
  1358. + if (err || value == 0)
  1359. + dri2_dpy->min_swap_interval = 1;
  1360. +
  1361. + if (dri2_dpy->image->base.version < NULL_IMAGE_EXTENSION_VERSION_MIN) {
  1362. + _eglError(EGL_NOT_INITIALIZED, "image extension version too old");
  1363. + goto cleanup;
  1364. + }
  1365. +
  1366. + if (!display_output_init(dri2_dpy->fd, &dri2_dpy->output,
  1367. + dri2_dpy->atomic_enabled)) {
  1368. + _eglError(EGL_NOT_INITIALIZED, "failed to create output");
  1369. + goto cleanup;
  1370. + }
  1371. +
  1372. + if (!dri2_null_add_configs_for_formats(disp)) {
  1373. + _eglError(EGL_NOT_INITIALIZED, "failed to add configs");
  1374. + goto cleanup;
  1375. + }
  1376. +
  1377. + disp->Extensions.EXT_buffer_age = EGL_TRUE;
  1378. + disp->Extensions.KHR_image_base = EGL_TRUE;
  1379. +
  1380. + /* Fill vtbl last to prevent accidentally calling virtual function during
  1381. + * initialization.
  1382. + */
  1383. + dri2_dpy->vtbl = &dri2_null_display_vtbl;
  1384. +
  1385. + return EGL_TRUE;
  1386. +
  1387. +cleanup:
  1388. + dri2_display_destroy(disp);
  1389. + return EGL_FALSE;
  1390. +}
  1391. +
  1392. +void
  1393. +dri2_teardown_null(struct dri2_egl_display *dri2_dpy)
  1394. +{
  1395. + drmModeAtomicFree(dri2_dpy->output.atomic_state);
  1396. +
  1397. + if (dri2_dpy->output.mode_blob_id)
  1398. + drmModeDestroyPropertyBlob(dri2_dpy->fd, dri2_dpy->output.mode_blob_id);
  1399. +
  1400. + if (dri2_dpy->output.plane_prop_res) {
  1401. + for (unsigned i = 0; dri2_dpy->output.plane_prop_res[i]; i++)
  1402. + drmModeFreeProperty(dri2_dpy->output.plane_prop_res[i]);
  1403. + free(dri2_dpy->output.plane_prop_res);
  1404. + }
  1405. +
  1406. + if (dri2_dpy->output.crtc_prop_res) {
  1407. + for (unsigned i = 0; dri2_dpy->output.crtc_prop_res[i]; i++)
  1408. + drmModeFreeProperty(dri2_dpy->output.crtc_prop_res[i]);
  1409. + free(dri2_dpy->output.crtc_prop_res);
  1410. + }
  1411. +
  1412. + if (dri2_dpy->output.connector_prop_res) {
  1413. + for (unsigned i = 0; dri2_dpy->output.connector_prop_res[i]; i++)
  1414. + drmModeFreeProperty(dri2_dpy->output.connector_prop_res[i]);
  1415. + free(dri2_dpy->output.connector_prop_res);
  1416. + }
  1417. +}
  1418. diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
  1419. index 6d7f62c..e4f2c43 100644
  1420. --- a/src/egl/main/eglapi.c
  1421. +++ b/src/egl/main/eglapi.c
  1422. @@ -989,7 +989,10 @@ _eglCreateWindowSurfaceCommon(_EGLDisplay *disp, EGLConfig config,
  1423. if (native_window == NULL)
  1424. - RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
  1425. +#ifdef HAVE_NULL_PLATFORM
  1426. + if (disp && disp->Platform != _EGL_PLATFORM_NULL)
  1427. +#endif
  1428. + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
  1429. if (disp && (disp->Platform == _EGL_PLATFORM_SURFACELESS ||
  1430. disp->Platform == _EGL_PLATFORM_DEVICE)) {
  1431. diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
  1432. index 486ac3b..395f381 100644
  1433. --- a/src/egl/main/egldisplay.c
  1434. +++ b/src/egl/main/egldisplay.c
  1435. @@ -78,6 +78,7 @@ static const struct {
  1436. { _EGL_PLATFORM_SURFACELESS, "surfaceless" },
  1437. { _EGL_PLATFORM_DEVICE, "device" },
  1438. { _EGL_PLATFORM_TIZEN, "tizen" },
  1439. + { _EGL_PLATFORM_NULL, "null" },
  1440. };
  1441. diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
  1442. index 020529c..8489af9 100644
  1443. --- a/src/egl/main/egldisplay.h
  1444. +++ b/src/egl/main/egldisplay.h
  1445. @@ -53,6 +53,7 @@ enum _egl_platform_type {
  1446. _EGL_PLATFORM_SURFACELESS,
  1447. _EGL_PLATFORM_DEVICE,
  1448. _EGL_PLATFORM_TIZEN,
  1449. + _EGL_PLATFORM_NULL,
  1450. _EGL_NUM_PLATFORMS,
  1451. _EGL_INVALID_PLATFORM = -1
  1452. diff --git a/src/egl/meson.build b/src/egl/meson.build
  1453. index 5749ec8..daa6a3a 100644
  1454. --- a/src/egl/meson.build
  1455. +++ b/src/egl/meson.build
  1456. @@ -146,6 +146,11 @@ if with_platform_tizen
  1457. incs_for_egl += [inc_loader]
  1458. deps_for_egl += [dep_tizen, dep_libdrm]
  1459. endif
  1460. +if with_platform_null
  1461. + files_egl += files('drivers/dri2/platform_null.c')
  1462. + incs_for_egl += [inc_loader]
  1463. + deps_for_egl += dep_libdrm
  1464. +endif
  1465. if cc.has_function('mincore')
  1466. c_args_for_egl += '-DHAVE_MINCORE'