some initial EGL 1.2 work
[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 #ifdef EGL_VERSION_1_2
164 case EGL_CONTEXT_CLIENT_TYPE:
165 *value = c->ClientAPI;
166 return EGL_FALSE;
167 #endif /* EGL_VERSION_1_2 */
168 default:
169 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
170 return EGL_FALSE;
171 }
172 }
173
174
175 /**
176 * Drivers will typically call this to do the error checking and
177 * update the various IsBound and DeletePending flags.
178 * Then, the driver will do its device-dependent Make-Current stuff.
179 */
180 EGLBoolean
181 _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
182 EGLSurface r, EGLContext context)
183 {
184 _EGLThreadInfo *t = _eglGetCurrentThread();
185 _EGLContext *ctx = _eglLookupContext(context);
186 _EGLSurface *draw = _eglLookupSurface(d);
187 _EGLSurface *read = _eglLookupSurface(r);
188
189 _EGLContext *oldContext = _eglGetCurrentContext();
190 _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW);
191 _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ);
192
193 /* error checking */
194 if (ctx) {
195 if (draw == NULL || read == NULL) {
196 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
197 return EGL_FALSE;
198 }
199 if (draw->Config != ctx->Config) {
200 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
201 return EGL_FALSE;
202 }
203 if (read->Config != ctx->Config) {
204 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
205 return EGL_FALSE;
206 }
207 }
208
209 /*
210 * check if the old context or surfaces need to be deleted
211 */
212 if (oldDrawSurface != NULL) {
213 oldDrawSurface->IsBound = EGL_FALSE;
214 if (oldDrawSurface->DeletePending) {
215 /* make sure we don't try to rebind a deleted surface */
216 if (draw == oldDrawSurface || draw == oldReadSurface) {
217 draw = NULL;
218 }
219 /* really delete surface now */
220 drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
221 }
222 }
223 if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
224 oldReadSurface->IsBound = EGL_FALSE;
225 if (oldReadSurface->DeletePending) {
226 /* make sure we don't try to rebind a deleted surface */
227 if (read == oldDrawSurface || read == oldReadSurface) {
228 read = NULL;
229 }
230 /* really delete surface now */
231 drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
232 }
233 }
234 if (oldContext != NULL) {
235 oldContext->IsBound = EGL_FALSE;
236 if (oldContext->DeletePending) {
237 /* make sure we don't try to rebind a deleted context */
238 if (ctx == oldContext) {
239 ctx = NULL;
240 }
241 /* really delete context now */
242 drv->API.DestroyContext(drv, dpy, oldContext->Handle);
243 }
244 }
245
246 if (ctx) {
247 /* check read/draw again, in case we deleted them above */
248 if (draw == NULL || read == NULL) {
249 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
250 return EGL_FALSE;
251 }
252 ctx->DrawSurface = draw;
253 ctx->ReadSurface = read;
254 ctx->IsBound = EGL_TRUE;
255 draw->IsBound = EGL_TRUE;
256 read->IsBound = EGL_TRUE;
257 }
258
259 t->CurrentContext = ctx;
260
261 return EGL_TRUE;
262 }
263
264
265 /**
266 * This is defined by the EGL_MESA_copy_context extension.
267 */
268 EGLBoolean
269 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
270 EGLContext dest, EGLint mask)
271 {
272 /* This function will always have to be overridden/implemented in the
273 * device driver. If the driver is based on Mesa, use _mesa_copy_context().
274 */
275 return EGL_FALSE;
276 }