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