eglcontext.c revision 4a49301e
1#include <assert.h>
2#include <stdlib.h>
3#include <string.h>
4#include "eglconfig.h"
5#include "eglcontext.h"
6#include "egldisplay.h"
7#include "egldriver.h"
8#include "eglglobals.h"
9#include "eglsurface.h"
10
11
12/**
13 * Initialize the given _EGLContext object to defaults and/or the values
14 * in the attrib_list.
15 */
16EGLBoolean
17_eglInitContext(_EGLDriver *drv, _EGLContext *ctx,
18                _EGLConfig *conf, const EGLint *attrib_list)
19{
20   EGLint i;
21   const EGLenum api = eglQueryAPI();
22
23   if (api == EGL_NONE) {
24      _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
25      return EGL_FALSE;
26   }
27
28   memset(ctx, 0, sizeof(_EGLContext));
29
30   ctx->ClientVersion = 1; /* the default, per EGL spec */
31
32   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
33      switch (attrib_list[i]) {
34      case EGL_CONTEXT_CLIENT_VERSION:
35         i++;
36         ctx->ClientVersion = attrib_list[i];
37         break;
38      default:
39         _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext");
40         return EGL_FALSE;
41      }
42   }
43
44   ctx->Config = conf;
45   ctx->DrawSurface = EGL_NO_SURFACE;
46   ctx->ReadSurface = EGL_NO_SURFACE;
47   ctx->ClientAPI = api;
48   ctx->WindowRenderBuffer = EGL_NONE;
49
50   return EGL_TRUE;
51}
52
53
54/**
55 * Just a placeholder/demo function.  Real driver will never use this!
56 */
57_EGLContext *
58_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
59                  _EGLContext *share_list, const EGLint *attrib_list)
60{
61#if 0 /* example code */
62   _EGLContext *context;
63
64   context = (_EGLContext *) calloc(1, sizeof(_EGLContext));
65   if (!context)
66      return NULL;
67
68   if (!_eglInitContext(drv, context, conf, attrib_list)) {
69      free(context);
70      return NULL;
71   }
72
73   return context;
74#endif
75   return NULL;
76}
77
78
79/**
80 * Default fallback routine - drivers should usually override this.
81 */
82EGLBoolean
83_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
84{
85   if (!_eglIsContextBound(ctx))
86      free(ctx);
87   return EGL_TRUE;
88}
89
90
91#ifdef EGL_VERSION_1_2
92static EGLint
93_eglQueryContextRenderBuffer(_EGLContext *ctx)
94{
95   _EGLSurface *surf = ctx->DrawSurface;
96   EGLint rb;
97
98   if (!surf)
99      return EGL_NONE;
100   if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
101      rb = ctx->WindowRenderBuffer;
102   else
103      rb = surf->RenderBuffer;
104   return rb;
105}
106#endif /* EGL_VERSION_1_2 */
107
108
109EGLBoolean
110_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
111                 EGLint attribute, EGLint *value)
112{
113   (void) drv;
114   (void) dpy;
115
116   if (!value)
117      return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
118
119   switch (attribute) {
120   case EGL_CONFIG_ID:
121      *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
122      break;
123   case EGL_CONTEXT_CLIENT_VERSION:
124      *value = c->ClientVersion;
125      break;
126#ifdef EGL_VERSION_1_2
127   case EGL_CONTEXT_CLIENT_TYPE:
128      *value = c->ClientAPI;
129      break;
130   case EGL_RENDER_BUFFER:
131      *value = _eglQueryContextRenderBuffer(c);
132      break;
133#endif /* EGL_VERSION_1_2 */
134   default:
135      return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
136   }
137
138   return EGL_TRUE;
139}
140
141
142/**
143 * Drivers will typically call this to do the error checking and
144 * update the various flags.
145 * Then, the driver will do its device-dependent Make-Current stuff.
146 */
147EGLBoolean
148_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
149                _EGLSurface *read, _EGLContext *ctx)
150{
151   _EGLThreadInfo *t = _eglGetCurrentThread();
152   _EGLContext *oldContext = NULL;
153   _EGLSurface *oldDrawSurface = NULL;
154   _EGLSurface *oldReadSurface = NULL;
155   EGLint apiIndex;
156
157   if (_eglIsCurrentThreadDummy())
158      return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
159
160   if (ctx) {
161      /* error checking */
162      if (ctx->Binding && ctx->Binding != t)
163         return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
164      if (draw == NULL || read == NULL)
165         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
166      if (draw->Config != ctx->Config || read->Config != ctx->Config)
167         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
168      if ((draw->Binding && draw->Binding->Binding != t) ||
169          (read->Binding && read->Binding->Binding != t))
170         return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
171
172#ifdef EGL_VERSION_1_4
173      /* OpenGL and OpenGL ES are conflicting */
174      switch (ctx->ClientAPI) {
175      case EGL_OPENGL_ES_API:
176         if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)])
177            return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
178         break;
179      case EGL_OPENGL_API:
180         if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)])
181            return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
182         break;
183      default:
184         break;
185      }
186#endif
187      apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
188   }
189   else {
190      if (draw != NULL || read != NULL)
191         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
192      apiIndex = t->CurrentAPIIndex;
193   }
194
195   oldContext = t->CurrentContexts[apiIndex];
196   if (oldContext) {
197      oldDrawSurface = oldContext->DrawSurface;
198      oldReadSurface = oldContext->ReadSurface;
199      assert(oldDrawSurface);
200      assert(oldReadSurface);
201
202      /* break old bindings */
203      t->CurrentContexts[apiIndex] = NULL;
204      oldContext->Binding = NULL;
205      oldContext->DrawSurface = NULL;
206      oldContext->ReadSurface = NULL;
207      oldDrawSurface->Binding = NULL;
208      oldReadSurface->Binding = NULL;
209
210      /*
211       * check if the old context or surfaces need to be deleted
212       */
213      if (!_eglIsSurfaceLinked(oldDrawSurface)) {
214         assert(draw != oldDrawSurface && read != oldDrawSurface);
215         drv->API.DestroySurface(drv, dpy, oldDrawSurface);
216      }
217      if (oldReadSurface != oldDrawSurface &&
218          !_eglIsSurfaceLinked(oldReadSurface)) {
219         assert(draw != oldReadSurface && read != oldReadSurface);
220         drv->API.DestroySurface(drv, dpy, oldReadSurface);
221      }
222      if (!_eglIsContextLinked(oldContext)) {
223         assert(ctx != oldContext);
224         drv->API.DestroyContext(drv, dpy, oldContext);
225      }
226   }
227
228   /* build new bindings */
229   if (ctx) {
230      t->CurrentContexts[apiIndex] = ctx;
231      ctx->Binding = t;
232      ctx->DrawSurface = draw;
233      ctx->ReadSurface = read;
234      draw->Binding = ctx;
235      read->Binding = ctx;
236   }
237
238   return EGL_TRUE;
239}
240
241
242/**
243 * This is defined by the EGL_MESA_copy_context extension.
244 */
245EGLBoolean
246_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
247                    EGLContext dest, EGLint mask)
248{
249   /* This function will always have to be overridden/implemented in the
250    * device driver.  If the driver is based on Mesa, use _mesa_copy_context().
251    */
252   return EGL_FALSE;
253}
254