egl: Replace IsBound by a pointer to the binding.
[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 dpy, EGLSurface d,
150 EGLSurface r, EGLContext context)
151 {
152 _EGLThreadInfo *t = _eglGetCurrentThread();
153 _EGLContext *ctx = _eglLookupContext(context);
154 _EGLSurface *draw = _eglLookupSurface(d);
155 _EGLSurface *read = _eglLookupSurface(r);
156 _EGLContext *oldContext = NULL;
157 _EGLSurface *oldDrawSurface = NULL;
158 _EGLSurface *oldReadSurface = NULL;
159 EGLint apiIndex;
160
161 if (_eglIsCurrentThreadDummy())
162 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
163
164 /* error checking */
165 if (ctx) {
166 if (draw == NULL || read == NULL) {
167 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
168 return EGL_FALSE;
169 }
170 if (draw->Config != ctx->Config) {
171 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
172 return EGL_FALSE;
173 }
174 if (read->Config != ctx->Config) {
175 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
176 return EGL_FALSE;
177 }
178
179 #ifdef EGL_VERSION_1_4
180 /* OpenGL and OpenGL ES are conflicting */
181 switch (ctx->ClientAPI) {
182 case EGL_OPENGL_ES_API:
183 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)])
184 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
185 break;
186 case EGL_OPENGL_API:
187 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)])
188 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
189 break;
190 default:
191 break;
192 }
193 #endif
194 apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
195 }
196 else {
197 apiIndex = t->CurrentAPIIndex;
198 }
199
200 oldContext = t->CurrentContexts[apiIndex];
201 if (oldContext) {
202 oldDrawSurface = oldContext->DrawSurface;
203 oldReadSurface = oldContext->ReadSurface;
204 }
205
206 /*
207 * check if the old context or surfaces need to be deleted
208 */
209 if (oldDrawSurface != NULL) {
210 oldDrawSurface->Binding = NULL;
211 if (!_eglIsSurfaceLinked(oldDrawSurface)) {
212 /* make sure we don't try to rebind a deleted surface */
213 if (draw == oldDrawSurface || draw == oldReadSurface) {
214 draw = NULL;
215 }
216 /* really delete surface now */
217 drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
218 }
219 }
220 if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
221 oldReadSurface->Binding = NULL;
222 if (!_eglIsSurfaceLinked(oldReadSurface)) {
223 /* make sure we don't try to rebind a deleted surface */
224 if (read == oldDrawSurface || read == oldReadSurface) {
225 read = NULL;
226 }
227 /* really delete surface now */
228 drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
229 }
230 }
231 if (oldContext != NULL) {
232 oldContext->Binding = NULL;
233 if (!_eglIsContextLinked(oldContext)) {
234 /* make sure we don't try to rebind a deleted context */
235 if (ctx == oldContext) {
236 ctx = NULL;
237 }
238 /* really delete context now */
239 drv->API.DestroyContext(drv, dpy, _eglGetContextHandle(oldContext));
240 }
241 }
242
243 if (ctx) {
244 /* check read/draw again, in case we deleted them above */
245 if (draw == NULL || read == NULL) {
246 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
247 return EGL_FALSE;
248 }
249 ctx->DrawSurface = draw;
250 ctx->ReadSurface = read;
251 ctx->Binding = t;
252 draw->Binding = ctx;
253 read->Binding = ctx;
254 t->CurrentContexts[apiIndex] = ctx;
255 }
256 else {
257 t->CurrentContexts[apiIndex] = NULL;
258 }
259
260 return EGL_TRUE;
261 }
262
263
264 /**
265 * This is defined by the EGL_MESA_copy_context extension.
266 */
267 EGLBoolean
268 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
269 EGLContext dest, EGLint mask)
270 {
271 /* This function will always have to be overridden/implemented in the
272 * device driver. If the driver is based on Mesa, use _mesa_copy_context().
273 */
274 return EGL_FALSE;
275 }