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