Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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