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