egl: Add funtions to link contexts and surfaces to displays.
[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, EGLDisplay dpy, _EGLContext *ctx,
18 EGLConfig config, const EGLint *attrib_list)
19 {
20 _EGLConfig *conf;
21 _EGLDisplay *display = _eglLookupDisplay(dpy);
22 EGLint i;
23 const EGLenum api = eglQueryAPI();
24
25 if (api == EGL_NONE) {
26 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
27 return EGL_FALSE;
28 }
29
30 conf = _eglLookupConfig(drv, dpy, config);
31 if (!conf) {
32 _eglError(EGL_BAD_CONFIG, "_eglInitContext");
33 return EGL_FALSE;
34 }
35
36 memset(ctx, 0, sizeof(_EGLContext));
37
38 ctx->ClientVersion = 1; /* the default, per EGL spec */
39
40 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
41 switch (attrib_list[i]) {
42 case EGL_CONTEXT_CLIENT_VERSION:
43 i++;
44 ctx->ClientVersion = attrib_list[i];
45 break;
46 default:
47 _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext");
48 return EGL_FALSE;
49 }
50 }
51
52 ctx->Display = display;
53 ctx->Config = conf;
54 ctx->DrawSurface = EGL_NO_SURFACE;
55 ctx->ReadSurface = EGL_NO_SURFACE;
56 ctx->ClientAPI = api;
57
58 return EGL_TRUE;
59 }
60
61
62 /**
63 * Save a new _EGLContext into the hash table.
64 */
65 void
66 _eglSaveContext(_EGLContext *ctx)
67 {
68 /* no-op.
69 * Public EGLContext handle and private _EGLContext are the same.
70 */
71 }
72
73
74 /**
75 * Remove the given _EGLContext object from the hash table.
76 */
77 void
78 _eglRemoveContext(_EGLContext *ctx)
79 {
80 /* no-op.
81 * Public EGLContext handle and private _EGLContext are the same.
82 */
83 }
84
85
86 /**
87 * Just a placeholder/demo function. Real driver will never use this!
88 */
89 EGLContext
90 _eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
91 EGLContext share_list, const EGLint *attrib_list)
92 {
93 #if 0 /* example code */
94 _EGLContext *context;
95
96 context = (_EGLContext *) calloc(1, sizeof(_EGLContext));
97 if (!context)
98 return EGL_NO_CONTEXT;
99
100 if (!_eglInitContext(drv, dpy, context, config, attrib_list)) {
101 free(context);
102 return EGL_NO_CONTEXT;
103 }
104
105 _eglSaveContext(context);
106 return (EGLContext) context;
107 #endif
108 return EGL_NO_CONTEXT;
109 }
110
111
112 /**
113 * Default fallback routine - drivers should usually override this.
114 */
115 EGLBoolean
116 _eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
117 {
118 _EGLContext *context = _eglLookupContext(ctx);
119 if (context) {
120 if (context->IsBound) {
121 context->DeletePending = EGL_TRUE;
122 }
123 else {
124 free(context);
125 }
126 return EGL_TRUE;
127 }
128 else {
129 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
130 return EGL_TRUE;
131 }
132 }
133
134
135 EGLBoolean
136 _eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx,
137 EGLint attribute, EGLint *value)
138 {
139 _EGLContext *c = _eglLookupContext(ctx);
140
141 (void) drv;
142 (void) dpy;
143
144 if (!c) {
145 _eglError(EGL_BAD_CONTEXT, "eglQueryContext");
146 return EGL_FALSE;
147 }
148
149 switch (attribute) {
150 case EGL_CONFIG_ID:
151 *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
152 return EGL_TRUE;
153 #ifdef EGL_VERSION_1_2
154 case EGL_CONTEXT_CLIENT_TYPE:
155 *value = c->ClientAPI;
156 return EGL_TRUE;
157 #endif /* EGL_VERSION_1_2 */
158 case EGL_CONTEXT_CLIENT_VERSION:
159 *value = c->ClientVersion;
160 return EGL_TRUE;
161 default:
162 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
163 return EGL_FALSE;
164 }
165 }
166
167
168 /**
169 * Drivers will typically call this to do the error checking and
170 * update the various IsBound and DeletePending flags.
171 * Then, the driver will do its device-dependent Make-Current stuff.
172 */
173 EGLBoolean
174 _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
175 EGLSurface r, EGLContext context)
176 {
177 _EGLThreadInfo *t = _eglGetCurrentThread();
178 _EGLContext *ctx = _eglLookupContext(context);
179 _EGLSurface *draw = _eglLookupSurface(d);
180 _EGLSurface *read = _eglLookupSurface(r);
181 _EGLContext *oldContext = NULL;
182 _EGLSurface *oldDrawSurface = NULL;
183 _EGLSurface *oldReadSurface = NULL;
184 EGLint apiIndex;
185
186 if (_eglIsCurrentThreadDummy())
187 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
188
189 /* error checking */
190 if (ctx) {
191 if (draw == NULL || read == NULL) {
192 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
193 return EGL_FALSE;
194 }
195 if (draw->Config != ctx->Config) {
196 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
197 return EGL_FALSE;
198 }
199 if (read->Config != ctx->Config) {
200 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
201 return EGL_FALSE;
202 }
203
204 #ifdef EGL_VERSION_1_4
205 /* OpenGL and OpenGL ES are conflicting */
206 switch (ctx->ClientAPI) {
207 case EGL_OPENGL_ES_API:
208 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)])
209 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
210 break;
211 case EGL_OPENGL_API:
212 if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)])
213 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
214 break;
215 default:
216 break;
217 }
218 #endif
219 apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
220 }
221 else {
222 apiIndex = t->CurrentAPIIndex;
223 }
224
225 oldContext = t->CurrentContexts[apiIndex];
226 if (oldContext) {
227 oldDrawSurface = oldContext->DrawSurface;
228 oldReadSurface = oldContext->ReadSurface;
229 }
230
231 /*
232 * check if the old context or surfaces need to be deleted
233 */
234 if (oldDrawSurface != NULL) {
235 oldDrawSurface->IsBound = EGL_FALSE;
236 if (oldDrawSurface->DeletePending) {
237 /* make sure we don't try to rebind a deleted surface */
238 if (draw == oldDrawSurface || draw == oldReadSurface) {
239 draw = NULL;
240 }
241 /* really delete surface now */
242 drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
243 }
244 }
245 if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
246 oldReadSurface->IsBound = EGL_FALSE;
247 if (oldReadSurface->DeletePending) {
248 /* make sure we don't try to rebind a deleted surface */
249 if (read == oldDrawSurface || read == oldReadSurface) {
250 read = NULL;
251 }
252 /* really delete surface now */
253 drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
254 }
255 }
256 if (oldContext != NULL) {
257 oldContext->IsBound = EGL_FALSE;
258 if (oldContext->DeletePending) {
259 /* make sure we don't try to rebind a deleted context */
260 if (ctx == oldContext) {
261 ctx = NULL;
262 }
263 /* really delete context now */
264 drv->API.DestroyContext(drv, dpy, _eglGetContextHandle(oldContext));
265 }
266 }
267
268 if (ctx) {
269 /* check read/draw again, in case we deleted them above */
270 if (draw == NULL || read == NULL) {
271 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
272 return EGL_FALSE;
273 }
274 ctx->DrawSurface = draw;
275 ctx->ReadSurface = read;
276 ctx->IsBound = EGL_TRUE;
277 draw->IsBound = EGL_TRUE;
278 read->IsBound = EGL_TRUE;
279 t->CurrentContexts[apiIndex] = ctx;
280 }
281 else {
282 t->CurrentContexts[apiIndex] = NULL;
283 }
284
285 return EGL_TRUE;
286 }
287
288
289 /**
290 * This is defined by the EGL_MESA_copy_context extension.
291 */
292 EGLBoolean
293 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
294 EGLContext dest, EGLint mask)
295 {
296 /* This function will always have to be overridden/implemented in the
297 * device driver. If the driver is based on Mesa, use _mesa_copy_context().
298 */
299 return EGL_FALSE;
300 }