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