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