• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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