glamor_egl.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. /*
  2. * Copyright © 2010 Intel Corporation.
  3. *
  4. * Permission is hereby granted, free of charge, to any person
  5. * obtaining a copy of this software and associated documentation
  6. * files (the "Software"), to deal in the Software without
  7. * restriction, including without limitation the rights to use, copy,
  8. * modify, merge, publish, distribute, sublicense, and/or sell copies
  9. * of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice (including
  13. * the next paragraph) shall be included in all copies or substantial
  14. * portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. *
  25. * Authors:
  26. * Zhigang Gong <zhigang.gong@linux.intel.com>
  27. *
  28. */
  29. #include "dix-config.h"
  30. #define GLAMOR_FOR_XORG
  31. #include <xorg-server.h>
  32. #include <unistd.h>
  33. #include <fcntl.h>
  34. #include <sys/ioctl.h>
  35. #include <errno.h>
  36. #include <xf86.h>
  37. #include <xf86drm.h>
  38. #define EGL_DISPLAY_NO_X_MESA
  39. #ifdef GLAMOR_HAS_GBM
  40. #include <gbm.h>
  41. #include <drm_fourcc.h>
  42. #endif
  43. #define MESA_EGL_NO_X11_HEADERS
  44. #include <epoxy/gl.h>
  45. #include <epoxy/egl.h>
  46. #include "glamor.h"
  47. #include "glamor_priv.h"
  48. #include "dri3.h"
  49. static const char glamor_name[] = "glamor";
  50. static void
  51. glamor_identify(int flags)
  52. {
  53. xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n",
  54. glamor_name);
  55. }
  56. struct glamor_egl_screen_private {
  57. EGLDisplay display;
  58. EGLContext context;
  59. EGLint major, minor;
  60. char *device_path;
  61. CreateScreenResourcesProcPtr CreateScreenResources;
  62. CloseScreenProcPtr CloseScreen;
  63. int fd;
  64. EGLImageKHR front_image;
  65. PixmapPtr *back_pixmap;
  66. int cpp;
  67. #ifdef GLAMOR_HAS_GBM
  68. struct gbm_device *gbm;
  69. #endif
  70. int has_gem;
  71. int gl_context_depth;
  72. int dri3_capable;
  73. CloseScreenProcPtr saved_close_screen;
  74. xf86FreeScreenProc *saved_free_screen;
  75. };
  76. int xf86GlamorEGLPrivateIndex = -1;
  77. static struct glamor_egl_screen_private *
  78. glamor_egl_get_screen_private(ScrnInfoPtr scrn)
  79. {
  80. return (struct glamor_egl_screen_private *)
  81. scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
  82. }
  83. static void
  84. glamor_egl_make_current(struct glamor_context *glamor_ctx)
  85. {
  86. /* There's only a single global dispatch table in Mesa. EGL, GLX,
  87. * and AIGLX's direct dispatch table manipulation don't talk to
  88. * each other. We need to set the context to NULL first to avoid
  89. * EGL's no-op context change fast path when switching back to
  90. * EGL.
  91. */
  92. eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
  93. EGL_NO_SURFACE, EGL_NO_CONTEXT);
  94. if (!eglMakeCurrent(glamor_ctx->display,
  95. EGL_NO_SURFACE, EGL_NO_SURFACE,
  96. glamor_ctx->ctx)) {
  97. FatalError("Failed to make EGL context current\n");
  98. }
  99. }
  100. static EGLImageKHR
  101. _glamor_egl_create_image(struct glamor_egl_screen_private *glamor_egl,
  102. int width, int height, int stride, int name, int depth)
  103. {
  104. EGLImageKHR image;
  105. EGLint attribs[] = {
  106. EGL_WIDTH, 0,
  107. EGL_HEIGHT, 0,
  108. EGL_DRM_BUFFER_STRIDE_MESA, 0,
  109. EGL_DRM_BUFFER_FORMAT_MESA,
  110. EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
  111. EGL_DRM_BUFFER_USE_MESA,
  112. EGL_DRM_BUFFER_USE_SHARE_MESA | EGL_DRM_BUFFER_USE_SCANOUT_MESA,
  113. EGL_NONE
  114. };
  115. attribs[1] = width;
  116. attribs[3] = height;
  117. attribs[5] = stride;
  118. if (depth != 32 && depth != 24)
  119. return EGL_NO_IMAGE_KHR;
  120. image = eglCreateImageKHR(glamor_egl->display,
  121. glamor_egl->context,
  122. EGL_DRM_BUFFER_MESA,
  123. (void *) (uintptr_t) name,
  124. attribs);
  125. if (image == EGL_NO_IMAGE_KHR)
  126. return EGL_NO_IMAGE_KHR;
  127. return image;
  128. }
  129. static int
  130. glamor_get_flink_name(int fd, int handle, int *name)
  131. {
  132. struct drm_gem_flink flink;
  133. flink.handle = handle;
  134. if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0)
  135. return FALSE;
  136. *name = flink.name;
  137. return TRUE;
  138. }
  139. static Bool
  140. glamor_create_texture_from_image(ScreenPtr screen,
  141. EGLImageKHR image, GLuint * texture)
  142. {
  143. struct glamor_screen_private *glamor_priv =
  144. glamor_get_screen_private(screen);
  145. glamor_make_current(glamor_priv);
  146. glGenTextures(1, texture);
  147. glBindTexture(GL_TEXTURE_2D, *texture);
  148. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  149. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  150. glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
  151. glBindTexture(GL_TEXTURE_2D, 0);
  152. return TRUE;
  153. }
  154. unsigned int
  155. glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h)
  156. {
  157. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  158. struct glamor_egl_screen_private *glamor_egl;
  159. EGLImageKHR image;
  160. GLuint texture;
  161. #ifdef GLAMOR_HAS_GBM
  162. struct gbm_bo *bo;
  163. EGLNativePixmapType native_pixmap;
  164. glamor_egl = glamor_egl_get_screen_private(scrn);
  165. bo = gbm_bo_create(glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888,
  166. GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
  167. if (!bo)
  168. return 0;
  169. /* If the following assignment raises an error or a warning
  170. * then that means EGLNativePixmapType is not struct gbm_bo *
  171. * on your platform: This code won't work and you should not
  172. * compile with dri3 support enabled */
  173. native_pixmap = bo;
  174. image = eglCreateImageKHR(glamor_egl->display,
  175. EGL_NO_CONTEXT,
  176. EGL_NATIVE_PIXMAP_KHR,
  177. native_pixmap, NULL);
  178. gbm_bo_destroy(bo);
  179. if (image == EGL_NO_IMAGE_KHR)
  180. return 0;
  181. glamor_create_texture_from_image(screen, image, &texture);
  182. eglDestroyImageKHR(glamor_egl->display, image);
  183. return texture;
  184. #else
  185. return 0; /* this path should never happen */
  186. #endif
  187. }
  188. Bool
  189. glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride)
  190. {
  191. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  192. struct glamor_pixmap_private *pixmap_priv;
  193. struct glamor_egl_screen_private *glamor_egl;
  194. PixmapPtr screen_pixmap;
  195. glamor_egl = glamor_egl_get_screen_private(scrn);
  196. screen_pixmap = screen->GetScreenPixmap(screen);
  197. pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
  198. if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) {
  199. xf86DrvMsg(scrn->scrnIndex, X_ERROR,
  200. "Failed to create textured screen.");
  201. return FALSE;
  202. }
  203. glamor_egl->front_image = pixmap_priv->base.image;
  204. glamor_set_screen_pixmap(screen_pixmap, glamor_egl->back_pixmap);
  205. return TRUE;
  206. }
  207. Bool
  208. glamor_egl_create_textured_screen_ext(ScreenPtr screen,
  209. int handle,
  210. int stride, PixmapPtr *back_pixmap)
  211. {
  212. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  213. struct glamor_egl_screen_private *glamor_egl;
  214. glamor_egl = glamor_egl_get_screen_private(scrn);
  215. glamor_egl->back_pixmap = back_pixmap;
  216. if (!glamor_egl_create_textured_screen(screen, handle, stride))
  217. return FALSE;
  218. return TRUE;
  219. }
  220. static Bool
  221. glamor_egl_check_has_gem(int fd)
  222. {
  223. struct drm_gem_flink flink;
  224. flink.handle = 0;
  225. ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
  226. if (errno == ENOENT || errno == EINVAL)
  227. return TRUE;
  228. return FALSE;
  229. }
  230. Bool
  231. glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride)
  232. {
  233. ScreenPtr screen = pixmap->drawable.pScreen;
  234. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  235. struct glamor_screen_private *glamor_priv =
  236. glamor_get_screen_private(screen);
  237. struct glamor_pixmap_private *pixmap_priv =
  238. glamor_get_pixmap_private(pixmap);
  239. struct glamor_egl_screen_private *glamor_egl;
  240. EGLImageKHR image;
  241. GLuint texture;
  242. int name;
  243. Bool ret = FALSE;
  244. glamor_egl = glamor_egl_get_screen_private(scrn);
  245. glamor_make_current(glamor_priv);
  246. if (glamor_egl->has_gem) {
  247. if (!glamor_get_flink_name(glamor_egl->fd, handle, &name)) {
  248. xf86DrvMsg(scrn->scrnIndex, X_ERROR,
  249. "Couldn't flink pixmap handle\n");
  250. glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
  251. assert(0);
  252. return FALSE;
  253. }
  254. }
  255. else
  256. name = handle;
  257. image = _glamor_egl_create_image(glamor_egl,
  258. pixmap->drawable.width,
  259. pixmap->drawable.height,
  260. ((stride * 8 +
  261. 7) / pixmap->drawable.bitsPerPixel),
  262. name, pixmap->drawable.depth);
  263. if (image == EGL_NO_IMAGE_KHR) {
  264. glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
  265. goto done;
  266. }
  267. glamor_create_texture_from_image(screen, image, &texture);
  268. glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
  269. glamor_set_pixmap_texture(pixmap, texture);
  270. pixmap_priv->base.image = image;
  271. ret = TRUE;
  272. done:
  273. return ret;
  274. }
  275. Bool
  276. glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap, void *bo)
  277. {
  278. ScreenPtr screen = pixmap->drawable.pScreen;
  279. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  280. struct glamor_screen_private *glamor_priv =
  281. glamor_get_screen_private(screen);
  282. struct glamor_pixmap_private *pixmap_priv =
  283. glamor_get_pixmap_private(pixmap);
  284. struct glamor_egl_screen_private *glamor_egl;
  285. EGLImageKHR image;
  286. GLuint texture;
  287. Bool ret = FALSE;
  288. glamor_egl = glamor_egl_get_screen_private(scrn);
  289. glamor_make_current(glamor_priv);
  290. image = eglCreateImageKHR(glamor_egl->display,
  291. glamor_egl->context,
  292. EGL_NATIVE_PIXMAP_KHR, bo, NULL);
  293. if (image == EGL_NO_IMAGE_KHR) {
  294. glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
  295. goto done;
  296. }
  297. glamor_create_texture_from_image(screen, image, &texture);
  298. glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
  299. glamor_set_pixmap_texture(pixmap, texture);
  300. pixmap_priv->base.image = image;
  301. ret = TRUE;
  302. done:
  303. return ret;
  304. }
  305. #ifdef GLAMOR_HAS_GBM
  306. int glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd);
  307. void glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name);
  308. int
  309. glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd)
  310. {
  311. union gbm_bo_handle handle;
  312. struct drm_prime_handle args;
  313. handle = gbm_bo_get_handle(bo);
  314. args.handle = handle.u32;
  315. args.flags = DRM_CLOEXEC;
  316. if (ioctl(gbm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
  317. return FALSE;
  318. *fd = args.fd;
  319. return TRUE;
  320. }
  321. void
  322. glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name)
  323. {
  324. union gbm_bo_handle handle;
  325. handle = gbm_bo_get_handle(bo);
  326. if (!glamor_get_flink_name(gbm_fd, handle.u32, name))
  327. *name = -1;
  328. }
  329. #endif
  330. int
  331. glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
  332. PixmapPtr pixmap,
  333. unsigned int tex,
  334. Bool want_name, CARD16 *stride, CARD32 *size)
  335. {
  336. #ifdef GLAMOR_HAS_GBM
  337. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  338. struct glamor_pixmap_private *pixmap_priv =
  339. glamor_get_pixmap_private(pixmap);
  340. struct glamor_screen_private *glamor_priv =
  341. glamor_get_screen_private(screen);
  342. struct glamor_egl_screen_private *glamor_egl;
  343. EGLImageKHR image;
  344. struct gbm_bo *bo;
  345. int fd = -1;
  346. EGLint attribs[] = {
  347. EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
  348. EGL_GL_TEXTURE_LEVEL_KHR, 0,
  349. EGL_NONE
  350. };
  351. glamor_egl = glamor_egl_get_screen_private(scrn);
  352. glamor_make_current(glamor_priv);
  353. image = pixmap_priv->base.image;
  354. if (!image) {
  355. image = eglCreateImageKHR(glamor_egl->display,
  356. glamor_egl->context,
  357. EGL_GL_TEXTURE_2D_KHR,
  358. (EGLClientBuffer) (uintptr_t)
  359. tex, attribs);
  360. if (image == EGL_NO_IMAGE_KHR)
  361. goto failure;
  362. pixmap_priv->base.image = image;
  363. glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
  364. }
  365. bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
  366. if (!bo)
  367. goto failure;
  368. pixmap->devKind = gbm_bo_get_stride(bo);
  369. if (want_name) {
  370. if (glamor_egl->has_gem)
  371. glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
  372. }
  373. else {
  374. if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd)) {
  375. }
  376. }
  377. *stride = pixmap->devKind;
  378. *size = pixmap->devKind * gbm_bo_get_height(bo);
  379. gbm_bo_destroy(bo);
  380. failure:
  381. return fd;
  382. #else
  383. return -1;
  384. #endif
  385. }
  386. _X_EXPORT PixmapPtr
  387. glamor_pixmap_from_fd(ScreenPtr screen,
  388. int fd,
  389. CARD16 width,
  390. CARD16 height,
  391. CARD16 stride, CARD8 depth, CARD8 bpp)
  392. {
  393. #ifdef GLAMOR_HAS_GBM
  394. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  395. struct glamor_egl_screen_private *glamor_egl;
  396. struct gbm_bo *bo;
  397. EGLImageKHR image;
  398. PixmapPtr pixmap;
  399. Bool ret = FALSE;
  400. EGLint attribs[] = {
  401. EGL_WIDTH, 0,
  402. EGL_HEIGHT, 0,
  403. EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
  404. EGL_DMA_BUF_PLANE0_FD_EXT, 0,
  405. EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
  406. EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
  407. EGL_NONE
  408. };
  409. glamor_egl = glamor_egl_get_screen_private(scrn);
  410. if (!glamor_egl->dri3_capable)
  411. return NULL;
  412. if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0)
  413. return NULL;
  414. attribs[1] = width;
  415. attribs[3] = height;
  416. attribs[7] = fd;
  417. attribs[11] = stride;
  418. image = eglCreateImageKHR(glamor_egl->display,
  419. EGL_NO_CONTEXT,
  420. EGL_LINUX_DMA_BUF_EXT,
  421. NULL, attribs);
  422. if (image == EGL_NO_IMAGE_KHR)
  423. return NULL;
  424. /* EGL_EXT_image_dma_buf_import can impose restrictions on the
  425. * usage of the image. Use gbm_bo to bypass the limitations. */
  426. bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
  427. eglDestroyImageKHR(glamor_egl->display, image);
  428. if (!bo)
  429. return NULL;
  430. pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
  431. screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
  432. ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
  433. gbm_bo_destroy(bo);
  434. if (ret)
  435. return pixmap;
  436. else {
  437. screen->DestroyPixmap(pixmap);
  438. return NULL;
  439. }
  440. #else
  441. return NULL;
  442. #endif
  443. }
  444. static void
  445. _glamor_egl_destroy_pixmap_image(PixmapPtr pixmap)
  446. {
  447. ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
  448. struct glamor_egl_screen_private *glamor_egl =
  449. glamor_egl_get_screen_private(scrn);
  450. struct glamor_pixmap_private *pixmap_priv =
  451. glamor_get_pixmap_private(pixmap);
  452. if (pixmap_priv->base.image) {
  453. /* Before destroy an image which was attached to
  454. * a texture. we must call glFlush to make sure the
  455. * operation on that texture has been done.*/
  456. glamor_block_handler(pixmap->drawable.pScreen);
  457. eglDestroyImageKHR(glamor_egl->display, pixmap_priv->base.image);
  458. pixmap_priv->base.image = NULL;
  459. }
  460. }
  461. _X_EXPORT void
  462. glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
  463. {
  464. ScrnInfoPtr scrn = xf86ScreenToScrn(front->drawable.pScreen);
  465. struct glamor_egl_screen_private *glamor_egl =
  466. glamor_egl_get_screen_private(scrn);
  467. EGLImageKHR temp;
  468. struct glamor_pixmap_private *front_priv =
  469. glamor_get_pixmap_private(front);
  470. struct glamor_pixmap_private *back_priv =
  471. glamor_get_pixmap_private(back);
  472. glamor_pixmap_exchange_fbos(front, back);
  473. temp = back_priv->base.image;
  474. back_priv->base.image = front_priv->base.image;
  475. front_priv->base.image = temp;
  476. glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
  477. glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
  478. glamor_egl->front_image = front_priv->base.image;
  479. }
  480. void
  481. glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap)
  482. {
  483. if (pixmap->refcnt == 1)
  484. _glamor_egl_destroy_pixmap_image(pixmap);
  485. glamor_destroy_textured_pixmap(pixmap);
  486. }
  487. static Bool
  488. glamor_egl_close_screen(ScreenPtr screen)
  489. {
  490. ScrnInfoPtr scrn;
  491. struct glamor_egl_screen_private *glamor_egl;
  492. struct glamor_pixmap_private *pixmap_priv;
  493. PixmapPtr screen_pixmap;
  494. scrn = xf86ScreenToScrn(screen);
  495. glamor_egl = glamor_egl_get_screen_private(scrn);
  496. screen_pixmap = screen->GetScreenPixmap(screen);
  497. pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
  498. eglDestroyImageKHR(glamor_egl->display, glamor_egl->front_image);
  499. pixmap_priv->base.image = NULL;
  500. glamor_egl->front_image = NULL;
  501. if (glamor_egl->back_pixmap && *glamor_egl->back_pixmap) {
  502. pixmap_priv = glamor_get_pixmap_private(*glamor_egl->back_pixmap);
  503. if (pixmap_priv->base.image) {
  504. eglDestroyImageKHR(glamor_egl->display, pixmap_priv->base.image);
  505. pixmap_priv->base.image = NULL;
  506. }
  507. }
  508. screen->CloseScreen = glamor_egl->saved_close_screen;
  509. return screen->CloseScreen(screen);
  510. }
  511. static int
  512. glamor_dri3_open_client(ClientPtr client,
  513. ScreenPtr screen,
  514. RRProviderPtr provider,
  515. int *fdp)
  516. {
  517. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  518. struct glamor_egl_screen_private *glamor_egl =
  519. glamor_egl_get_screen_private(scrn);
  520. int fd;
  521. drm_magic_t magic;
  522. fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC);
  523. if (fd < 0)
  524. return BadAlloc;
  525. /* Before FD passing in the X protocol with DRI3 (and increased
  526. * security of rendering with per-process address spaces on the
  527. * GPU), the kernel had to come up with a way to have the server
  528. * decide which clients got to access the GPU, which was done by
  529. * each client getting a unique (magic) number from the kernel,
  530. * passing it to the server, and the server then telling the
  531. * kernel which clients were authenticated for using the device.
  532. *
  533. * Now that we have FD passing, the server can just set up the
  534. * authentication on its own and hand the prepared FD off to the
  535. * client.
  536. */
  537. if (drmGetMagic(fd, &magic) < 0) {
  538. if (errno == EACCES) {
  539. /* Assume that we're on a render node, and the fd is
  540. * already as authenticated as it should be.
  541. */
  542. *fdp = fd;
  543. return Success;
  544. } else {
  545. close(fd);
  546. return BadMatch;
  547. }
  548. }
  549. if (drmAuthMagic(glamor_egl->fd, magic) < 0) {
  550. close(fd);
  551. return BadMatch;
  552. }
  553. *fdp = fd;
  554. return Success;
  555. }
  556. static dri3_screen_info_rec glamor_dri3_info = {
  557. .version = 1,
  558. .open_client = glamor_dri3_open_client,
  559. .pixmap_from_fd = glamor_pixmap_from_fd,
  560. .fd_from_pixmap = glamor_fd_from_pixmap,
  561. };
  562. void
  563. glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
  564. {
  565. ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
  566. glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  567. struct glamor_egl_screen_private *glamor_egl =
  568. glamor_egl_get_screen_private(scrn);
  569. glamor_egl->saved_close_screen = screen->CloseScreen;
  570. screen->CloseScreen = glamor_egl_close_screen;
  571. glamor_ctx->ctx = glamor_egl->context;
  572. glamor_ctx->display = glamor_egl->display;
  573. glamor_ctx->make_current = glamor_egl_make_current;
  574. if (glamor_egl->dri3_capable) {
  575. /* Tell the core that we have the interfaces for import/export
  576. * of pixmaps.
  577. */
  578. glamor_enable_dri3(screen);
  579. /* If the driver wants to do its own auth dance (e.g. Xwayland
  580. * on pre-3.15 kernels that don't have render nodes and thus
  581. * has the wayland compositor as a master), then it needs us
  582. * to stay out of the way and let it init DRI3 on its own.
  583. */
  584. if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) {
  585. /* To do DRI3 device FD generation, we need to open a new fd
  586. * to the same device we were handed in originally.
  587. */
  588. glamor_egl->device_path = drmGetDeviceNameFromFd(glamor_egl->fd);
  589. if (!dri3_screen_init(screen, &glamor_dri3_info)) {
  590. xf86DrvMsg(scrn->scrnIndex, X_ERROR,
  591. "Failed to initialize DRI3.\n");
  592. }
  593. }
  594. }
  595. }
  596. static void
  597. glamor_egl_free_screen(ScrnInfoPtr scrn)
  598. {
  599. struct glamor_egl_screen_private *glamor_egl;
  600. glamor_egl = glamor_egl_get_screen_private(scrn);
  601. if (glamor_egl != NULL) {
  602. eglMakeCurrent(glamor_egl->display,
  603. EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  604. #ifdef GLAMOR_HAS_GBM
  605. if (glamor_egl->gbm)
  606. gbm_device_destroy(glamor_egl->gbm);
  607. #endif
  608. free(glamor_egl->device_path);
  609. scrn->FreeScreen = glamor_egl->saved_free_screen;
  610. free(glamor_egl);
  611. scrn->FreeScreen(scrn);
  612. }
  613. }
  614. Bool
  615. glamor_egl_init(ScrnInfoPtr scrn, int fd)
  616. {
  617. struct glamor_egl_screen_private *glamor_egl;
  618. const char *version;
  619. EGLint config_attribs[] = {
  620. #ifdef GLAMOR_GLES2
  621. EGL_CONTEXT_CLIENT_VERSION, 2,
  622. #endif
  623. EGL_NONE
  624. };
  625. glamor_identify(0);
  626. glamor_egl = calloc(sizeof(*glamor_egl), 1);
  627. if (glamor_egl == NULL)
  628. return FALSE;
  629. if (xf86GlamorEGLPrivateIndex == -1)
  630. xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
  631. scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
  632. glamor_egl->fd = fd;
  633. #ifdef GLAMOR_HAS_GBM
  634. glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
  635. if (glamor_egl->gbm == NULL) {
  636. ErrorF("couldn't get display device\n");
  637. return FALSE;
  638. }
  639. glamor_egl->display = eglGetDisplay(glamor_egl->gbm);
  640. #else
  641. glamor_egl->display = eglGetDisplay((EGLNativeDisplayType) (intptr_t) fd);
  642. #endif
  643. glamor_egl->has_gem = glamor_egl_check_has_gem(fd);
  644. #ifndef GLAMOR_GLES2
  645. eglBindAPI(EGL_OPENGL_API);
  646. #else
  647. eglBindAPI(EGL_OPENGL_ES_API);
  648. #endif
  649. if (!eglInitialize
  650. (glamor_egl->display, &glamor_egl->major, &glamor_egl->minor)) {
  651. xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n");
  652. return FALSE;
  653. }
  654. version = eglQueryString(glamor_egl->display, EGL_VERSION);
  655. xf86Msg(X_INFO, "%s: EGL version %s:\n", glamor_name, version);
  656. #define GLAMOR_CHECK_EGL_EXTENSION(EXT) \
  657. if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) { \
  658. ErrorF("EGL_" #EXT " required.\n"); \
  659. return FALSE; \
  660. }
  661. #define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2) \
  662. if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) && \
  663. !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) { \
  664. ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n"); \
  665. return FALSE; \
  666. }
  667. GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image);
  668. GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image);
  669. #ifdef GLAMOR_GLES2
  670. GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_gles2);
  671. #else
  672. GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context,
  673. KHR_surfaceless_opengl);
  674. #endif
  675. #ifdef GLAMOR_HAS_GBM
  676. if (epoxy_has_egl_extension(glamor_egl->display,
  677. "EGL_KHR_gl_texture_2D_image") &&
  678. epoxy_has_egl_extension(glamor_egl->display,
  679. "EGL_EXT_image_dma_buf_import"))
  680. glamor_egl->dri3_capable = TRUE;
  681. #endif
  682. glamor_egl->context = eglCreateContext(glamor_egl->display,
  683. NULL, EGL_NO_CONTEXT,
  684. config_attribs);
  685. if (glamor_egl->context == EGL_NO_CONTEXT) {
  686. xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create EGL context\n");
  687. return FALSE;
  688. }
  689. if (!eglMakeCurrent(glamor_egl->display,
  690. EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
  691. xf86DrvMsg(scrn->scrnIndex, X_ERROR,
  692. "Failed to make EGL context current\n");
  693. return FALSE;
  694. }
  695. glamor_egl->saved_free_screen = scrn->FreeScreen;
  696. scrn->FreeScreen = glamor_egl_free_screen;
  697. #ifdef GLAMOR_GLES2
  698. xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using GLES2.\n");
  699. xf86DrvMsg(scrn->scrnIndex, X_WARNING,
  700. "Glamor is using GLES2 but GLX needs GL. "
  701. "Indirect GLX may not work correctly.\n");
  702. #endif
  703. return TRUE;
  704. }
  705. /** Stub to retain compatibility with pre-server-1.16 ABI. */
  706. Bool
  707. glamor_egl_init_textured_pixmap(ScreenPtr screen)
  708. {
  709. return TRUE;
  710. }