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