a73859c0b9da44a8304a2b5cccb2899fc77a8b45
[mesa.git] / src / gallium / state_trackers / egl / common / egl_g3d_api.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "egldriver.h"
27 #include "eglcurrent.h"
28 #include "egllog.h"
29
30 #include "pipe/p_screen.h"
31 #include "util/u_memory.h"
32 #include "util/u_inlines.h"
33 #include "util/u_box.h"
34
35 #include "egl_g3d.h"
36 #include "egl_g3d_api.h"
37 #include "egl_g3d_image.h"
38 #include "egl_g3d_sync.h"
39 #include "egl_g3d_st.h"
40 #include "native.h"
41
42 #ifdef EGL_WL_bind_wayland_display
43 #include <wayland-drm.h>
44 #endif
45
46 /**
47 * Return the state tracker for the given context.
48 */
49 static struct st_api *
50 egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx,
51 enum st_profile_type *profile)
52 {
53 struct st_api *stapi;
54 EGLint api = -1;
55
56 *profile = ST_PROFILE_DEFAULT;
57
58 switch (ctx->ClientAPI) {
59 case EGL_OPENGL_ES_API:
60 switch (ctx->ClientVersion) {
61 case 1:
62 api = ST_API_OPENGL;
63 *profile = ST_PROFILE_OPENGL_ES1;
64 break;
65 case 2:
66 api = ST_API_OPENGL;
67 *profile = ST_PROFILE_OPENGL_ES2;
68 break;
69 default:
70 _eglLog(_EGL_WARNING, "unknown client version %d",
71 ctx->ClientVersion);
72 break;
73 }
74 break;
75 case EGL_OPENVG_API:
76 api = ST_API_OPENVG;
77 break;
78 case EGL_OPENGL_API:
79 api = ST_API_OPENGL;
80 break;
81 default:
82 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
83 break;
84 }
85
86 stapi = egl_g3d_get_st_api(drv, api);
87 if (stapi && !(stapi->profile_mask & (1 << *profile)))
88 stapi = NULL;
89
90 return stapi;
91 }
92
93 struct egl_g3d_choose_config_data {
94 _EGLConfig criteria;
95 enum pipe_format format;
96 };
97
98 static int
99 egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2,
100 void *priv_data)
101 {
102 struct egl_g3d_choose_config_data *data =
103 (struct egl_g3d_choose_config_data *) priv_data;
104 const _EGLConfig *criteria = &data->criteria;;
105
106 /* EGL_NATIVE_VISUAL_TYPE ignored? */
107 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
108 }
109
110 static EGLBoolean
111 egl_g3d_match_config(const _EGLConfig *conf, void *priv_data)
112 {
113 struct egl_g3d_choose_config_data *data =
114 (struct egl_g3d_choose_config_data *) priv_data;
115 struct egl_g3d_config *gconf = egl_g3d_config(conf);
116
117 if (data->format != PIPE_FORMAT_NONE &&
118 data->format != gconf->native->color_format)
119 return EGL_FALSE;
120
121 return _eglMatchConfig(conf, &data->criteria);
122 }
123
124 static EGLBoolean
125 egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs,
126 EGLConfig *configs, EGLint size, EGLint *num_configs)
127 {
128 struct egl_g3d_choose_config_data data;
129
130 if (!_eglParseConfigAttribList(&data.criteria, dpy, attribs))
131 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
132
133 data.format = PIPE_FORMAT_NONE;
134 if (data.criteria.MatchNativePixmap != EGL_NONE &&
135 data.criteria.MatchNativePixmap != EGL_DONT_CARE) {
136 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
137
138 if (!gdpy->native->get_pixmap_format(gdpy->native,
139 (EGLNativePixmapType) data.criteria.MatchNativePixmap,
140 &data.format))
141 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglChooseConfig");
142 }
143
144 return _eglFilterConfigArray(dpy->Configs, configs, size, num_configs,
145 egl_g3d_match_config, egl_g3d_compare_config, &data);
146 }
147
148 static _EGLContext *
149 egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
150 _EGLContext *share, const EGLint *attribs)
151 {
152 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
153 struct egl_g3d_context *gshare = egl_g3d_context(share);
154 struct egl_g3d_config *gconf = egl_g3d_config(conf);
155 struct egl_g3d_context *gctx;
156 struct st_context_attribs stattribs;
157 enum st_context_error ctx_err = 0;
158
159 gctx = CALLOC_STRUCT(egl_g3d_context);
160 if (!gctx) {
161 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
162 return NULL;
163 }
164
165 if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
166 FREE(gctx);
167 return NULL;
168 }
169
170 memset(&stattribs, 0, sizeof(stattribs));
171 if (gconf)
172 stattribs.visual = gconf->stvis;
173
174 gctx->stapi = egl_g3d_choose_st(drv, &gctx->base, &stattribs.profile);
175 if (!gctx->stapi) {
176 FREE(gctx);
177 return NULL;
178 }
179
180 gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
181 &stattribs, &ctx_err, (gshare) ? gshare->stctxi : NULL);
182 if (!gctx->stctxi) {
183 FREE(gctx);
184 return NULL;
185 }
186
187 gctx->stctxi->st_manager_private = (void *) &gctx->base;
188
189 return &gctx->base;
190 }
191
192 /**
193 * Destroy a context.
194 */
195 static void
196 destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
197 {
198 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
199
200 /* FIXME a context might live longer than its display */
201 if (!dpy->Initialized)
202 _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
203
204 gctx->stctxi->destroy(gctx->stctxi);
205
206 FREE(gctx);
207 }
208
209 static EGLBoolean
210 egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
211 {
212 if (_eglPutContext(ctx))
213 destroy_context(dpy, ctx);
214 return EGL_TRUE;
215 }
216
217 struct egl_g3d_create_surface_arg {
218 EGLint type;
219 union {
220 EGLNativeWindowType win;
221 EGLNativePixmapType pix;
222 } u;
223 };
224
225 static _EGLSurface *
226 egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
227 struct egl_g3d_create_surface_arg *arg,
228 const EGLint *attribs)
229 {
230 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
231 struct egl_g3d_config *gconf = egl_g3d_config(conf);
232 struct egl_g3d_surface *gsurf;
233 struct native_surface *nsurf;
234 const char *err;
235
236 switch (arg->type) {
237 case EGL_WINDOW_BIT:
238 err = "eglCreateWindowSurface";
239 break;
240 case EGL_PIXMAP_BIT:
241 err = "eglCreatePixmapSurface";
242 break;
243 #ifdef EGL_MESA_screen_surface
244 case EGL_SCREEN_BIT_MESA:
245 err = "eglCreateScreenSurface";
246 break;
247 #endif
248 default:
249 err = "eglCreateUnknownSurface";
250 break;
251 }
252
253 gsurf = CALLOC_STRUCT(egl_g3d_surface);
254 if (!gsurf) {
255 _eglError(EGL_BAD_ALLOC, err);
256 return NULL;
257 }
258
259 if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
260 FREE(gsurf);
261 return NULL;
262 }
263
264 /* create the native surface */
265 switch (arg->type) {
266 case EGL_WINDOW_BIT:
267 nsurf = gdpy->native->create_window_surface(gdpy->native,
268 arg->u.win, gconf->native);
269 break;
270 case EGL_PIXMAP_BIT:
271 nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
272 arg->u.pix, gconf->native);
273 break;
274 #ifdef EGL_MESA_screen_surface
275 case EGL_SCREEN_BIT_MESA:
276 /* prefer back buffer (move to _eglInitSurface?) */
277 gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
278 nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
279 gconf->native, gsurf->base.Width, gsurf->base.Height);
280 break;
281 #endif
282 default:
283 nsurf = NULL;
284 break;
285 }
286
287 if (!nsurf) {
288 FREE(gsurf);
289 return NULL;
290 }
291 /* initialize the geometry */
292 if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
293 &gsurf->base.Width, &gsurf->base.Height)) {
294 nsurf->destroy(nsurf);
295 FREE(gsurf);
296 return NULL;
297 }
298
299 gsurf->stvis = gconf->stvis;
300 if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER &&
301 gconf->stvis.buffer_mask & ST_ATTACHMENT_FRONT_LEFT_MASK)
302 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
303
304 /* surfaces can always be posted when the display supports it */
305 if (dpy->Extensions.NV_post_sub_buffer)
306 gsurf->base.PostSubBufferSupportedNV = EGL_TRUE;
307
308 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
309 if (!gsurf->stfbi) {
310 nsurf->destroy(nsurf);
311 FREE(gsurf);
312 return NULL;
313 }
314
315 nsurf->user_data = &gsurf->base;
316 gsurf->native = nsurf;
317
318 return &gsurf->base;
319 }
320
321 static _EGLSurface *
322 egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
323 _EGLConfig *conf, EGLNativeWindowType win,
324 const EGLint *attribs)
325 {
326 struct egl_g3d_create_surface_arg arg;
327
328 memset(&arg, 0, sizeof(arg));
329 arg.type = EGL_WINDOW_BIT;
330 arg.u.win = win;
331
332 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
333 }
334
335 static _EGLSurface *
336 egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
337 _EGLConfig *conf, EGLNativePixmapType pix,
338 const EGLint *attribs)
339 {
340 struct egl_g3d_create_surface_arg arg;
341
342 memset(&arg, 0, sizeof(arg));
343 arg.type = EGL_PIXMAP_BIT;
344 arg.u.pix = pix;
345
346 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
347 }
348
349 static struct egl_g3d_surface *
350 create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
351 const EGLint *attribs, const char *func)
352 {
353 struct egl_g3d_config *gconf = egl_g3d_config(conf);
354 struct egl_g3d_surface *gsurf;
355
356 gsurf = CALLOC_STRUCT(egl_g3d_surface);
357 if (!gsurf) {
358 _eglError(EGL_BAD_ALLOC, func);
359 return NULL;
360 }
361
362 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
363 FREE(gsurf);
364 return NULL;
365 }
366
367 gsurf->stvis = gconf->stvis;
368
369 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
370 if (!gsurf->stfbi) {
371 FREE(gsurf);
372 return NULL;
373 }
374
375 return gsurf;
376 }
377
378 static _EGLSurface *
379 egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
380 _EGLConfig *conf, const EGLint *attribs)
381 {
382 struct egl_g3d_surface *gsurf;
383
384 gsurf = create_pbuffer_surface(dpy, conf, attribs,
385 "eglCreatePbufferSurface");
386 if (!gsurf)
387 return NULL;
388
389 gsurf->client_buffer_type = EGL_NONE;
390
391 return &gsurf->base;
392 }
393
394 static _EGLSurface *
395 egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
396 EGLenum buftype,
397 EGLClientBuffer buffer,
398 _EGLConfig *conf,
399 const EGLint *attribs)
400 {
401 struct egl_g3d_surface *gsurf;
402 struct pipe_resource *ptex = NULL;
403 EGLint pbuffer_attribs[32];
404 EGLint count, i;
405
406 switch (buftype) {
407 case EGL_OPENVG_IMAGE:
408 break;
409 default:
410 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
411 return NULL;
412 break;
413 }
414
415 /* parse the attributes first */
416 count = 0;
417 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
418 EGLint attr = attribs[i++];
419 EGLint val = attribs[i];
420 EGLint err = EGL_SUCCESS;
421
422 switch (attr) {
423 case EGL_TEXTURE_FORMAT:
424 case EGL_TEXTURE_TARGET:
425 case EGL_MIPMAP_TEXTURE:
426 pbuffer_attribs[count++] = attr;
427 pbuffer_attribs[count++] = val;
428 break;
429 default:
430 err = EGL_BAD_ATTRIBUTE;
431 break;
432 }
433 /* bail out */
434 if (err != EGL_SUCCESS) {
435 _eglError(err, "eglCreatePbufferFromClientBuffer");
436 return NULL;
437 }
438 }
439
440 pbuffer_attribs[count++] = EGL_NONE;
441
442 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
443 "eglCreatePbufferFromClientBuffer");
444 if (!gsurf)
445 return NULL;
446
447 gsurf->client_buffer_type = buftype;
448 gsurf->client_buffer = buffer;
449
450 /* validate now so that it fails if the client buffer is invalid */
451 if (!gsurf->stfbi->validate(gsurf->stfbi,
452 &gsurf->stvis.render_buffer, 1, &ptex)) {
453 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
454 FREE(gsurf);
455 return NULL;
456 }
457 pipe_resource_reference(&ptex, NULL);
458
459 return &gsurf->base;
460 }
461
462 /**
463 * Destroy a surface.
464 */
465 static void
466 destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
467 {
468 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
469
470 /* FIXME a surface might live longer than its display */
471 if (!dpy->Initialized)
472 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
473
474 pipe_resource_reference(&gsurf->render_texture, NULL);
475 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
476 if (gsurf->native)
477 gsurf->native->destroy(gsurf->native);
478 FREE(gsurf);
479 }
480
481 static EGLBoolean
482 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
483 {
484 if (_eglPutSurface(surf))
485 destroy_surface(dpy, surf);
486 return EGL_TRUE;
487 }
488
489 static EGLBoolean
490 egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
491 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
492 {
493 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
494 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
495 struct egl_g3d_surface *gread = egl_g3d_surface(read);
496 struct egl_g3d_context *old_gctx;
497 _EGLContext *old_ctx;
498 _EGLSurface *old_draw, *old_read;
499 EGLBoolean ok = EGL_TRUE;
500
501 /* make new bindings */
502 if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
503 return EGL_FALSE;
504
505 old_gctx = egl_g3d_context(old_ctx);
506 if (old_gctx) {
507 /* flush old context */
508 old_gctx->stctxi->flush(old_gctx->stctxi, ST_FLUSH_FRONT, NULL);
509 }
510
511 if (gctx) {
512 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
513 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
514 if (ok) {
515 if (gdraw) {
516 if (gdraw->base.Type == EGL_WINDOW_BIT) {
517 gctx->base.WindowRenderBuffer =
518 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
519 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
520 }
521 }
522 }
523 }
524 else if (old_gctx) {
525 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
526 if (ok)
527 old_gctx->base.WindowRenderBuffer = EGL_NONE;
528 }
529
530 if (ok) {
531 if (_eglPutContext(old_ctx))
532 destroy_context(dpy, old_ctx);
533 if (_eglPutSurface(old_draw))
534 destroy_surface(dpy, old_draw);
535 if (_eglPutSurface(old_read))
536 destroy_surface(dpy, old_read);
537 }
538 else {
539 /* undo the previous _eglBindContext */
540 _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
541 assert(&gctx->base == ctx &&
542 &gdraw->base == draw &&
543 &gread->base == read);
544
545 _eglPutSurface(draw);
546 _eglPutSurface(read);
547 _eglPutContext(ctx);
548
549 _eglPutSurface(old_draw);
550 _eglPutSurface(old_read);
551 _eglPutContext(old_ctx);
552 }
553
554 return ok;
555 }
556
557 static EGLBoolean
558 swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
559 EGLint num_rects, const EGLint *rects, EGLBoolean preserve)
560 {
561 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
562 _EGLContext *ctx = _eglGetCurrentContext();
563 struct egl_g3d_context *gctx = NULL;
564 struct native_present_control ctrl;
565
566 /* no-op for pixmap or pbuffer surface */
567 if (gsurf->base.Type == EGL_PIXMAP_BIT ||
568 gsurf->base.Type == EGL_PBUFFER_BIT)
569 return EGL_TRUE;
570
571 /* or when the surface is single-buffered */
572 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
573 return EGL_TRUE;
574
575 if (ctx && ctx->DrawSurface == surf)
576 gctx = egl_g3d_context(ctx);
577
578 /* flush if the surface is current */
579 if (gctx) {
580 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
581 }
582
583 memset(&ctrl, 0, sizeof(ctrl));
584 ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT;
585 ctrl.preserve = preserve;
586 ctrl.swap_interval = gsurf->base.SwapInterval;
587 ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE);
588 ctrl.num_rects = num_rects;
589 ctrl.rects = rects;
590
591 return gsurf->native->present(gsurf->native, &ctrl);
592 }
593
594 static EGLBoolean
595 egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
596 {
597 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
598
599 return swap_buffers(drv, dpy, surf, 0, NULL,
600 (gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED));
601 }
602
603 #ifdef EGL_NOK_swap_region
604 static EGLBoolean
605 egl_g3d_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
606 EGLint num_rects, const EGLint *rects)
607 {
608 /* Note: y=0=top */
609 return swap_buffers(drv, dpy, surf, num_rects, rects, EGL_TRUE);
610 }
611 #endif /* EGL_NOK_swap_region */
612
613 static EGLBoolean
614 egl_g3d_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
615 EGLint x, EGLint y, EGLint width, EGLint height)
616 {
617 EGLint rect[4];
618
619 if (x < 0 || y < 0 || width < 0 || height < 0)
620 return _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
621
622 /* clamp */
623 if (x + width > surf->Width)
624 width = surf->Width - x;
625 if (y + height > surf->Height)
626 height = surf->Height - y;
627
628 if (width <= 0 || height <= 0)
629 return EGL_TRUE;
630
631 rect[0] = x;
632 /* Note: y=0=bottom */
633 rect[1] = surf->Height - y - height;
634 rect[2] = width;
635 rect[3] = height;
636
637 return swap_buffers(drv, dpy, surf, 1, rect, EGL_TRUE);
638 }
639
640 static EGLBoolean
641 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
642 EGLNativePixmapType target)
643 {
644 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
645 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
646 _EGLContext *ctx = _eglGetCurrentContext();
647
648 if (!gsurf->render_texture)
649 return EGL_TRUE;
650
651 /* flush if the surface is current */
652 if (ctx && ctx->DrawSurface == &gsurf->base) {
653 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
654 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
655 }
656
657 return gdpy->native->copy_to_pixmap(gdpy->native,
658 target, gsurf->render_texture);
659 }
660
661 static EGLBoolean
662 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
663 {
664 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
665 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
666 struct pipe_screen *screen = gdpy->native->screen;
667 struct pipe_fence_handle *fence = NULL;
668
669 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence);
670 if (fence) {
671 screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
672 screen->fence_reference(screen, &fence, NULL);
673 }
674
675 return EGL_TRUE;
676 }
677
678 static EGLBoolean
679 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
680 {
681 _EGLContext *ctx = _eglGetCurrentContext();
682
683 if (engine != EGL_CORE_NATIVE_ENGINE)
684 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
685
686 if (ctx && ctx->DrawSurface) {
687 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
688
689 if (gsurf->native)
690 gsurf->native->wait(gsurf->native);
691 }
692
693 return EGL_TRUE;
694 }
695
696 static EGLBoolean
697 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
698 _EGLSurface *surf, EGLint buffer)
699 {
700 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
701 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
702 struct egl_g3d_context *gctx;
703 enum pipe_format internal_format;
704 enum st_texture_type target;
705
706 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
707 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
708 if (buffer != EGL_BACK_BUFFER)
709 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
710 if (gsurf->base.BoundToTexture)
711 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
712
713 switch (gsurf->base.TextureFormat) {
714 case EGL_TEXTURE_RGB:
715 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
716 break;
717 case EGL_TEXTURE_RGBA:
718 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
719 break;
720 default:
721 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
722 }
723
724 switch (gsurf->base.TextureTarget) {
725 case EGL_TEXTURE_2D:
726 target = ST_TEXTURE_2D;
727 break;
728 default:
729 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
730 }
731
732 if (!es1)
733 return EGL_TRUE;
734 if (!gsurf->render_texture)
735 return EGL_FALSE;
736
737 /* flush properly if the surface is bound */
738 if (gsurf->base.CurrentContext) {
739 gctx = egl_g3d_context(gsurf->base.CurrentContext);
740 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
741 }
742
743 gctx = egl_g3d_context(es1);
744 if (gctx->stctxi->teximage) {
745 if (!gctx->stctxi->teximage(gctx->stctxi, target,
746 gsurf->base.MipmapLevel, internal_format,
747 gsurf->render_texture, gsurf->base.MipmapTexture))
748 return EGL_FALSE;
749 gsurf->base.BoundToTexture = EGL_TRUE;
750 }
751
752 return EGL_TRUE;
753 }
754
755 static EGLBoolean
756 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
757 _EGLSurface *surf, EGLint buffer)
758 {
759 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
760
761 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
762 !gsurf->base.BoundToTexture)
763 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
764 if (buffer != EGL_BACK_BUFFER)
765 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
766
767 if (gsurf->render_texture) {
768 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
769 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
770
771 /* what if the context the surface binds to is no longer current? */
772 if (gctx) {
773 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
774 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
775 }
776 }
777
778 gsurf->base.BoundToTexture = EGL_FALSE;
779
780 return EGL_TRUE;
781 }
782
783 #ifdef EGL_MESA_screen_surface
784
785 static _EGLSurface *
786 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
787 _EGLConfig *conf, const EGLint *attribs)
788 {
789 struct egl_g3d_create_surface_arg arg;
790
791 memset(&arg, 0, sizeof(arg));
792 arg.type = EGL_SCREEN_BIT_MESA;
793
794 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
795 }
796
797 static EGLBoolean
798 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
799 _EGLScreen *scr, _EGLSurface *surf,
800 _EGLMode *mode)
801 {
802 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
803 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
804 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
805 struct native_surface *nsurf;
806 const struct native_mode *nmode;
807 EGLBoolean changed;
808
809 if (gsurf) {
810 EGLint idx;
811
812 if (!mode)
813 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
814 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
815 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
816 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
817 return _eglError(EGL_BAD_MATCH,
818 "eglShowSurfaceMESA(surface smaller than mode size)");
819
820 /* find the index of the mode */
821 for (idx = 0; idx < gscr->base.NumModes; idx++)
822 if (mode == &gscr->base.Modes[idx])
823 break;
824 if (idx >= gscr->base.NumModes) {
825 return _eglError(EGL_BAD_MODE_MESA,
826 "eglShowSurfaceMESA(unknown mode)");
827 }
828
829 nsurf = gsurf->native;
830 nmode = gscr->native_modes[idx];
831 }
832 else {
833 if (mode)
834 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
835
836 /* disable the screen */
837 nsurf = NULL;
838 nmode = NULL;
839 }
840
841 /* TODO surface panning by CRTC choosing */
842 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
843 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
844 if (changed) {
845 gscr->base.CurrentSurface = &gsurf->base;
846 gscr->base.CurrentMode = mode;
847 }
848
849 return changed;
850 }
851
852 #endif /* EGL_MESA_screen_surface */
853
854 #ifdef EGL_WL_bind_wayland_display
855
856 static EGLBoolean
857 egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
858 struct wl_display *wl_dpy)
859 {
860 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
861
862 if (!gdpy->native->wayland_bufmgr)
863 return EGL_FALSE;
864
865 return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy);
866 }
867
868 static EGLBoolean
869 egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
870 struct wl_display *wl_dpy)
871 {
872 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
873
874 if (!gdpy->native->wayland_bufmgr)
875 return EGL_FALSE;
876
877 return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy);
878 }
879
880 static EGLBoolean
881 egl_g3d_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *dpy,
882 struct wl_buffer *_buffer,
883 EGLint attribute, EGLint *value)
884 {
885 struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
886 struct pipe_resource *resource = buffer->driver_buffer;
887
888 if (!wayland_buffer_is_drm(&buffer->buffer))
889 return EGL_FALSE;
890
891 switch (attribute) {
892 case EGL_TEXTURE_FORMAT:
893 switch (resource->format) {
894 case PIPE_FORMAT_B8G8R8A8_UNORM:
895 *value = EGL_TEXTURE_RGBA;
896 return EGL_TRUE;
897 case PIPE_FORMAT_B8G8R8X8_UNORM:
898 *value = EGL_TEXTURE_RGB;
899 return EGL_TRUE;
900 default:
901 return EGL_FALSE;
902 }
903 case EGL_WIDTH:
904 *value = buffer->buffer.width;
905 return EGL_TRUE;
906 case EGL_HEIGHT:
907 *value = buffer->buffer.height;
908 return EGL_TRUE;
909 default:
910 return EGL_FALSE;
911 }
912 }
913 #endif /* EGL_WL_bind_wayland_display */
914
915 void
916 egl_g3d_init_driver_api(_EGLDriver *drv)
917 {
918 _eglInitDriverFallbacks(drv);
919
920 drv->API.ChooseConfig = egl_g3d_choose_config;
921
922 drv->API.CreateContext = egl_g3d_create_context;
923 drv->API.DestroyContext = egl_g3d_destroy_context;
924 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
925 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
926 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
927 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
928 drv->API.DestroySurface = egl_g3d_destroy_surface;
929 drv->API.MakeCurrent = egl_g3d_make_current;
930 drv->API.SwapBuffers = egl_g3d_swap_buffers;
931 drv->API.CopyBuffers = egl_g3d_copy_buffers;
932 drv->API.WaitClient = egl_g3d_wait_client;
933 drv->API.WaitNative = egl_g3d_wait_native;
934
935 drv->API.BindTexImage = egl_g3d_bind_tex_image;
936 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
937
938 drv->API.CreateImageKHR = egl_g3d_create_image;
939 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
940 #ifdef EGL_MESA_drm_image
941 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
942 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
943 #endif
944 #ifdef EGL_WL_bind_wayland_display
945 drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl;
946 drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl;
947 drv->API.QueryWaylandBufferWL = egl_g3d_query_wayland_buffer_wl;
948 #endif
949
950 drv->API.CreateSyncKHR = egl_g3d_create_sync;
951 drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
952 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
953 drv->API.SignalSyncKHR = egl_g3d_signal_sync;
954
955 #ifdef EGL_MESA_screen_surface
956 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
957 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
958 #endif
959
960 #ifdef EGL_NOK_swap_region
961 drv->API.SwapBuffersRegionNOK = egl_g3d_swap_buffers_region;
962 #endif
963
964 drv->API.PostSubBufferNV = egl_g3d_post_sub_buffer;
965 }