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