07ea6dc8b9989c3acd4ad1c78b2e33e883d04b13
[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_resource *psrc = gsurf->render_texture;
669 struct pipe_box src_box;
670 u_box_origin_2d(ptex->width0, ptex->height0, &src_box);
671 if (psrc) {
672 gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, 0, 0, 0, 0,
673 gsurf->render_texture, 0, &src_box);
674 nsurf->present(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT, FALSE, 0);
675 }
676
677 pipe_resource_reference(&ptex, NULL);
678 }
679
680 nsurf->destroy(nsurf);
681
682 return EGL_TRUE;
683 }
684
685 static EGLBoolean
686 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
687 {
688 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
689 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
690 struct pipe_screen *screen = gdpy->native->screen;
691 struct pipe_fence_handle *fence = NULL;
692
693 gctx->stctxi->flush(gctx->stctxi,
694 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
695 if (fence) {
696 screen->fence_finish(screen, fence, 0);
697 screen->fence_reference(screen, &fence, NULL);
698 }
699
700 return EGL_TRUE;
701 }
702
703 static EGLBoolean
704 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
705 {
706 _EGLContext *ctx = _eglGetCurrentContext();
707
708 if (engine != EGL_CORE_NATIVE_ENGINE)
709 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
710
711 if (ctx && ctx->DrawSurface) {
712 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
713
714 if (gsurf->native)
715 gsurf->native->wait(gsurf->native);
716 }
717
718 return EGL_TRUE;
719 }
720
721 static EGLBoolean
722 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
723 _EGLSurface *surf, EGLint buffer)
724 {
725 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
726 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
727 struct egl_g3d_context *gctx;
728 enum pipe_format internal_format;
729 enum st_texture_type target;
730
731 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
732 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
733 if (buffer != EGL_BACK_BUFFER)
734 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
735 if (gsurf->base.BoundToTexture)
736 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
737
738 switch (gsurf->base.TextureFormat) {
739 case EGL_TEXTURE_RGB:
740 internal_format = PIPE_FORMAT_R8G8B8_UNORM;
741 break;
742 case EGL_TEXTURE_RGBA:
743 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
744 break;
745 default:
746 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
747 }
748
749 switch (gsurf->base.TextureTarget) {
750 case EGL_TEXTURE_2D:
751 target = ST_TEXTURE_2D;
752 break;
753 default:
754 return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
755 }
756
757 if (!es1)
758 return EGL_TRUE;
759 if (!gsurf->render_texture)
760 return EGL_FALSE;
761
762 /* flush properly if the surface is bound */
763 if (gsurf->base.CurrentContext) {
764 gctx = egl_g3d_context(gsurf->base.CurrentContext);
765 gctx->stctxi->flush(gctx->stctxi,
766 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
767 }
768
769 gctx = egl_g3d_context(es1);
770 if (gctx->stctxi->teximage) {
771 if (!gctx->stctxi->teximage(gctx->stctxi, target,
772 gsurf->base.MipmapLevel, internal_format,
773 gsurf->render_texture, gsurf->base.MipmapTexture))
774 return EGL_FALSE;
775 gsurf->base.BoundToTexture = EGL_TRUE;
776 }
777
778 return EGL_TRUE;
779 }
780
781 static EGLBoolean
782 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
783 _EGLSurface *surf, EGLint buffer)
784 {
785 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
786
787 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
788 !gsurf->base.BoundToTexture)
789 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
790 if (buffer != EGL_BACK_BUFFER)
791 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
792
793 if (gsurf->render_texture) {
794 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
795 struct egl_g3d_context *gctx = egl_g3d_context(ctx);
796
797 /* what if the context the surface binds to is no longer current? */
798 if (gctx) {
799 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
800 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
801 }
802 }
803
804 gsurf->base.BoundToTexture = EGL_FALSE;
805
806 return EGL_TRUE;
807 }
808
809 #ifdef EGL_MESA_screen_surface
810
811 static _EGLSurface *
812 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
813 _EGLConfig *conf, const EGLint *attribs)
814 {
815 struct egl_g3d_create_surface_arg arg;
816
817 memset(&arg, 0, sizeof(arg));
818 arg.type = EGL_SCREEN_BIT_MESA;
819
820 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
821 }
822
823 static EGLBoolean
824 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
825 _EGLScreen *scr, _EGLSurface *surf,
826 _EGLMode *mode)
827 {
828 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
829 struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
830 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
831 struct native_surface *nsurf;
832 const struct native_mode *nmode;
833 EGLBoolean changed;
834
835 if (gsurf) {
836 EGLint idx;
837
838 if (!mode)
839 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
840 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
841 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
842 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
843 return _eglError(EGL_BAD_MATCH,
844 "eglShowSurfaceMESA(surface smaller than mode size)");
845
846 /* find the index of the mode */
847 for (idx = 0; idx < gscr->base.NumModes; idx++)
848 if (mode == &gscr->base.Modes[idx])
849 break;
850 if (idx >= gscr->base.NumModes) {
851 return _eglError(EGL_BAD_MODE_MESA,
852 "eglShowSurfaceMESA(unknown mode)");
853 }
854
855 nsurf = gsurf->native;
856 nmode = gscr->native_modes[idx];
857 }
858 else {
859 if (mode)
860 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
861
862 /* disable the screen */
863 nsurf = NULL;
864 nmode = NULL;
865 }
866
867 /* TODO surface panning by CRTC choosing */
868 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
869 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
870 if (changed) {
871 gscr->base.CurrentSurface = &gsurf->base;
872 gscr->base.CurrentMode = mode;
873 }
874
875 return changed;
876 }
877
878 #endif /* EGL_MESA_screen_surface */
879
880 void
881 egl_g3d_init_driver_api(_EGLDriver *drv)
882 {
883 _eglInitDriverFallbacks(drv);
884
885 drv->API.ChooseConfig = egl_g3d_choose_config;
886
887 drv->API.CreateContext = egl_g3d_create_context;
888 drv->API.DestroyContext = egl_g3d_destroy_context;
889 drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
890 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
891 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
892 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
893 drv->API.DestroySurface = egl_g3d_destroy_surface;
894 drv->API.MakeCurrent = egl_g3d_make_current;
895 drv->API.SwapBuffers = egl_g3d_swap_buffers;
896 drv->API.CopyBuffers = egl_g3d_copy_buffers;
897 drv->API.WaitClient = egl_g3d_wait_client;
898 drv->API.WaitNative = egl_g3d_wait_native;
899
900 drv->API.BindTexImage = egl_g3d_bind_tex_image;
901 drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
902
903 drv->API.CreateImageKHR = egl_g3d_create_image;
904 drv->API.DestroyImageKHR = egl_g3d_destroy_image;
905 #ifdef EGL_MESA_drm_image
906 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
907 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
908 #endif
909
910 #ifdef EGL_KHR_reusable_sync
911 drv->API.CreateSyncKHR = egl_g3d_create_sync;
912 drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
913 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
914 drv->API.SignalSyncKHR = egl_g3d_signal_sync;
915 #endif
916
917 #ifdef EGL_MESA_screen_surface
918 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
919 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
920 #endif
921 }