Merge branch 'vbo_clean'
[mesa.git] / src / egl / main / eglcontext.c
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 */
16 EGLBoolean
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 if (!conf) {
29 _eglError(EGL_BAD_CONFIG, "_eglInitContext");
30 return EGL_FALSE;
31 }
32
33 memset(ctx, 0, sizeof(_EGLContext));
34
35 ctx->ClientVersion = 1; /* the default, per EGL spec */
36
37 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
38 switch (attrib_list[i]) {
39 case EGL_CONTEXT_CLIENT_VERSION:
40 i++;
41 ctx->ClientVersion = attrib_list[i];
42 break;
43 default:
44 _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext");
45 return EGL_FALSE;
46 }
47 }
48
49 ctx->Config = conf;
50 ctx->DrawSurface = EGL_NO_SURFACE;
51 ctx->ReadSurface = EGL_NO_SURFACE;
52 ctx->ClientAPI = api;
53
54 return EGL_TRUE;
55 }
56
57
58 /**
59 * Just a placeholder/demo function. Real driver will never use this!
60 */
61 EGLContext
62 _eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
63 EGLContext share_list, const EGLint *attrib_list)
64 {
65 #if 0 /* example code */
66 _EGLContext *context;
67 _EGLConfig *conf;
68
69 conf = _eglLookupConfig(drv, dpy, config);
70 if (!conf) {
71 _eglError(EGL_BAD_CONFIG, "eglCreateContext");
72 return EGL_NO_CONTEXT;
73 }
74
75 context = (_EGLContext *) calloc(1, sizeof(_EGLContext));
76 if (!context)
77 return EGL_NO_CONTEXT;
78
79 if (!_eglInitContext(drv, context, conf, attrib_list)) {
80 free(context);
81 return EGL_NO_CONTEXT;
82 }
83
84 return _eglLinkContext(context, _eglLookupDisplay(dpy));
85 #endif
86 return EGL_NO_CONTEXT;
87 }
88
89
90 /**
91 * Default fallback routine - drivers should usually override this.
92 */
93 EGLBoolean
94 _eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
95 {
96 _EGLContext *context = _eglLookupContext(ctx);
97 if (context) {
98 _eglUnlinkContext(context);
99 if (!_eglIsContextBound(context))
100 free(context);
101 return EGL_TRUE;
102 }
103 else {
104 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
105 return EGL_TRUE;
106 }
107 }
108
109
110 EGLBoolean
111 _eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx,
112 EGLint attribute, EGLint *value)
113 {
114 _EGLContext *c = _eglLookupContext(ctx);
115
116 (void) drv;
117 (void) dpy;
118
119 if (!c) {
120 _eglError(EGL_BAD_CONTEXT, "eglQueryContext");
121 return EGL_FALSE;
122 }
123
124 switch (attribute) {
125 case EGL_CONFIG_ID:
126 *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
127 return EGL_TRUE;
128 #ifdef EGL_VERSION_1_2
129 case EGL_CONTEXT_CLIENT_TYPE:
130 *value = c->ClientAPI;
131 return EGL_TRUE;
132 #endif /* EGL_VERSION_1_2 */
133 case EGL_CONTEXT_CLIENT_VERSION:
134 *value = c->ClientVersion;
135 return EGL_TRUE;
136 default:
137 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
138 return EGL_FALSE;
139 }
140 }
141
142
143 /**
144 * Drivers will typically call this to do the error checking and
145 * update the various flags.
146 * Then, the driver will do its device-dependent Make-Current stuff.
147 */
148 EGLBoolean
149 _eglMakeCurrent(_EGLDriver *drv, EGLDisplay display, EGLSurface d,
150 EGLSurface r, EGLContext context)
151 {
152 _EGLThreadInfo *t = _eglGetCurrentThread();
153 _EGLDisplay *dpy = _eglLookupDisplay(display);
154 _EGLContext *ctx = _eglLookupContext(context);
155 _EGLSurface *draw = _eglLookupSurface(d);
156 _EGLSurface *read = _eglLookupSurface(r);
157 _EGLContext *oldContext = NULL;
158 _EGLSurface *oldDrawSurface = NULL;
159 _EGLSurface *oldReadSurface = NULL;
160 EGLint apiIndex;
161
162 if (_eglIsCurrentThreadDummy())
163 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
164 if (dpy == NULL)
165 return _eglError(EGL_BAD_DISPLAY, "eglMakeCurrent");
166
167 if (ctx) {
168 /* error checking */
169 if (ctx->Binding && ctx->Binding != t)
170 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
171 if (draw == NULL || read == NULL) {
172 EGLint err = (d == EGL_NO_SURFACE || r == EGL_NO_SURFACE)
173 ? EGL_BAD_MATCH : EGL_BAD_SURFACE;
174 return _eglError(err, "eglMakeCurrent");
175 }
176 if (draw->Config != ctx->Config || read->Config != ctx->Config)
177 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
178 if ((draw->Binding && draw->Binding->Binding != t) ||
179 (read->Binding && read->Binding->Binding != t))
180 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
181
182 #ifdef EGL_VERSION_1_4
183 /* OpenGL and OpenGL ES are conflicting */
184 switch (ctx->ClientAPI) {
185 case EGL_OPENGL_ES_API:
186 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)])
187 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
188 break;
189 case EGL_OPENGL_API:
190 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)])
191 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
192 break;
193 default:
194 break;
195 }
196 #endif
197 apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
198 }
199 else {
200 if (context != EGL_NO_CONTEXT)
201 return _eglError(EGL_BAD_CONTEXT, "eglMakeCurrent");
202 if (draw != NULL || read != NULL)
203 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
204 apiIndex = t->CurrentAPIIndex;
205 }
206
207 oldContext = t->CurrentContexts[apiIndex];
208 if (oldContext) {
209 oldDrawSurface = oldContext->DrawSurface;
210 oldReadSurface = oldContext->ReadSurface;
211 assert(oldDrawSurface);
212 assert(oldReadSurface);
213
214 /* break old bindings */
215 t->CurrentContexts[apiIndex] = NULL;
216 oldContext->Binding = NULL;
217 oldContext->DrawSurface = NULL;
218 oldContext->ReadSurface = NULL;
219 oldDrawSurface->Binding = NULL;
220 oldReadSurface->Binding = NULL;
221
222 /*
223 * check if the old context or surfaces need to be deleted
224 * FIXME They are linked so that they can be unlinked. This is ugly.
225 */
226 if (!_eglIsSurfaceLinked(oldDrawSurface)) {
227 assert(draw != oldDrawSurface && read != oldDrawSurface);
228 drv->API.DestroySurface(drv, display,
229 _eglLinkSurface(oldDrawSurface, dpy));
230 }
231 if (oldReadSurface != oldDrawSurface &&
232 !_eglIsSurfaceLinked(oldReadSurface)) {
233 assert(draw != oldReadSurface && read != oldReadSurface);
234 drv->API.DestroySurface(drv, display,
235 _eglLinkSurface(oldReadSurface, dpy));
236 }
237 if (!_eglIsContextLinked(oldContext)) {
238 assert(ctx != oldContext);
239 drv->API.DestroyContext(drv, display,
240 _eglLinkContext(oldContext, dpy));
241 }
242 }
243
244 /* build new bindings */
245 if (ctx) {
246 t->CurrentContexts[apiIndex] = ctx;
247 ctx->Binding = t;
248 ctx->DrawSurface = draw;
249 ctx->ReadSurface = read;
250 draw->Binding = ctx;
251 read->Binding = ctx;
252 }
253
254 return EGL_TRUE;
255 }
256
257
258 /**
259 * This is defined by the EGL_MESA_copy_context extension.
260 */
261 EGLBoolean
262 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
263 EGLContext dest, EGLint mask)
264 {
265 /* This function will always have to be overridden/implemented in the
266 * device driver. If the driver is based on Mesa, use _mesa_copy_context().
267 */
268 return EGL_FALSE;
269 }