st-api: Rework how drawables are invalidated v3.
[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
555 /* no-op for pixmap or pbuffer surface */
556 if (gsurf->base.Type == EGL_PIXMAP_BIT ||
557 gsurf->base.Type == EGL_PBUFFER_BIT)
558 return EGL_TRUE;
559
560 /* or when the surface is single-buffered */
561 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
562 return EGL_TRUE;
563
564 if (ctx && ctx->DrawSurface == surf)
565 gctx = egl_g3d_context(ctx);
566
567 /* flush if the surface is current */
568 if (gctx) {
569 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
570 }
571
572 return gsurf->native->present(gsurf->native,
573 NATIVE_ATTACHMENT_BACK_LEFT,
574 gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED,
575 gsurf->base.SwapInterval);
576 }
577
578 static EGLBoolean
579 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
580 EGLNativePixmapType target)
581 {
582 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
583 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
584 _EGLContext *ctx = _eglGetCurrentContext();
585
586 if (!gsurf->render_texture)
587 return EGL_TRUE;
588
589 /* flush if the surface is current */
590 if (ctx && ctx->DrawSurface == &gsurf->base) {
591 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
592 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
593 }
594
595 return gdpy->native->copy_to_pixmap(gdpy->native,
596 target, gsurf->render_texture);
597 }
598
599 static EGLBoolean
600 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
601 {
602 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
603 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
604 struct pipe_screen *screen = gdpy->native->screen;
605 struct pipe_fence_handle *fence = NULL;
606
607 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence);
608 if (fence) {
609 screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
610 screen->fence_reference(screen, &fence, NULL);
611 }
612
613 return EGL_TRUE;
614 }
615
616 static EGLBoolean
617 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
618 {
619 _EGLContext *ctx = _eglGetCurrentContext();
620
621 if (engine != EGL_CORE_NATIVE_ENGINE)
622 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
623
624 if (ctx && ctx->DrawSurface) {
625 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
626
627 if (gsurf->native)
628 gsurf->native->wait(gsurf->native);
629 }
630
631 return EGL_TRUE;
632 }
633
634 static EGLBoolean
635 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
636 _EGLSurface *surf, EGLint buffer)
637 {
638 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
639 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
640 struct egl_g3d_context *gctx;
641 enum pipe_format internal_format;
642 enum st_texture_type target;
643
644 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
645 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
646 if (buffer != EGL_BACK_BUFFER)
647 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
648 if (gsurf->base.BoundToTexture)
649 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
650
651 switch (gsurf->base.TextureFormat) {
652 case EGL_TEXTURE_RGB:
653 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
654 break;
655 case EGL_TEXTURE_RGBA:
656 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
657 break;
658 default:
659 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
660 }
661
662 switch (gsurf->base.TextureTarget) {
663 case EGL_TEXTURE_2D:
664 target = ST_TEXTURE_2D;
665 break;
666 default:
667 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
668 }
669
670 if (!es1)
671 return EGL_TRUE;
672 if (!gsurf->render_texture)
673 return EGL_FALSE;
674
675 /* flush properly if the surface is bound */
676 if (gsurf->base.CurrentContext) {
677 gctx = egl_g3d_context(gsurf->base.CurrentContext);
678 gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
679 }
680
681 gctx = egl_g3d_context(es1);
682 if (gctx->stctxi->teximage) {
683 if (!gctx->stctxi->teximage(gctx->stctxi, target,
684 gsurf->base.MipmapLevel, internal_format,
685 gsurf->render_texture, gsurf->base.MipmapTexture))
686 return EGL_FALSE;
687 gsurf->base.BoundToTexture = EGL_TRUE;
688 }
689
690 return EGL_TRUE;
691 }
692
693 static EGLBoolean
694 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
695 _EGLSurface *surf, EGLint buffer)
696 {
697 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
698
699 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
700 !gsurf->base.BoundToTexture)
701 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
702 if (buffer != EGL_BACK_BUFFER)
703 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
704
705 if (gsurf->render_texture) {
706 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
707 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
708
709 /* what if the context the surface binds to is no longer current? */
710 if (gctx) {
711 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
712 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
713 }
714 }
715
716 gsurf->base.BoundToTexture = EGL_FALSE;
717
718 return EGL_TRUE;
719 }
720
721 #ifdef EGL_MESA_screen_surface
722
723 static _EGLSurface *
724 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
725 _EGLConfig *conf, const EGLint *attribs)
726 {
727 struct egl_g3d_create_surface_arg arg;
728
729 memset(&arg, 0, sizeof(arg));
730 arg.type = EGL_SCREEN_BIT_MESA;
731
732 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
733 }
734
735 static EGLBoolean
736 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
737 _EGLScreen *scr, _EGLSurface *surf,
738 _EGLMode *mode)
739 {
740 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
741 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
742 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
743 struct native_surface *nsurf;
744 const struct native_mode *nmode;
745 EGLBoolean changed;
746
747 if (gsurf) {
748 EGLint idx;
749
750 if (!mode)
751 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
752 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
753 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
754 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
755 return _eglError(EGL_BAD_MATCH,
756 "eglShowSurfaceMESA(surface smaller than mode size)");
757
758 /* find the index of the mode */
759 for (idx = 0; idx < gscr->base.NumModes; idx++)
760 if (mode == &gscr->base.Modes[idx])
761 break;
762 if (idx >= gscr->base.NumModes) {
763 return _eglError(EGL_BAD_MODE_MESA,
764 "eglShowSurfaceMESA(unknown mode)");
765 }
766
767 nsurf = gsurf->native;
768 nmode = gscr->native_modes[idx];
769 }
770 else {
771 if (mode)
772 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
773
774 /* disable the screen */
775 nsurf = NULL;
776 nmode = NULL;
777 }
778
779 /* TODO surface panning by CRTC choosing */
780 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
781 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
782 if (changed) {
783 gscr->base.CurrentSurface = &gsurf->base;
784 gscr->base.CurrentMode = mode;
785 }
786
787 return changed;
788 }
789
790 #endif /* EGL_MESA_screen_surface */
791
792 #ifdef EGL_WL_bind_wayland_display
793
794 static EGLBoolean
795 egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
796 struct wl_display *wl_dpy)
797 {
798 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
799
800 if (!gdpy->native->wayland_bufmgr)
801 return EGL_FALSE;
802
803 return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy);
804 }
805
806 static EGLBoolean
807 egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
808 struct wl_display *wl_dpy)
809 {
810 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
811
812 if (!gdpy->native->wayland_bufmgr)
813 return EGL_FALSE;
814
815 return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy);
816 }
817
818 #endif /* EGL_WL_bind_wayland_display */
819
820 void
821 egl_g3d_init_driver_api(_EGLDriver *drv)
822 {
823 _eglInitDriverFallbacks(drv);
824
825 drv->API.ChooseConfig = egl_g3d_choose_config;
826
827 drv->API.CreateContext = egl_g3d_create_context;
828 drv->API.DestroyContext = egl_g3d_destroy_context;
829 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
830 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
831 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
832 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
833 drv->API.DestroySurface = egl_g3d_destroy_surface;
834 drv->API.MakeCurrent = egl_g3d_make_current;
835 drv->API.SwapBuffers = egl_g3d_swap_buffers;
836 drv->API.CopyBuffers = egl_g3d_copy_buffers;
837 drv->API.WaitClient = egl_g3d_wait_client;
838 drv->API.WaitNative = egl_g3d_wait_native;
839
840 drv->API.BindTexImage = egl_g3d_bind_tex_image;
841 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
842
843 drv->API.CreateImageKHR = egl_g3d_create_image;
844 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
845 #ifdef EGL_MESA_drm_image
846 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
847 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
848 #endif
849 #ifdef EGL_WL_bind_wayland_display
850 drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl;
851 drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl;
852
853 #endif
854
855 #ifdef EGL_KHR_reusable_sync
856 drv->API.CreateSyncKHR = egl_g3d_create_sync;
857 drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
858 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
859 drv->API.SignalSyncKHR = egl_g3d_signal_sync;
860 #endif
861
862 #ifdef EGL_MESA_screen_surface
863 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
864 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
865 #endif
866 }