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