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