egl: Store configs in a dynamic array.
[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
34 #include "egl_g3d.h"
35 #include "egl_g3d_api.h"
36 #include "egl_g3d_image.h"
37 #include "egl_g3d_st.h"
38 #include "egl_g3d_loader.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 {
47 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
48 EGLint idx = -1;
49
50 switch (ctx->ClientAPI) {
51 case EGL_OPENGL_ES_API:
52 switch (ctx->ClientVersion) {
53 case 1:
54 idx = ST_API_OPENGL_ES1;
55 break;
56 case 2:
57 idx = ST_API_OPENGL_ES2;
58 break;
59 default:
60 _eglLog(_EGL_WARNING, "unknown client version %d",
61 ctx->ClientVersion);
62 break;
63 }
64 break;
65 case EGL_OPENVG_API:
66 idx = ST_API_OPENVG;
67 break;
68 case EGL_OPENGL_API:
69 idx = ST_API_OPENGL;
70 break;
71 default:
72 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
73 break;
74 }
75
76 return (idx >= 0) ? gdrv->loader->get_st_api(idx) : NULL;
77 }
78
79 static _EGLContext *
80 egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
81 _EGLContext *share, const EGLint *attribs)
82 {
83 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
84 struct egl_g3d_context *gshare = egl_g3d_context(share);
85 struct egl_g3d_config *gconf = egl_g3d_config(conf);
86 struct egl_g3d_context *gctx;
87
88 gctx = CALLOC_STRUCT(egl_g3d_context);
89 if (!gctx) {
90 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
91 return NULL;
92 }
93
94 if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
95 FREE(gctx);
96 return NULL;
97 }
98
99 gctx->stapi = egl_g3d_choose_st(drv, &gctx->base);
100 if (!gctx->stapi) {
101 FREE(gctx);
102 return NULL;
103 }
104
105 gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
106 &gconf->stvis, (gshare) ? gshare->stctxi : NULL);
107 if (!gctx->stctxi) {
108 FREE(gctx);
109 return NULL;
110 }
111
112 gctx->stctxi->st_manager_private = (void *) &gctx->base;
113
114 return &gctx->base;
115 }
116
117 /**
118 * Destroy a context.
119 */
120 static void
121 destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
122 {
123 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
124
125 /* FIXME a context might live longer than its display */
126 if (!dpy->Initialized)
127 _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
128
129 gctx->stctxi->destroy(gctx->stctxi);
130
131 FREE(gctx);
132 }
133
134 static EGLBoolean
135 egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
136 {
137 if (!_eglIsContextBound(ctx))
138 destroy_context(dpy, ctx);
139 return EGL_TRUE;
140 }
141
142 struct egl_g3d_create_surface_arg {
143 EGLint type;
144 union {
145 EGLNativeWindowType win;
146 EGLNativePixmapType pix;
147 } u;
148 };
149
150 static _EGLSurface *
151 egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
152 struct egl_g3d_create_surface_arg *arg,
153 const EGLint *attribs)
154 {
155 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
156 struct egl_g3d_config *gconf = egl_g3d_config(conf);
157 struct egl_g3d_surface *gsurf;
158 struct native_surface *nsurf;
159 const char *err;
160
161 switch (arg->type) {
162 case EGL_WINDOW_BIT:
163 err = "eglCreateWindowSurface";
164 break;
165 case EGL_PIXMAP_BIT:
166 err = "eglCreatePixmapSurface";
167 break;
168 #ifdef EGL_MESA_screen_surface
169 case EGL_SCREEN_BIT_MESA:
170 err = "eglCreateScreenSurface";
171 break;
172 #endif
173 default:
174 err = "eglCreateUnknownSurface";
175 break;
176 }
177
178 gsurf = CALLOC_STRUCT(egl_g3d_surface);
179 if (!gsurf) {
180 _eglError(EGL_BAD_ALLOC, err);
181 return NULL;
182 }
183
184 if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
185 FREE(gsurf);
186 return NULL;
187 }
188
189 /* create the native surface */
190 switch (arg->type) {
191 case EGL_WINDOW_BIT:
192 nsurf = gdpy->native->create_window_surface(gdpy->native,
193 arg->u.win, gconf->native);
194 break;
195 case EGL_PIXMAP_BIT:
196 nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
197 arg->u.pix, gconf->native);
198 break;
199 #ifdef EGL_MESA_screen_surface
200 case EGL_SCREEN_BIT_MESA:
201 /* prefer back buffer (move to _eglInitSurface?) */
202 gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
203 nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
204 gconf->native, gsurf->base.Width, gsurf->base.Height);
205 break;
206 #endif
207 default:
208 nsurf = NULL;
209 break;
210 }
211
212 if (!nsurf) {
213 FREE(gsurf);
214 return NULL;
215 }
216 /* initialize the geometry */
217 if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
218 &gsurf->base.Width, &gsurf->base.Height)) {
219 nsurf->destroy(nsurf);
220 FREE(gsurf);
221 return NULL;
222 }
223
224 gsurf->stvis = gconf->stvis;
225 if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER)
226 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
227
228 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
229 if (!gsurf->stfbi) {
230 nsurf->destroy(nsurf);
231 FREE(gsurf);
232 return NULL;
233 }
234
235 nsurf->user_data = &gsurf->base;
236 gsurf->native = nsurf;
237
238 return &gsurf->base;
239 }
240
241 static _EGLSurface *
242 egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
243 _EGLConfig *conf, EGLNativeWindowType win,
244 const EGLint *attribs)
245 {
246 struct egl_g3d_create_surface_arg arg;
247
248 memset(&arg, 0, sizeof(arg));
249 arg.type = EGL_WINDOW_BIT;
250 arg.u.win = win;
251
252 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
253 }
254
255 static _EGLSurface *
256 egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
257 _EGLConfig *conf, EGLNativePixmapType pix,
258 const EGLint *attribs)
259 {
260 struct egl_g3d_create_surface_arg arg;
261
262 memset(&arg, 0, sizeof(arg));
263 arg.type = EGL_PIXMAP_BIT;
264 arg.u.pix = pix;
265
266 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
267 }
268
269 static struct egl_g3d_surface *
270 create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
271 const EGLint *attribs, const char *func)
272 {
273 struct egl_g3d_config *gconf = egl_g3d_config(conf);
274 struct egl_g3d_surface *gsurf;
275
276 gsurf = CALLOC_STRUCT(egl_g3d_surface);
277 if (!gsurf) {
278 _eglError(EGL_BAD_ALLOC, func);
279 return NULL;
280 }
281
282 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
283 FREE(gsurf);
284 return NULL;
285 }
286
287 gsurf->stvis = gconf->stvis;
288
289 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
290 if (!gsurf->stfbi) {
291 FREE(gsurf);
292 return NULL;
293 }
294
295 return gsurf;
296 }
297
298 static _EGLSurface *
299 egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
300 _EGLConfig *conf, const EGLint *attribs)
301 {
302 struct egl_g3d_surface *gsurf;
303 struct pipe_resource *ptex = NULL;
304
305 gsurf = create_pbuffer_surface(dpy, conf, attribs,
306 "eglCreatePbufferSurface");
307 if (!gsurf)
308 return NULL;
309
310 gsurf->client_buffer_type = EGL_NONE;
311
312 if (!gsurf->stfbi->validate(gsurf->stfbi,
313 &gsurf->stvis.render_buffer, 1, &ptex)) {
314 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
315 FREE(gsurf);
316 return NULL;
317 }
318
319 return &gsurf->base;
320 }
321
322 static _EGLSurface *
323 egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
324 EGLenum buftype,
325 EGLClientBuffer buffer,
326 _EGLConfig *conf,
327 const EGLint *attribs)
328 {
329 struct egl_g3d_surface *gsurf;
330 struct pipe_resource *ptex = NULL;
331 EGLint pbuffer_attribs[32];
332 EGLint count, i;
333
334 switch (buftype) {
335 case EGL_OPENVG_IMAGE:
336 break;
337 default:
338 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
339 return NULL;
340 break;
341 }
342
343 /* parse the attributes first */
344 count = 0;
345 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
346 EGLint attr = attribs[i++];
347 EGLint val = attribs[i];
348 EGLint err = EGL_SUCCESS;
349
350 switch (attr) {
351 case EGL_TEXTURE_FORMAT:
352 case EGL_TEXTURE_TARGET:
353 case EGL_MIPMAP_TEXTURE:
354 pbuffer_attribs[count++] = attr;
355 pbuffer_attribs[count++] = val;
356 break;
357 default:
358 err = EGL_BAD_ATTRIBUTE;
359 break;
360 }
361 /* bail out */
362 if (err != EGL_SUCCESS) {
363 _eglError(err, "eglCreatePbufferFromClientBuffer");
364 return NULL;
365 }
366 }
367
368 pbuffer_attribs[count++] = EGL_NONE;
369
370 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
371 "eglCreatePbufferFromClientBuffer");
372 if (!gsurf)
373 return NULL;
374
375 gsurf->client_buffer_type = buftype;
376 gsurf->client_buffer = buffer;
377
378 if (!gsurf->stfbi->validate(gsurf->stfbi,
379 &gsurf->stvis.render_buffer, 1, &ptex)) {
380 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
381 FREE(gsurf);
382 return NULL;
383 }
384
385 return &gsurf->base;
386 }
387
388 /**
389 * Destroy a surface.
390 */
391 static void
392 destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
393 {
394 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
395
396 /* FIXME a surface might live longer than its display */
397 if (!dpy->Initialized)
398 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
399
400 pipe_resource_reference(&gsurf->render_texture, NULL);
401 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
402 if (gsurf->native)
403 gsurf->native->destroy(gsurf->native);
404 FREE(gsurf);
405 }
406
407 static EGLBoolean
408 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
409 {
410 if (!_eglIsSurfaceBound(surf))
411 destroy_surface(dpy, surf);
412 return EGL_TRUE;
413 }
414
415 static EGLBoolean
416 egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
417 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
418 {
419 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
420 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
421 struct egl_g3d_surface *gread = egl_g3d_surface(read);
422 struct egl_g3d_context *old_gctx;
423 EGLBoolean ok = EGL_TRUE;
424
425 /* bind the new context and return the "orphaned" one */
426 if (!_eglBindContext(&ctx, &draw, &read))
427 return EGL_FALSE;
428 old_gctx = egl_g3d_context(ctx);
429
430 if (old_gctx) {
431 /* flush old context */
432 old_gctx->stctxi->flush(old_gctx->stctxi,
433 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
434 }
435
436 if (gctx) {
437 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
438 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
439 if (ok) {
440 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi);
441 if (gread != gdraw) {
442 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
443 gread->stfbi);
444 }
445
446 if (gdraw->base.Type == EGL_WINDOW_BIT) {
447 gctx->base.WindowRenderBuffer =
448 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
449 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
450 }
451 }
452 }
453 else if (old_gctx) {
454 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
455 old_gctx->base.WindowRenderBuffer = EGL_NONE;
456 }
457
458 if (ctx && !_eglIsContextLinked(ctx))
459 destroy_context(dpy, ctx);
460 if (draw && !_eglIsSurfaceLinked(draw))
461 destroy_surface(dpy, draw);
462 if (read && read != draw && !_eglIsSurfaceLinked(read))
463 destroy_surface(dpy, read);
464
465 return ok;
466 }
467
468 static EGLBoolean
469 egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
470 {
471 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
472 _EGLContext *ctx = _eglGetCurrentContext();
473 struct egl_g3d_context *gctx = NULL;
474
475 /* no-op for pixmap or pbuffer surface */
476 if (gsurf->base.Type == EGL_PIXMAP_BIT ||
477 gsurf->base.Type == EGL_PBUFFER_BIT)
478 return EGL_TRUE;
479
480 /* or when the surface is single-buffered */
481 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
482 return EGL_TRUE;
483
484 if (ctx && ctx->DrawSurface == surf)
485 gctx = egl_g3d_context(ctx);
486
487 /* flush if the surface is current */
488 if (gctx) {
489 gctx->stctxi->flush(gctx->stctxi,
490 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
491 }
492
493 return gsurf->native->swap_buffers(gsurf->native);
494 }
495
496 /**
497 * Get the pipe surface of the given attachment of the native surface.
498 */
499 static struct pipe_resource *
500 get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf,
501 enum native_attachment natt)
502 {
503 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
504
505 textures[natt] = NULL;
506 nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL);
507
508 return textures[natt];
509 }
510
511 static EGLBoolean
512 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
513 EGLNativePixmapType target)
514 {
515 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
516 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
517 _EGLContext *ctx = _eglGetCurrentContext();
518 struct egl_g3d_config *gconf;
519 struct native_surface *nsurf;
520 struct pipe_resource *ptex;
521
522 if (!gsurf->render_texture)
523 return EGL_TRUE;
524
525 gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target));
526 if (!gconf)
527 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
528
529 nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
530 target, gconf->native);
531 if (!nsurf)
532 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
533
534 /* flush if the surface is current */
535 if (ctx && ctx->DrawSurface == &gsurf->base) {
536 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
537 gctx->stctxi->flush(gctx->stctxi,
538 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
539 }
540
541 /* create a pipe context to copy surfaces */
542 if (!gdpy->pipe) {
543 gdpy->pipe =
544 gdpy->native->screen->context_create(gdpy->native->screen, NULL);
545 if (!gdpy->pipe)
546 return EGL_FALSE;
547 }
548
549 ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT);
550 if (ptex) {
551 struct pipe_resource *psrc = gsurf->render_texture;
552 struct pipe_subresource subsrc, subdst;
553 subsrc.face = 0;
554 subsrc.level = 0;
555 subdst.face = 0;
556 subdst.level = 0;
557
558 if (psrc) {
559 gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, subdst, 0, 0, 0,
560 gsurf->render_texture, subsrc, 0, 0, 0, ptex->width0, ptex->height0);
561
562 nsurf->flush_frontbuffer(nsurf);
563 }
564
565 pipe_resource_reference(&ptex, NULL);
566 }
567
568 nsurf->destroy(nsurf);
569
570 return EGL_TRUE;
571 }
572
573 static EGLBoolean
574 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
575 {
576 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
577 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
578 struct pipe_screen *screen = gdpy->native->screen;
579 struct pipe_fence_handle *fence = NULL;
580
581 gctx->stctxi->flush(gctx->stctxi,
582 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
583 screen->fence_finish(screen, fence, 0);
584 screen->fence_reference(screen, &fence, NULL);
585
586 return EGL_TRUE;
587 }
588
589 static EGLBoolean
590 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
591 {
592 _EGLContext *ctx = _eglGetCurrentContext();
593
594 if (engine != EGL_CORE_NATIVE_ENGINE)
595 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
596
597 if (ctx && ctx->DrawSurface) {
598 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
599
600 if (gsurf->native)
601 gsurf->native->wait(gsurf->native);
602 }
603
604 return EGL_TRUE;
605 }
606
607 static EGLBoolean
608 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
609 _EGLSurface *surf, EGLint buffer)
610 {
611 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
612 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
613 struct egl_g3d_context *gctx;
614 enum pipe_format internal_format;
615 enum st_texture_type target;
616
617 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
618 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
619 if (buffer != EGL_BACK_BUFFER)
620 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
621 if (gsurf->base.BoundToTexture)
622 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
623
624 switch (gsurf->base.TextureFormat) {
625 case EGL_TEXTURE_RGB:
626 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
627 break;
628 case EGL_TEXTURE_RGBA:
629 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
630 break;
631 default:
632 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
633 }
634
635 switch (gsurf->base.TextureTarget) {
636 case EGL_TEXTURE_2D:
637 target = ST_TEXTURE_2D;
638 break;
639 default:
640 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
641 }
642
643 if (!es1)
644 return EGL_TRUE;
645 if (!gsurf->render_texture)
646 return EGL_FALSE;
647
648 /* flush properly if the surface is bound */
649 if (gsurf->base.CurrentContext) {
650 gctx = egl_g3d_context(gsurf->base.CurrentContext);
651 gctx->stctxi->flush(gctx->stctxi,
652 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
653 }
654
655 gctx = egl_g3d_context(es1);
656 if (gctx->stctxi->teximage) {
657 if (!gctx->stctxi->teximage(gctx->stctxi, target,
658 gsurf->base.MipmapLevel, internal_format,
659 gsurf->render_texture, gsurf->base.MipmapTexture))
660 return EGL_FALSE;
661 gsurf->base.BoundToTexture = EGL_TRUE;
662 }
663
664 return EGL_TRUE;
665 }
666
667 static EGLBoolean
668 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
669 _EGLSurface *surf, EGLint buffer)
670 {
671 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
672
673 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
674 !gsurf->base.BoundToTexture)
675 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
676 if (buffer != EGL_BACK_BUFFER)
677 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
678
679 if (gsurf->render_texture) {
680 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
681 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
682
683 /* what if the context the surface binds to is no longer current? */
684 if (gctx) {
685 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
686 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
687 }
688 }
689
690 gsurf->base.BoundToTexture = EGL_FALSE;
691
692 return EGL_TRUE;
693 }
694
695 #ifdef EGL_MESA_screen_surface
696
697 static _EGLSurface *
698 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
699 _EGLConfig *conf, const EGLint *attribs)
700 {
701 struct egl_g3d_create_surface_arg arg;
702
703 memset(&arg, 0, sizeof(arg));
704 arg.type = EGL_SCREEN_BIT_MESA;
705
706 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
707 }
708
709 static EGLBoolean
710 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
711 _EGLScreen *scr, _EGLSurface *surf,
712 _EGLMode *mode)
713 {
714 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
715 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
716 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
717 struct native_surface *nsurf;
718 const struct native_mode *nmode;
719 EGLBoolean changed;
720
721 if (gsurf) {
722 EGLint idx;
723
724 if (!mode)
725 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
726 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
727 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
728 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
729 return _eglError(EGL_BAD_MATCH,
730 "eglShowSurfaceMESA(surface smaller than mode size)");
731
732 /* find the index of the mode */
733 for (idx = 0; idx < gscr->base.NumModes; idx++)
734 if (mode == &gscr->base.Modes[idx])
735 break;
736 if (idx >= gscr->base.NumModes) {
737 return _eglError(EGL_BAD_MODE_MESA,
738 "eglShowSurfaceMESA(unknown mode)");
739 }
740
741 nsurf = gsurf->native;
742 nmode = gscr->native_modes[idx];
743 }
744 else {
745 if (mode)
746 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
747
748 /* disable the screen */
749 nsurf = NULL;
750 nmode = NULL;
751 }
752
753 /* TODO surface panning by CRTC choosing */
754 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
755 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
756 if (changed) {
757 gscr->base.CurrentSurface = &gsurf->base;
758 gscr->base.CurrentMode = mode;
759 }
760
761 return changed;
762 }
763
764 #endif /* EGL_MESA_screen_surface */
765
766 /**
767 * Find a config that supports the pixmap.
768 */
769 _EGLConfig *
770 egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix)
771 {
772 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
773 struct egl_g3d_config *gconf;
774 EGLint i;
775
776 for (i = 0; i < dpy->Configs->Size; i++) {
777 gconf = egl_g3d_config((_EGLConfig *) dpy->Configs->Elements[i]);
778 if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native))
779 break;
780 }
781
782 return (i < dpy->Configs->Size) ? &gconf->base : NULL;
783 }
784
785 void
786 egl_g3d_init_driver_api(_EGLDriver *drv)
787 {
788 _eglInitDriverFallbacks(drv);
789
790 drv->API.CreateContext = egl_g3d_create_context;
791 drv->API.DestroyContext = egl_g3d_destroy_context;
792 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
793 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
794 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
795 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
796 drv->API.DestroySurface = egl_g3d_destroy_surface;
797 drv->API.MakeCurrent = egl_g3d_make_current;
798 drv->API.SwapBuffers = egl_g3d_swap_buffers;
799 drv->API.CopyBuffers = egl_g3d_copy_buffers;
800 drv->API.WaitClient = egl_g3d_wait_client;
801 drv->API.WaitNative = egl_g3d_wait_native;
802
803 drv->API.BindTexImage = egl_g3d_bind_tex_image;
804 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
805
806 drv->API.CreateImageKHR = egl_g3d_create_image;
807 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
808
809 #ifdef EGL_MESA_screen_surface
810 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
811 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
812 #endif
813 }