st/egl: Fix eglCopyBuffers.
[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 gconf->stvis.buffer_mask & ST_ATTACHMENT_FRONT_LEFT_MASK)
329 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
330
331 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
332 if (!gsurf->stfbi) {
333 nsurf->destroy(nsurf);
334 FREE(gsurf);
335 return NULL;
336 }
337
338 nsurf->user_data = &gsurf->base;
339 gsurf->native = nsurf;
340
341 return &gsurf->base;
342 }
343
344 static _EGLSurface *
345 egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
346 _EGLConfig *conf, EGLNativeWindowType win,
347 const EGLint *attribs)
348 {
349 struct egl_g3d_create_surface_arg arg;
350
351 memset(&arg, 0, sizeof(arg));
352 arg.type = EGL_WINDOW_BIT;
353 arg.u.win = win;
354
355 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
356 }
357
358 static _EGLSurface *
359 egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
360 _EGLConfig *conf, EGLNativePixmapType pix,
361 const EGLint *attribs)
362 {
363 struct egl_g3d_create_surface_arg arg;
364
365 memset(&arg, 0, sizeof(arg));
366 arg.type = EGL_PIXMAP_BIT;
367 arg.u.pix = pix;
368
369 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
370 }
371
372 static struct egl_g3d_surface *
373 create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
374 const EGLint *attribs, const char *func)
375 {
376 struct egl_g3d_config *gconf = egl_g3d_config(conf);
377 struct egl_g3d_surface *gsurf;
378
379 gsurf = CALLOC_STRUCT(egl_g3d_surface);
380 if (!gsurf) {
381 _eglError(EGL_BAD_ALLOC, func);
382 return NULL;
383 }
384
385 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
386 FREE(gsurf);
387 return NULL;
388 }
389
390 gsurf->stvis = gconf->stvis;
391
392 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
393 if (!gsurf->stfbi) {
394 FREE(gsurf);
395 return NULL;
396 }
397
398 return gsurf;
399 }
400
401 static _EGLSurface *
402 egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
403 _EGLConfig *conf, const EGLint *attribs)
404 {
405 struct egl_g3d_surface *gsurf;
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 return &gsurf->base;
415 }
416
417 static _EGLSurface *
418 egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
419 EGLenum buftype,
420 EGLClientBuffer buffer,
421 _EGLConfig *conf,
422 const EGLint *attribs)
423 {
424 struct egl_g3d_surface *gsurf;
425 struct pipe_resource *ptex = NULL;
426 EGLint pbuffer_attribs[32];
427 EGLint count, i;
428
429 switch (buftype) {
430 case EGL_OPENVG_IMAGE:
431 break;
432 default:
433 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
434 return NULL;
435 break;
436 }
437
438 /* parse the attributes first */
439 count = 0;
440 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
441 EGLint attr = attribs[i++];
442 EGLint val = attribs[i];
443 EGLint err = EGL_SUCCESS;
444
445 switch (attr) {
446 case EGL_TEXTURE_FORMAT:
447 case EGL_TEXTURE_TARGET:
448 case EGL_MIPMAP_TEXTURE:
449 pbuffer_attribs[count++] = attr;
450 pbuffer_attribs[count++] = val;
451 break;
452 default:
453 err = EGL_BAD_ATTRIBUTE;
454 break;
455 }
456 /* bail out */
457 if (err != EGL_SUCCESS) {
458 _eglError(err, "eglCreatePbufferFromClientBuffer");
459 return NULL;
460 }
461 }
462
463 pbuffer_attribs[count++] = EGL_NONE;
464
465 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
466 "eglCreatePbufferFromClientBuffer");
467 if (!gsurf)
468 return NULL;
469
470 gsurf->client_buffer_type = buftype;
471 gsurf->client_buffer = buffer;
472
473 /* validate now so that it fails if the client buffer is invalid */
474 if (!gsurf->stfbi->validate(gsurf->stfbi,
475 &gsurf->stvis.render_buffer, 1, &ptex)) {
476 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
477 FREE(gsurf);
478 return NULL;
479 }
480 pipe_resource_reference(&ptex, NULL);
481
482 return &gsurf->base;
483 }
484
485 /**
486 * Destroy a surface.
487 */
488 static void
489 destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
490 {
491 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
492
493 /* FIXME a surface might live longer than its display */
494 if (!dpy->Initialized)
495 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
496
497 pipe_resource_reference(&gsurf->render_texture, NULL);
498 egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
499 if (gsurf->native)
500 gsurf->native->destroy(gsurf->native);
501 FREE(gsurf);
502 }
503
504 static EGLBoolean
505 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
506 {
507 if (_eglPutSurface(surf))
508 destroy_surface(dpy, surf);
509 return EGL_TRUE;
510 }
511
512 static EGLBoolean
513 egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
514 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
515 {
516 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
517 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
518 struct egl_g3d_surface *gread = egl_g3d_surface(read);
519 struct egl_g3d_context *old_gctx;
520 _EGLContext *old_ctx;
521 _EGLSurface *old_draw, *old_read;
522 EGLBoolean ok = EGL_TRUE;
523
524 /* make new bindings */
525 if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
526 return EGL_FALSE;
527
528 old_gctx = egl_g3d_context(old_ctx);
529 if (old_gctx) {
530 /* flush old context */
531 old_gctx->stctxi->flush(old_gctx->stctxi,
532 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
533 }
534
535 if (gctx) {
536 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
537 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
538 if (ok) {
539 if (gdraw) {
540 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
541 gdraw->stfbi);
542
543 if (gdraw->base.Type == EGL_WINDOW_BIT) {
544 gctx->base.WindowRenderBuffer =
545 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
546 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
547 }
548 }
549 if (gread && gread != gdraw) {
550 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
551 gread->stfbi);
552 }
553 }
554 }
555 else if (old_gctx) {
556 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
557 if (ok)
558 old_gctx->base.WindowRenderBuffer = EGL_NONE;
559 }
560
561 if (ok) {
562 if (_eglPutContext(old_ctx))
563 destroy_context(dpy, old_ctx);
564 if (_eglPutSurface(old_draw))
565 destroy_surface(dpy, old_draw);
566 if (_eglPutSurface(old_read))
567 destroy_surface(dpy, old_read);
568 }
569 else {
570 /* undo the previous _eglBindContext */
571 _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
572 assert(&gctx->base == ctx &&
573 &gdraw->base == draw &&
574 &gread->base == read);
575
576 _eglPutSurface(draw);
577 _eglPutSurface(read);
578 _eglPutContext(ctx);
579
580 _eglPutSurface(old_draw);
581 _eglPutSurface(old_read);
582 _eglPutContext(old_ctx);
583 }
584
585 return ok;
586 }
587
588 static EGLBoolean
589 egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
590 {
591 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
592 _EGLContext *ctx = _eglGetCurrentContext();
593 struct egl_g3d_context *gctx = NULL;
594
595 /* no-op for pixmap or pbuffer surface */
596 if (gsurf->base.Type == EGL_PIXMAP_BIT ||
597 gsurf->base.Type == EGL_PBUFFER_BIT)
598 return EGL_TRUE;
599
600 /* or when the surface is single-buffered */
601 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
602 return EGL_TRUE;
603
604 if (ctx && ctx->DrawSurface == surf)
605 gctx = egl_g3d_context(ctx);
606
607 /* flush if the surface is current */
608 if (gctx) {
609 gctx->stctxi->flush(gctx->stctxi,
610 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
611 }
612
613 return gsurf->native->present(gsurf->native,
614 NATIVE_ATTACHMENT_BACK_LEFT,
615 gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED,
616 gsurf->base.SwapInterval);
617 }
618
619 /**
620 * Get the pipe surface of the given attachment of the native surface.
621 */
622 static struct pipe_resource *
623 get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf,
624 enum native_attachment natt)
625 {
626 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
627
628 textures[natt] = NULL;
629 nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL);
630
631 return textures[natt];
632 }
633
634 static EGLBoolean
635 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
636 EGLNativePixmapType target)
637 {
638 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
639 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
640 _EGLContext *ctx = _eglGetCurrentContext();
641 struct native_surface *nsurf;
642 struct pipe_resource *ptex;
643
644 if (!gsurf->render_texture)
645 return EGL_TRUE;
646
647 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, target, NULL);
648 if (!nsurf)
649 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
650
651 /* flush if the surface is current */
652 if (ctx && ctx->DrawSurface == &gsurf->base) {
653 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
654 gctx->stctxi->flush(gctx->stctxi,
655 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
656 }
657
658 /* create a pipe context to copy surfaces */
659 if (!gdpy->pipe) {
660 gdpy->pipe =
661 gdpy->native->screen->context_create(gdpy->native->screen, NULL);
662 if (!gdpy->pipe)
663 return EGL_FALSE;
664 }
665
666 ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT);
667 if (ptex) {
668 struct pipe_box src_box;
669
670 u_box_origin_2d(ptex->width0, ptex->height0, &src_box);
671 gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, 0, 0, 0, 0,
672 gsurf->render_texture, 0, &src_box);
673 gdpy->pipe->flush(gdpy->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
674 nsurf->present(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT, FALSE, 0);
675
676 pipe_resource_reference(&ptex, NULL);
677 }
678
679 nsurf->destroy(nsurf);
680
681 return EGL_TRUE;
682 }
683
684 static EGLBoolean
685 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
686 {
687 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
688 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
689 struct pipe_screen *screen = gdpy->native->screen;
690 struct pipe_fence_handle *fence = NULL;
691
692 gctx->stctxi->flush(gctx->stctxi,
693 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
694 if (fence) {
695 screen->fence_finish(screen, fence, 0);
696 screen->fence_reference(screen, &fence, NULL);
697 }
698
699 return EGL_TRUE;
700 }
701
702 static EGLBoolean
703 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
704 {
705 _EGLContext *ctx = _eglGetCurrentContext();
706
707 if (engine != EGL_CORE_NATIVE_ENGINE)
708 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
709
710 if (ctx && ctx->DrawSurface) {
711 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
712
713 if (gsurf->native)
714 gsurf->native->wait(gsurf->native);
715 }
716
717 return EGL_TRUE;
718 }
719
720 static EGLBoolean
721 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
722 _EGLSurface *surf, EGLint buffer)
723 {
724 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
725 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
726 struct egl_g3d_context *gctx;
727 enum pipe_format internal_format;
728 enum st_texture_type target;
729
730 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
731 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
732 if (buffer != EGL_BACK_BUFFER)
733 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
734 if (gsurf->base.BoundToTexture)
735 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
736
737 switch (gsurf->base.TextureFormat) {
738 case EGL_TEXTURE_RGB:
739 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
740 break;
741 case EGL_TEXTURE_RGBA:
742 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
743 break;
744 default:
745 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
746 }
747
748 switch (gsurf->base.TextureTarget) {
749 case EGL_TEXTURE_2D:
750 target = ST_TEXTURE_2D;
751 break;
752 default:
753 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
754 }
755
756 if (!es1)
757 return EGL_TRUE;
758 if (!gsurf->render_texture)
759 return EGL_FALSE;
760
761 /* flush properly if the surface is bound */
762 if (gsurf->base.CurrentContext) {
763 gctx = egl_g3d_context(gsurf->base.CurrentContext);
764 gctx->stctxi->flush(gctx->stctxi,
765 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
766 }
767
768 gctx = egl_g3d_context(es1);
769 if (gctx->stctxi->teximage) {
770 if (!gctx->stctxi->teximage(gctx->stctxi, target,
771 gsurf->base.MipmapLevel, internal_format,
772 gsurf->render_texture, gsurf->base.MipmapTexture))
773 return EGL_FALSE;
774 gsurf->base.BoundToTexture = EGL_TRUE;
775 }
776
777 return EGL_TRUE;
778 }
779
780 static EGLBoolean
781 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
782 _EGLSurface *surf, EGLint buffer)
783 {
784 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
785
786 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
787 !gsurf->base.BoundToTexture)
788 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
789 if (buffer != EGL_BACK_BUFFER)
790 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
791
792 if (gsurf->render_texture) {
793 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
794 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
795
796 /* what if the context the surface binds to is no longer current? */
797 if (gctx) {
798 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
799 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
800 }
801 }
802
803 gsurf->base.BoundToTexture = EGL_FALSE;
804
805 return EGL_TRUE;
806 }
807
808 #ifdef EGL_MESA_screen_surface
809
810 static _EGLSurface *
811 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
812 _EGLConfig *conf, const EGLint *attribs)
813 {
814 struct egl_g3d_create_surface_arg arg;
815
816 memset(&arg, 0, sizeof(arg));
817 arg.type = EGL_SCREEN_BIT_MESA;
818
819 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
820 }
821
822 static EGLBoolean
823 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
824 _EGLScreen *scr, _EGLSurface *surf,
825 _EGLMode *mode)
826 {
827 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
828 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
829 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
830 struct native_surface *nsurf;
831 const struct native_mode *nmode;
832 EGLBoolean changed;
833
834 if (gsurf) {
835 EGLint idx;
836
837 if (!mode)
838 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
839 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
840 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
841 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
842 return _eglError(EGL_BAD_MATCH,
843 "eglShowSurfaceMESA(surface smaller than mode size)");
844
845 /* find the index of the mode */
846 for (idx = 0; idx < gscr->base.NumModes; idx++)
847 if (mode == &gscr->base.Modes[idx])
848 break;
849 if (idx >= gscr->base.NumModes) {
850 return _eglError(EGL_BAD_MODE_MESA,
851 "eglShowSurfaceMESA(unknown mode)");
852 }
853
854 nsurf = gsurf->native;
855 nmode = gscr->native_modes[idx];
856 }
857 else {
858 if (mode)
859 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
860
861 /* disable the screen */
862 nsurf = NULL;
863 nmode = NULL;
864 }
865
866 /* TODO surface panning by CRTC choosing */
867 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
868 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
869 if (changed) {
870 gscr->base.CurrentSurface = &gsurf->base;
871 gscr->base.CurrentMode = mode;
872 }
873
874 return changed;
875 }
876
877 #endif /* EGL_MESA_screen_surface */
878
879 void
880 egl_g3d_init_driver_api(_EGLDriver *drv)
881 {
882 _eglInitDriverFallbacks(drv);
883
884 drv->API.ChooseConfig = egl_g3d_choose_config;
885
886 drv->API.CreateContext = egl_g3d_create_context;
887 drv->API.DestroyContext = egl_g3d_destroy_context;
888 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
889 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
890 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
891 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
892 drv->API.DestroySurface = egl_g3d_destroy_surface;
893 drv->API.MakeCurrent = egl_g3d_make_current;
894 drv->API.SwapBuffers = egl_g3d_swap_buffers;
895 drv->API.CopyBuffers = egl_g3d_copy_buffers;
896 drv->API.WaitClient = egl_g3d_wait_client;
897 drv->API.WaitNative = egl_g3d_wait_native;
898
899 drv->API.BindTexImage = egl_g3d_bind_tex_image;
900 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
901
902 drv->API.CreateImageKHR = egl_g3d_create_image;
903 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
904 #ifdef EGL_MESA_drm_image
905 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
906 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
907 #endif
908
909 #ifdef EGL_KHR_reusable_sync
910 drv->API.CreateSyncKHR = egl_g3d_create_sync;
911 drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
912 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
913 drv->API.SignalSyncKHR = egl_g3d_signal_sync;
914 #endif
915
916 #ifdef EGL_MESA_screen_surface
917 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
918 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
919 #endif
920 }