Redo _eglInitSurface() so it can be used with all surface types.
[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 /* XXX this should be per-thread someday */
91 return _eglGlobal.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 _EGLContext *ctx = _eglLookupContext(context);
180 _EGLSurface *draw = _eglLookupSurface(d);
181 _EGLSurface *read = _eglLookupSurface(r);
182
183 _EGLContext *oldContext = _eglGetCurrentContext();
184 _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW);
185 _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ);
186
187 /* error checking */
188 if (ctx) {
189 if (draw == NULL || read == NULL) {
190 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
191 return EGL_FALSE;
192 }
193 if (draw->Config != ctx->Config) {
194 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
195 return EGL_FALSE;
196 }
197 if (read->Config != ctx->Config) {
198 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
199 return EGL_FALSE;
200 }
201 }
202
203 /*
204 * check if the old context or surfaces need to be deleted
205 */
206 if (oldDrawSurface != NULL) {
207 oldDrawSurface->IsBound = EGL_FALSE;
208 if (oldDrawSurface->DeletePending) {
209 /* make sure we don't try to rebind a deleted surface */
210 if (draw == oldDrawSurface || draw == oldReadSurface) {
211 draw = NULL;
212 }
213 /* really delete surface now */
214 drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
215 }
216 }
217 if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
218 oldReadSurface->IsBound = EGL_FALSE;
219 if (oldReadSurface->DeletePending) {
220 /* make sure we don't try to rebind a deleted surface */
221 if (read == oldDrawSurface || read == oldReadSurface) {
222 read = NULL;
223 }
224 /* really delete surface now */
225 drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
226 }
227 }
228 if (oldContext != NULL) {
229 oldContext->IsBound = EGL_FALSE;
230 if (oldContext->DeletePending) {
231 /* make sure we don't try to rebind a deleted context */
232 if (ctx == oldContext) {
233 ctx = NULL;
234 }
235 /* really delete context now */
236 drv->API.DestroyContext(drv, dpy, oldContext->Handle);
237 }
238 }
239
240 if (ctx) {
241 /* check read/draw again, in case we deleted them above */
242 if (draw == NULL || read == NULL) {
243 _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
244 return EGL_FALSE;
245 }
246 ctx->DrawSurface = draw;
247 ctx->ReadSurface = read;
248 ctx->IsBound = EGL_TRUE;
249 draw->IsBound = EGL_TRUE;
250 read->IsBound = EGL_TRUE;
251 }
252
253 _eglGlobal.CurrentContext = ctx;
254
255 return EGL_TRUE;
256 }
257
258
259 /**
260 * This is defined by the EGL_MESA_copy_context extension.
261 */
262 EGLBoolean
263 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
264 EGLContext dest, EGLint mask)
265 {
266 /* This function will always have to be overridden/implemented in the
267 * device driver. If the driver is based on Mesa, use _mesa_copy_context().
268 */
269 return EGL_FALSE;
270 }