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
 *
3
 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4
 * Copyright 2009-2010 Chia-I Wu 
5
 * Copyright 2010-2011 LunarG, Inc.
6
 * All Rights Reserved.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the
10
 * "Software"), to deal in the Software without restriction, including
11
 * without limitation the rights to use, copy, modify, merge, publish,
12
 * distribute, sub license, and/or sell copies of the Software, and to
13
 * permit persons to whom the Software is furnished to do so, subject to
14
 * the following conditions:
15
 *
16
 * The above copyright notice and this permission notice (including the
17
 * next paragraph) shall be included in all copies or substantial portions
18
 * of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
 * DEALINGS IN THE SOFTWARE.
27
 *
28
 **************************************************************************/
29
 
30
 
31
#include 
32
#include 
33
#include 
34
#include "eglconfig.h"
35
#include "eglcontext.h"
36
#include "egldisplay.h"
37
#include "eglcurrent.h"
38
#include "eglsurface.h"
39
#include "egllog.h"
40
 
41
 
42
/**
43
 * Return the API bit (one of EGL_xxx_BIT) of the context.
44
 */
45
static EGLint
46
_eglGetContextAPIBit(_EGLContext *ctx)
47
{
48
   EGLint bit = 0;
49
 
50
   switch (ctx->ClientAPI) {
51
   case EGL_OPENGL_ES_API:
52
      switch (ctx->ClientMajorVersion) {
53
      case 1:
54
         bit = EGL_OPENGL_ES_BIT;
55
         break;
56
      case 2:
57
         bit = EGL_OPENGL_ES2_BIT;
58
         break;
59
      case 3:
60
         bit = EGL_OPENGL_ES3_BIT_KHR;
61
         break;
62
      default:
63
         break;
64
      }
65
      break;
66
   case EGL_OPENVG_API:
67
      bit = EGL_OPENVG_BIT;
68
      break;
69
   case EGL_OPENGL_API:
70
      bit = EGL_OPENGL_BIT;
71
      break;
72
   default:
73
      break;
74
   }
75
 
76
   return bit;
77
}
78
 
79
 
80
/**
81
 * Parse the list of context attributes and return the proper error code.
82
 */
83
static EGLint
84
_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
85
                           const EGLint *attrib_list)
86
{
87
   EGLenum api = ctx->ClientAPI;
88
   EGLint i, err = EGL_SUCCESS;
89
 
90
   if (!attrib_list)
91
      return EGL_SUCCESS;
92
 
93
   if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) {
94
      _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]);
95
      return EGL_BAD_ATTRIBUTE;
96
   }
97
 
98
   for (i = 0; attrib_list[i] != EGL_NONE; i++) {
99
      EGLint attr = attrib_list[i++];
100
      EGLint val = attrib_list[i];
101
 
102
      switch (attr) {
103
      case EGL_CONTEXT_CLIENT_VERSION:
104
         ctx->ClientMajorVersion = val;
105
         break;
106
 
107
      case EGL_CONTEXT_MINOR_VERSION_KHR:
108
         if (!dpy->Extensions.KHR_create_context) {
109
            err = EGL_BAD_ATTRIBUTE;
110
            break;
111
         }
112
 
113
         ctx->ClientMinorVersion = val;
114
         break;
115
 
116
      case EGL_CONTEXT_FLAGS_KHR:
117
         if (!dpy->Extensions.KHR_create_context) {
118
            err = EGL_BAD_ATTRIBUTE;
119
            break;
120
         }
121
 
122
         /* The EGL_KHR_create_context spec says:
123
          *
124
          *     "Flags are only defined for OpenGL context creation, and
125
          *     specifying a flags value other than zero for other types of
126
          *     contexts, including OpenGL ES contexts, will generate an
127
          *     error."
128
          */
129
         if (api != EGL_OPENGL_API && val != 0) {
130
            err = EGL_BAD_ATTRIBUTE;
131
            break;
132
         }
133
 
134
         ctx->Flags = val;
135
         break;
136
 
137
      case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
138
         if (!dpy->Extensions.KHR_create_context) {
139
            err = EGL_BAD_ATTRIBUTE;
140
            break;
141
         }
142
 
143
         /* The EGL_KHR_create_context spec says:
144
          *
145
          *     "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
146
          *     OpenGL contexts, and specifying it for other types of
147
          *     contexts, including OpenGL ES contexts, will generate an
148
          *     error."
149
          */
150
         if (api != EGL_OPENGL_API) {
151
            err = EGL_BAD_ATTRIBUTE;
152
            break;
153
         }
154
 
155
         ctx->Profile = val;
156
         break;
157
 
158
      case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
159
         /* The EGL_KHR_create_context spec says:
160
          *
161
          *     "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
162
          *     meaningful for OpenGL contexts, and specifying it for other
163
          *     types of contexts, including OpenGL ES contexts, will generate
164
          *     an error."
165
          */
166
           if (!dpy->Extensions.KHR_create_context
167
               || api != EGL_OPENGL_API) {
168
            err = EGL_BAD_ATTRIBUTE;
169
            break;
170
         }
171
 
172
         ctx->ResetNotificationStrategy = val;
173
         break;
174
 
175
      case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
176
         /* The EGL_EXT_create_context_robustness spec says:
177
          *
178
          *     "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
179
          *     meaningful for OpenGL ES contexts, and specifying it for other
180
          *     types of contexts will generate an EGL_BAD_ATTRIBUTE error."
181
          */
182
         if (!dpy->Extensions.EXT_create_context_robustness
183
             || api != EGL_OPENGL_ES_API) {
184
            err = EGL_BAD_ATTRIBUTE;
185
            break;
186
         }
187
 
188
         ctx->ResetNotificationStrategy = val;
189
         break;
190
 
191
      case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
192
         if (!dpy->Extensions.EXT_create_context_robustness) {
193
            err = EGL_BAD_ATTRIBUTE;
194
            break;
195
         }
196
 
197
         ctx->Flags = EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
198
         break;
199
 
200
      default:
201
         err = EGL_BAD_ATTRIBUTE;
202
         break;
203
      }
204
 
205
      if (err != EGL_SUCCESS) {
206
         _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
207
         break;
208
      }
209
   }
210
 
211
   if (api == EGL_OPENGL_API) {
212
      /* The EGL_KHR_create_context spec says:
213
       *
214
       *     "If the requested OpenGL version is less than 3.2,
215
       *     EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
216
       *     functionality of the context is determined solely by the
217
       *     requested version."
218
       *
219
       * Since the value is ignored, only validate the setting if the version
220
       * is >= 3.2.
221
       */
222
      if (ctx->ClientMajorVersion >= 4
223
          || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
224
         switch (ctx->Profile) {
225
         case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
226
         case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
227
            break;
228
 
229
         default:
230
            /* The EGL_KHR_create_context spec says:
231
             *
232
             *     "* If an OpenGL context is requested, the requested version
233
             *        is greater than 3.2, and the value for attribute
234
             *        EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
235
             *        any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
236
             *        and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
237
             *        more than one of these bits set; or if the implementation does
238
             *        not support the requested profile, then an EGL_BAD_MATCH error
239
             *        is generated."
240
             */
241
            err = EGL_BAD_MATCH;
242
            break;
243
         }
244
      }
245
 
246
      /* The EGL_KHR_create_context spec says:
247
       *
248
       *     "* If an OpenGL context is requested and the values for
249
       *        attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
250
       *        EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
251
       *        the value for attribute
252
       *        EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
253
       *        version and feature set that are not defined, than an
254
       *        EGL_BAD_MATCH error is generated.
255
       *
256
       *        ... Thus, examples of invalid combinations of attributes
257
       *        include:
258
       *
259
       *          - Major version < 1 or > 4
260
       *          - Major version == 1 and minor version < 0 or > 5
261
       *          - Major version == 2 and minor version < 0 or > 1
262
       *          - Major version == 3 and minor version < 0 or > 2
263
       *          - Major version == 4 and minor version < 0 or > 2
264
       *          - Forward-compatible flag set and major version < 3"
265
       */
266
      if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
267
         err = EGL_BAD_MATCH;
268
 
269
      switch (ctx->ClientMajorVersion) {
270
      case 1:
271
         if (ctx->ClientMinorVersion > 5
272
             || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
273
            err = EGL_BAD_MATCH;
274
         break;
275
 
276
      case 2:
277
         if (ctx->ClientMinorVersion > 1
278
             || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
279
            err = EGL_BAD_MATCH;
280
         break;
281
 
282
      case 3:
283
         /* Note: The text above is incorrect.  There *is* an OpenGL 3.3!
284
          */
285
         if (ctx->ClientMinorVersion > 3)
286
            err = EGL_BAD_MATCH;
287
         break;
288
 
289
      case 4:
290
      default:
291
         /* Don't put additional version checks here.  We don't know that
292
          * there won't be versions > 4.2.
293
          */
294
         break;
295
      }
296
   } else if (api == EGL_OPENGL_ES_API) {
297
      /* The EGL_KHR_create_context spec says:
298
       *
299
       *     "* If an OpenGL ES context is requested and the values for
300
       *        attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
301
       *        EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
302
       *        is not defined, than an EGL_BAD_MATCH error is generated.
303
       *
304
       *        ... Examples of invalid combinations of attributes include:
305
       *
306
       *          - Major version < 1 or > 2
307
       *          - Major version == 1 and minor version < 0 or > 1
308
       *          - Major version == 2 and minor version != 0
309
       */
310
      if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
311
         err = EGL_BAD_MATCH;
312
 
313
      switch (ctx->ClientMajorVersion) {
314
      case 1:
315
         if (ctx->ClientMinorVersion > 1)
316
            err = EGL_BAD_MATCH;
317
         break;
318
 
319
      case 2:
320
         if (ctx->ClientMinorVersion > 0)
321
            err = EGL_BAD_MATCH;
322
         break;
323
 
324
      case 3:
325
      default:
326
         /* Don't put additional version checks here.  We don't know that
327
          * there won't be versions > 3.0.
328
          */
329
         break;
330
      }
331
   }
332
 
333
   switch (ctx->ResetNotificationStrategy) {
334
   case EGL_NO_RESET_NOTIFICATION_KHR:
335
   case EGL_LOSE_CONTEXT_ON_RESET_KHR:
336
      break;
337
 
338
   default:
339
      err = EGL_BAD_ATTRIBUTE;
340
      break;
341
   }
342
 
343
   if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
344
                      | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
345
                      | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
346
      err = EGL_BAD_ATTRIBUTE;
347
   }
348
 
349
   return err;
350
}
351
 
352
 
353
/**
354
 * Initialize the given _EGLContext object to defaults and/or the values
355
 * in the attrib_list.
356
 */
357
EGLBoolean
358
_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
359
                const EGLint *attrib_list)
360
{
361
   const EGLenum api = eglQueryAPI();
362
   EGLint err;
363
 
364
   if (api == EGL_NONE) {
365
      _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
366
      return EGL_FALSE;
367
   }
368
 
369
   _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
370
   ctx->ClientAPI = api;
371
   ctx->Config = conf;
372
   ctx->WindowRenderBuffer = EGL_NONE;
373
   ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
374
 
375
   ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
376
   ctx->ClientMinorVersion = 0;
377
   ctx->Flags = 0;
378
   ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
379
   ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
380
 
381
   err = _eglParseContextAttribList(ctx, dpy, attrib_list);
382
   if (err == EGL_SUCCESS && ctx->Config) {
383
      EGLint api_bit;
384
 
385
      api_bit = _eglGetContextAPIBit(ctx);
386
      if (!(ctx->Config->RenderableType & api_bit)) {
387
         _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
388
               api_bit, ctx->Config->RenderableType);
389
         err = EGL_BAD_CONFIG;
390
      }
391
   }
392
   if (err != EGL_SUCCESS)
393
      return _eglError(err, "eglCreateContext");
394
 
395
   return EGL_TRUE;
396
}
397
 
398
 
399
static EGLint
400
_eglQueryContextRenderBuffer(_EGLContext *ctx)
401
{
402
   _EGLSurface *surf = ctx->DrawSurface;
403
   EGLint rb;
404
 
405
   if (!surf)
406
      return EGL_NONE;
407
   if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
408
      rb = ctx->WindowRenderBuffer;
409
   else
410
      rb = surf->RenderBuffer;
411
   return rb;
412
}
413
 
414
 
415
EGLBoolean
416
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
417
                 EGLint attribute, EGLint *value)
418
{
419
   (void) drv;
420
   (void) dpy;
421
 
422
   if (!value)
423
      return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
424
 
425
   switch (attribute) {
426
   case EGL_CONFIG_ID:
427
      if (!c->Config)
428
         return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
429
      *value = c->Config->ConfigID;
430
      break;
431
   case EGL_CONTEXT_CLIENT_VERSION:
432
      *value = c->ClientMajorVersion;
433
      break;
434
   case EGL_CONTEXT_CLIENT_TYPE:
435
      *value = c->ClientAPI;
436
      break;
437
   case EGL_RENDER_BUFFER:
438
      *value = _eglQueryContextRenderBuffer(c);
439
      break;
440
   default:
441
      return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
442
   }
443
 
444
   return EGL_TRUE;
445
}
446
 
447
 
448
/**
449
 * Bind the context to the thread and return the previous context.
450
 *
451
 * Note that the context may be NULL.
452
 */
453
static _EGLContext *
454
_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
455
{
456
   EGLint apiIndex;
457
   _EGLContext *oldCtx;
458
 
459
    apiIndex = (ctx) ?
460
      _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
461
 
462
   oldCtx = t->CurrentContexts[apiIndex];
463
   if (ctx != oldCtx) {
464
      if (oldCtx)
465
         oldCtx->Binding = NULL;
466
      if (ctx)
467
         ctx->Binding = t;
468
 
469
      t->CurrentContexts[apiIndex] = ctx;
470
   }
471
 
472
   return oldCtx;
473
}
474
 
475
 
476
/**
477
 * Return true if the given context and surfaces can be made current.
478
 */
479
static EGLBoolean
480
_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
481
{
482
   _EGLThreadInfo *t = _eglGetCurrentThread();
483
   _EGLDisplay *dpy;
484
   EGLint conflict_api;
485
 
486
   if (_eglIsCurrentThreadDummy())
487
      return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
488
 
489
   /* this is easy */
490
   if (!ctx) {
491
      if (draw || read)
492
         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
493
      return EGL_TRUE;
494
   }
495
 
496
   dpy = ctx->Resource.Display;
497
   if (!dpy->Extensions.KHR_surfaceless_context
498
       && (draw == NULL || read == NULL))
499
      return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
500
 
501
   /*
502
    * The spec says
503
    *
504
    * "If ctx is current to some other thread, or if either draw or read are
505
    * bound to contexts in another thread, an EGL_BAD_ACCESS error is
506
    * generated."
507
    *
508
    * and
509
    *
510
    * "at most one context may be bound to a particular surface at a given
511
    * time"
512
    */
513
   if (ctx->Binding && ctx->Binding != t)
514
      return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
515
   if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
516
      if (draw->CurrentContext->Binding != t ||
517
          draw->CurrentContext->ClientAPI != ctx->ClientAPI)
518
         return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
519
   }
520
   if (read && read->CurrentContext && read->CurrentContext != ctx) {
521
      if (read->CurrentContext->Binding != t ||
522
          read->CurrentContext->ClientAPI != ctx->ClientAPI)
523
         return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
524
   }
525
 
526
   /* simply require the configs to be equal */
527
   if ((draw && draw->Config != ctx->Config) ||
528
       (read && read->Config != ctx->Config))
529
      return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
530
 
531
   switch (ctx->ClientAPI) {
532
   /* OpenGL and OpenGL ES are conflicting */
533
   case EGL_OPENGL_ES_API:
534
      conflict_api = EGL_OPENGL_API;
535
      break;
536
   case EGL_OPENGL_API:
537
      conflict_api = EGL_OPENGL_ES_API;
538
      break;
539
   default:
540
      conflict_api = -1;
541
      break;
542
   }
543
 
544
   if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
545
      return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
546
 
547
   return EGL_TRUE;
548
}
549
 
550
 
551
/**
552
 * Bind the context to the current thread and given surfaces.  Return the
553
 * previous bound context and surfaces.  The caller should unreference the
554
 * returned context and surfaces.
555
 *
556
 * Making a second call with the resources returned by the first call
557
 * unsurprisingly undoes the first call, except for the resouce reference
558
 * counts.
559
 */
560
EGLBoolean
561
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
562
                _EGLContext **old_ctx,
563
                _EGLSurface **old_draw, _EGLSurface **old_read)
564
{
565
   _EGLThreadInfo *t = _eglGetCurrentThread();
566
   _EGLContext *prev_ctx;
567
   _EGLSurface *prev_draw, *prev_read;
568
 
569
   printf("%s\n",__FUNCTION__);
570
 
571
   if (!_eglCheckMakeCurrent(ctx, draw, read))
572
      return EGL_FALSE;
573
 
574
   /* increment refcounts before binding */
575
   _eglGetContext(ctx);
576
   _eglGetSurface(draw);
577
   _eglGetSurface(read);
578
 
579
   /* bind the new context */
580
   prev_ctx = _eglBindContextToThread(ctx, t);
581
 
582
   /* break previous bindings */
583
   if (prev_ctx) {
584
      prev_draw = prev_ctx->DrawSurface;
585
      prev_read = prev_ctx->ReadSurface;
586
 
587
      if (prev_draw)
588
         prev_draw->CurrentContext = NULL;
589
      if (prev_read)
590
         prev_read->CurrentContext = NULL;
591
 
592
      prev_ctx->DrawSurface = NULL;
593
      prev_ctx->ReadSurface = NULL;
594
   }
595
   else {
596
      prev_draw = prev_read = NULL;
597
   }
598
 
599
   /* establish new bindings */
600
   if (ctx) {
601
      if (draw)
602
         draw->CurrentContext = ctx;
603
      if (read)
604
         read->CurrentContext = ctx;
605
 
606
      ctx->DrawSurface = draw;
607
      ctx->ReadSurface = read;
608
   }
609
 
610
   assert(old_ctx && old_draw && old_read);
611
   *old_ctx = prev_ctx;
612
   *old_draw = prev_draw;
613
   *old_read = prev_read;
614
 
615
   printf("leave %s\n",__FUNCTION__);
616
 
617
   return EGL_TRUE;
618
}