st/egl: overload NATIVE_PARAM_PREMULTIPLIED_ALPHA
[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 /**
43 * Return the state tracker for the given context.
44 */
45 static struct st_api *
46 egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx,
47 enum st_profile_type *profile)
48 {
49 struct st_api *stapi;
50 EGLint api = -1;
51
52 *profile = ST_PROFILE_DEFAULT;
53
54 switch (ctx->ClientAPI) {
55 case EGL_OPENGL_ES_API:
56 switch (ctx->ClientVersion) {
57 case 1:
58 api = ST_API_OPENGL;
59 *profile = ST_PROFILE_OPENGL_ES1;
60 break;
61 case 2:
62 api = ST_API_OPENGL;
63 *profile = ST_PROFILE_OPENGL_ES2;
64 break;
65 default:
66 _eglLog(_EGL_WARNING, "unknown client version %d",
67 ctx->ClientVersion);
68 break;
69 }
70 break;
71 case EGL_OPENVG_API:
72 api = ST_API_OPENVG;
73 break;
74 case EGL_OPENGL_API:
75 api = ST_API_OPENGL;
76 break;
77 default:
78 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
79 break;
80 }
81
82 stapi = egl_g3d_get_st_api(drv, api);
83 if (stapi && !(stapi->profile_mask & (1 << *profile)))
84 stapi = NULL;
85
86 return stapi;
87 }
88
89 struct egl_g3d_choose_config_data {
90 _EGLConfig criteria;
91 enum pipe_format format;
92 };
93
94 static int
95 egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2,
96 void *priv_data)
97 {
98 struct egl_g3d_choose_config_data *data =
99 (struct egl_g3d_choose_config_data *) priv_data;
100 const _EGLConfig *criteria = &data->criteria;;
101
102 /* EGL_NATIVE_VISUAL_TYPE ignored? */
103 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
104 }
105
106 static EGLBoolean
107 egl_g3d_match_config(const _EGLConfig *conf, void *priv_data)
108 {
109 struct egl_g3d_choose_config_data *data =
110 (struct egl_g3d_choose_config_data *) priv_data;
111 struct egl_g3d_config *gconf = egl_g3d_config(conf);
112
113 if (data->format != PIPE_FORMAT_NONE &&
114 data->format != gconf->native->color_format)
115 return EGL_FALSE;
116
117 return _eglMatchConfig(conf, &data->criteria);
118 }
119
120 static EGLBoolean
121 egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs,
122 EGLConfig *configs, EGLint size, EGLint *num_configs)
123 {
124 struct egl_g3d_choose_config_data data;
125
126 if (!_eglParseConfigAttribList(&data.criteria, dpy, attribs))
127 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
128
129 data.format = PIPE_FORMAT_NONE;
130 if (data.criteria.MatchNativePixmap != EGL_NONE &&
131 data.criteria.MatchNativePixmap != EGL_DONT_CARE) {
132 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
133
134 if (!gdpy->native->get_pixmap_format(gdpy->native,
135 (EGLNativePixmapType) data.criteria.MatchNativePixmap,
136 &data.format))
137 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglChooseConfig");
138 }
139
140 return _eglFilterConfigArray(dpy->Configs, configs, size, num_configs,
141 egl_g3d_match_config, egl_g3d_compare_config, &data);
142 }
143
144 static _EGLContext *
145 egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
146 _EGLContext *share, const EGLint *attribs)
147 {
148 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
149 struct egl_g3d_context *gshare = egl_g3d_context(share);
150 struct egl_g3d_config *gconf = egl_g3d_config(conf);
151 struct egl_g3d_context *gctx;
152 struct st_context_attribs stattribs;
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, (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 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
300 if (!gsurf->stfbi) {
301 nsurf->destroy(nsurf);
302 FREE(gsurf);
303 return NULL;
304 }
305
306 nsurf->user_data = &gsurf->base;
307 gsurf->native = nsurf;
308
309 return &gsurf->base;
310 }
311
312 static _EGLSurface *
313 egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
314 _EGLConfig *conf, EGLNativeWindowType win,
315 const EGLint *attribs)
316 {
317 struct egl_g3d_create_surface_arg arg;
318
319 memset(&arg, 0, sizeof(arg));
320 arg.type = EGL_WINDOW_BIT;
321 arg.u.win = win;
322
323 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
324 }
325
326 static _EGLSurface *
327 egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
328 _EGLConfig *conf, EGLNativePixmapType pix,
329 const EGLint *attribs)
330 {
331 struct egl_g3d_create_surface_arg arg;
332
333 memset(&arg, 0, sizeof(arg));
334 arg.type = EGL_PIXMAP_BIT;
335 arg.u.pix = pix;
336
337 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
338 }
339
340 static struct egl_g3d_surface *
341 create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
342 const EGLint *attribs, const char *func)
343 {
344 struct egl_g3d_config *gconf = egl_g3d_config(conf);
345 struct egl_g3d_surface *gsurf;
346
347 gsurf = CALLOC_STRUCT(egl_g3d_surface);
348 if (!gsurf) {
349 _eglError(EGL_BAD_ALLOC, func);
350 return NULL;
351 }
352
353 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
354 FREE(gsurf);
355 return NULL;
356 }
357
358 gsurf->stvis = gconf->stvis;
359
360 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
361 if (!gsurf->stfbi) {
362 FREE(gsurf);
363 return NULL;
364 }
365
366 return gsurf;
367 }
368
369 static _EGLSurface *
370 egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
371 _EGLConfig *conf, const EGLint *attribs)
372 {
373 struct egl_g3d_surface *gsurf;
374
375 gsurf = create_pbuffer_surface(dpy, conf, attribs,
376 "eglCreatePbufferSurface");
377 if (!gsurf)
378 return NULL;
379
380 gsurf->client_buffer_type = EGL_NONE;
381
382 return &gsurf->base;
383 }
384
385 static _EGLSurface *
386 egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
387 EGLenum buftype,
388 EGLClientBuffer buffer,
389 _EGLConfig *conf,
390 const EGLint *attribs)
391 {
392 struct egl_g3d_surface *gsurf;
393 struct pipe_resource *ptex = NULL;
394 EGLint pbuffer_attribs[32];
395 EGLint count, i;
396
397 switch (buftype) {
398 case EGL_OPENVG_IMAGE:
399 break;
400 default:
401 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
402 return NULL;
403 break;
404 }
405
406 /* parse the attributes first */
407 count = 0;
408 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
409 EGLint attr = attribs[i++];
410 EGLint val = attribs[i];
411 EGLint err = EGL_SUCCESS;
412
413 switch (attr) {
414 case EGL_TEXTURE_FORMAT:
415 case EGL_TEXTURE_TARGET:
416 case EGL_MIPMAP_TEXTURE:
417 pbuffer_attribs[count++] = attr;
418 pbuffer_attribs[count++] = val;
419 break;
420 default:
421 err = EGL_BAD_ATTRIBUTE;
422 break;
423 }
424 /* bail out */
425 if (err != EGL_SUCCESS) {
426 _eglError(err, "eglCreatePbufferFromClientBuffer");
427 return NULL;
428 }
429 }
430
431 pbuffer_attribs[count++] = EGL_NONE;
432
433 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
434 "eglCreatePbufferFromClientBuffer");
435 if (!gsurf)
436 return NULL;
437
438 gsurf->client_buffer_type = buftype;
439 gsurf->client_buffer = buffer;
440
441 /* validate now so that it fails if the client buffer is invalid */
442 if (!gsurf->stfbi->validate(gsurf->stfbi,
443 &gsurf->stvis.render_buffer, 1, &ptex)) {
444 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
445 FREE(gsurf);
446 return NULL;
447 }
448 pipe_resource_reference(&ptex, NULL);
449
450 return &gsurf->base;
451 }
452
453 /**
454 * Destroy a surface.
455 */
456 static void
457 destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
458 {
459 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
460
461 /* FIXME a surface might live longer than its display */
462 if (!dpy->Initialized)
463 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
464
465 pipe_resource_reference(&gsurf->render_texture, NULL);
466 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
467 if (gsurf->native)
468 gsurf->native->destroy(gsurf->native);
469 FREE(gsurf);
470 }
471
472 static EGLBoolean
473 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
474 {
475 if (_eglPutSurface(surf))
476 destroy_surface(dpy, surf);
477 return EGL_TRUE;
478 }
479
480 static EGLBoolean
481 egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
482 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
483 {
484 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
485 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
486 struct egl_g3d_surface *gread = egl_g3d_surface(read);
487 struct egl_g3d_context *old_gctx;
488 _EGLContext *old_ctx;
489 _EGLSurface *old_draw, *old_read;
490 EGLBoolean ok = EGL_TRUE;
491
492 /* make new bindings */
493 if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
494 return EGL_FALSE;
495
496 old_gctx = egl_g3d_context(old_ctx);
497 if (old_gctx) {
498 /* flush old context */
499 old_gctx->stctxi->flush(old_gctx->stctxi, ST_FLUSH_FRONT, NULL);
500 }
501
502 if (gctx) {
503 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
504 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
505 if (ok) {
506 if (gdraw) {
507 if (gdraw->base.Type == EGL_WINDOW_BIT) {
508 gctx->base.WindowRenderBuffer =
509 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
510 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
511 }
512 }
513 }
514 }
515 else if (old_gctx) {
516 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
517 if (ok)
518 old_gctx->base.WindowRenderBuffer = EGL_NONE;
519 }
520
521 if (ok) {
522 if (_eglPutContext(old_ctx))
523 destroy_context(dpy, old_ctx);
524 if (_eglPutSurface(old_draw))
525 destroy_surface(dpy, old_draw);
526 if (_eglPutSurface(old_read))
527 destroy_surface(dpy, old_read);
528 }
529 else {
530 /* undo the previous _eglBindContext */
531 _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
532 assert(&gctx->base == ctx &&
533 &gdraw->base == draw &&
534 &gread->base == read);
535
536 _eglPutSurface(draw);
537 _eglPutSurface(read);
538 _eglPutContext(ctx);
539
540 _eglPutSurface(old_draw);
541 _eglPutSurface(old_read);
542 _eglPutContext(old_ctx);
543 }
544
545 return ok;
546 }
547
548 static EGLBoolean
549 egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
550 {
551 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
552 _EGLContext *ctx = _eglGetCurrentContext();
553 struct egl_g3d_context *gctx = NULL;
554 struct native_present_control ctrl;
555
556 /* no-op for pixmap or pbuffer surface */
557 if (gsurf->base.Type == EGL_PIXMAP_BIT ||
558 gsurf->base.Type == EGL_PBUFFER_BIT)
559 return EGL_TRUE;
560
561 /* or when the surface is single-buffered */
562 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
563 return EGL_TRUE;
564
565 if (ctx && ctx->DrawSurface == surf)
566 gctx = egl_g3d_context(ctx);
567
568 /* flush if the surface is current */
569 if (gctx) {
570 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
571 }
572
573 memset(&ctrl, 0, sizeof(ctrl));
574 ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT;
575 ctrl.preserve = (gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED);
576 ctrl.swap_interval = gsurf->base.SwapInterval;
577 ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE);
578
579 return gsurf->native->present(gsurf->native, &ctrl);
580 }
581
582 static EGLBoolean
583 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
584 EGLNativePixmapType target)
585 {
586 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
587 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
588 _EGLContext *ctx = _eglGetCurrentContext();
589
590 if (!gsurf->render_texture)
591 return EGL_TRUE;
592
593 /* flush if the surface is current */
594 if (ctx && ctx->DrawSurface == &gsurf->base) {
595 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
596 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
597 }
598
599 return gdpy->native->copy_to_pixmap(gdpy->native,
600 target, gsurf->render_texture);
601 }
602
603 static EGLBoolean
604 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
605 {
606 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
607 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
608 struct pipe_screen *screen = gdpy->native->screen;
609 struct pipe_fence_handle *fence = NULL;
610
611 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence);
612 if (fence) {
613 screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
614 screen->fence_reference(screen, &fence, NULL);
615 }
616
617 return EGL_TRUE;
618 }
619
620 static EGLBoolean
621 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
622 {
623 _EGLContext *ctx = _eglGetCurrentContext();
624
625 if (engine != EGL_CORE_NATIVE_ENGINE)
626 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
627
628 if (ctx && ctx->DrawSurface) {
629 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
630
631 if (gsurf->native)
632 gsurf->native->wait(gsurf->native);
633 }
634
635 return EGL_TRUE;
636 }
637
638 static EGLBoolean
639 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
640 _EGLSurface *surf, EGLint buffer)
641 {
642 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
643 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
644 struct egl_g3d_context *gctx;
645 enum pipe_format internal_format;
646 enum st_texture_type target;
647
648 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
649 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
650 if (buffer != EGL_BACK_BUFFER)
651 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
652 if (gsurf->base.BoundToTexture)
653 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
654
655 switch (gsurf->base.TextureFormat) {
656 case EGL_TEXTURE_RGB:
657 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
658 break;
659 case EGL_TEXTURE_RGBA:
660 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
661 break;
662 default:
663 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
664 }
665
666 switch (gsurf->base.TextureTarget) {
667 case EGL_TEXTURE_2D:
668 target = ST_TEXTURE_2D;
669 break;
670 default:
671 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
672 }
673
674 if (!es1)
675 return EGL_TRUE;
676 if (!gsurf->render_texture)
677 return EGL_FALSE;
678
679 /* flush properly if the surface is bound */
680 if (gsurf->base.CurrentContext) {
681 gctx = egl_g3d_context(gsurf->base.CurrentContext);
682 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
683 }
684
685 gctx = egl_g3d_context(es1);
686 if (gctx->stctxi->teximage) {
687 if (!gctx->stctxi->teximage(gctx->stctxi, target,
688 gsurf->base.MipmapLevel, internal_format,
689 gsurf->render_texture, gsurf->base.MipmapTexture))
690 return EGL_FALSE;
691 gsurf->base.BoundToTexture = EGL_TRUE;
692 }
693
694 return EGL_TRUE;
695 }
696
697 static EGLBoolean
698 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
699 _EGLSurface *surf, EGLint buffer)
700 {
701 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
702
703 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
704 !gsurf->base.BoundToTexture)
705 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
706 if (buffer != EGL_BACK_BUFFER)
707 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
708
709 if (gsurf->render_texture) {
710 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
711 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
712
713 /* what if the context the surface binds to is no longer current? */
714 if (gctx) {
715 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
716 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
717 }
718 }
719
720 gsurf->base.BoundToTexture = EGL_FALSE;
721
722 return EGL_TRUE;
723 }
724
725 #ifdef EGL_MESA_screen_surface
726
727 static _EGLSurface *
728 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
729 _EGLConfig *conf, const EGLint *attribs)
730 {
731 struct egl_g3d_create_surface_arg arg;
732
733 memset(&arg, 0, sizeof(arg));
734 arg.type = EGL_SCREEN_BIT_MESA;
735
736 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
737 }
738
739 static EGLBoolean
740 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
741 _EGLScreen *scr, _EGLSurface *surf,
742 _EGLMode *mode)
743 {
744 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
745 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
746 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
747 struct native_surface *nsurf;
748 const struct native_mode *nmode;
749 EGLBoolean changed;
750
751 if (gsurf) {
752 EGLint idx;
753
754 if (!mode)
755 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
756 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
757 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
758 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
759 return _eglError(EGL_BAD_MATCH,
760 "eglShowSurfaceMESA(surface smaller than mode size)");
761
762 /* find the index of the mode */
763 for (idx = 0; idx < gscr->base.NumModes; idx++)
764 if (mode == &gscr->base.Modes[idx])
765 break;
766 if (idx >= gscr->base.NumModes) {
767 return _eglError(EGL_BAD_MODE_MESA,
768 "eglShowSurfaceMESA(unknown mode)");
769 }
770
771 nsurf = gsurf->native;
772 nmode = gscr->native_modes[idx];
773 }
774 else {
775 if (mode)
776 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
777
778 /* disable the screen */
779 nsurf = NULL;
780 nmode = NULL;
781 }
782
783 /* TODO surface panning by CRTC choosing */
784 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
785 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
786 if (changed) {
787 gscr->base.CurrentSurface = &gsurf->base;
788 gscr->base.CurrentMode = mode;
789 }
790
791 return changed;
792 }
793
794 #endif /* EGL_MESA_screen_surface */
795
796 #ifdef EGL_WL_bind_wayland_display
797
798 static EGLBoolean
799 egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
800 struct wl_display *wl_dpy)
801 {
802 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
803
804 if (!gdpy->native->wayland_bufmgr)
805 return EGL_FALSE;
806
807 return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy);
808 }
809
810 static EGLBoolean
811 egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
812 struct wl_display *wl_dpy)
813 {
814 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
815
816 if (!gdpy->native->wayland_bufmgr)
817 return EGL_FALSE;
818
819 return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy);
820 }
821
822 #endif /* EGL_WL_bind_wayland_display */
823
824 void
825 egl_g3d_init_driver_api(_EGLDriver *drv)
826 {
827 _eglInitDriverFallbacks(drv);
828
829 drv->API.ChooseConfig = egl_g3d_choose_config;
830
831 drv->API.CreateContext = egl_g3d_create_context;
832 drv->API.DestroyContext = egl_g3d_destroy_context;
833 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
834 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
835 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
836 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
837 drv->API.DestroySurface = egl_g3d_destroy_surface;
838 drv->API.MakeCurrent = egl_g3d_make_current;
839 drv->API.SwapBuffers = egl_g3d_swap_buffers;
840 drv->API.CopyBuffers = egl_g3d_copy_buffers;
841 drv->API.WaitClient = egl_g3d_wait_client;
842 drv->API.WaitNative = egl_g3d_wait_native;
843
844 drv->API.BindTexImage = egl_g3d_bind_tex_image;
845 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
846
847 drv->API.CreateImageKHR = egl_g3d_create_image;
848 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
849 #ifdef EGL_MESA_drm_image
850 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
851 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
852 #endif
853 #ifdef EGL_WL_bind_wayland_display
854 drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl;
855 drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl;
856
857 #endif
858
859 #ifdef EGL_KHR_reusable_sync
860 drv->API.CreateSyncKHR = egl_g3d_create_sync;
861 drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
862 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
863 drv->API.SignalSyncKHR = egl_g3d_signal_sync;
864 #endif
865
866 #ifdef EGL_MESA_screen_surface
867 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
868 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
869 #endif
870 }