egl: add copyright notices
[mesa.git] / src / egl / main / eglcontext.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "eglconfig.h"
35 #include "eglcontext.h"
36 #include "egldisplay.h"
37 #include "eglcurrent.h"
38 #include "eglsurface.h"
39 #include "egllog.h"
40
41
42 /**
43 * Return the API bit (one of EGL_xxx_BIT) of the context.
44 */
45 static EGLint
46 _eglGetContextAPIBit(_EGLContext *ctx)
47 {
48 EGLint bit = 0;
49
50 switch (ctx->ClientAPI) {
51 case EGL_OPENGL_ES_API:
52 switch (ctx->ClientVersion) {
53 case 1:
54 bit = EGL_OPENGL_ES_BIT;
55 break;
56 case 2:
57 bit = EGL_OPENGL_ES2_BIT;
58 break;
59 default:
60 break;
61 }
62 break;
63 case EGL_OPENVG_API:
64 bit = EGL_OPENVG_BIT;
65 break;
66 case EGL_OPENGL_API:
67 bit = EGL_OPENGL_BIT;
68 break;
69 default:
70 break;
71 }
72
73 return bit;
74 }
75
76
77 /**
78 * Parse the list of context attributes and return the proper error code.
79 */
80 static EGLint
81 _eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list)
82 {
83 EGLenum api = ctx->ClientAPI;
84 EGLint i, err = EGL_SUCCESS;
85
86 if (!attrib_list)
87 return EGL_SUCCESS;
88
89 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
90 EGLint attr = attrib_list[i++];
91 EGLint val = attrib_list[i];
92
93 switch (attr) {
94 case EGL_CONTEXT_CLIENT_VERSION:
95 if (api != EGL_OPENGL_ES_API) {
96 err = EGL_BAD_ATTRIBUTE;
97 break;
98 }
99 if (val != 1 && val != 2) {
100 err = EGL_BAD_ATTRIBUTE;
101 break;
102 }
103 ctx->ClientVersion = val;
104 break;
105 default:
106 err = EGL_BAD_ATTRIBUTE;
107 break;
108 }
109
110 if (err != EGL_SUCCESS) {
111 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
112 break;
113 }
114 }
115
116 return err;
117 }
118
119
120 /**
121 * Initialize the given _EGLContext object to defaults and/or the values
122 * in the attrib_list.
123 */
124 EGLBoolean
125 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
126 const EGLint *attrib_list)
127 {
128 const EGLenum api = eglQueryAPI();
129 EGLint err;
130
131 if (api == EGL_NONE) {
132 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
133 return EGL_FALSE;
134 }
135
136 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
137 ctx->ClientAPI = api;
138 ctx->Config = conf;
139 ctx->WindowRenderBuffer = EGL_NONE;
140
141 ctx->ClientVersion = 1; /* the default, per EGL spec */
142
143 err = _eglParseContextAttribList(ctx, attrib_list);
144 if (err == EGL_SUCCESS && ctx->Config) {
145 EGLint api_bit;
146
147 api_bit = _eglGetContextAPIBit(ctx);
148 if (!(ctx->Config->RenderableType & api_bit)) {
149 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
150 api_bit, ctx->Config->RenderableType);
151 err = EGL_BAD_CONFIG;
152 }
153 }
154 if (err != EGL_SUCCESS)
155 return _eglError(err, "eglCreateContext");
156
157 return EGL_TRUE;
158 }
159
160
161 #ifdef EGL_VERSION_1_2
162 static EGLint
163 _eglQueryContextRenderBuffer(_EGLContext *ctx)
164 {
165 _EGLSurface *surf = ctx->DrawSurface;
166 EGLint rb;
167
168 if (!surf)
169 return EGL_NONE;
170 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
171 rb = ctx->WindowRenderBuffer;
172 else
173 rb = surf->RenderBuffer;
174 return rb;
175 }
176 #endif /* EGL_VERSION_1_2 */
177
178
179 EGLBoolean
180 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
181 EGLint attribute, EGLint *value)
182 {
183 (void) drv;
184 (void) dpy;
185
186 if (!value)
187 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
188
189 switch (attribute) {
190 case EGL_CONFIG_ID:
191 if (!c->Config)
192 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
193 *value = c->Config->ConfigID;
194 break;
195 case EGL_CONTEXT_CLIENT_VERSION:
196 *value = c->ClientVersion;
197 break;
198 #ifdef EGL_VERSION_1_2
199 case EGL_CONTEXT_CLIENT_TYPE:
200 *value = c->ClientAPI;
201 break;
202 case EGL_RENDER_BUFFER:
203 *value = _eglQueryContextRenderBuffer(c);
204 break;
205 #endif /* EGL_VERSION_1_2 */
206 default:
207 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
208 }
209
210 return EGL_TRUE;
211 }
212
213
214 /**
215 * Bind the context to the thread and return the previous context.
216 *
217 * Note that the context may be NULL.
218 */
219 static _EGLContext *
220 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
221 {
222 EGLint apiIndex;
223 _EGLContext *oldCtx;
224
225 apiIndex = (ctx) ?
226 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
227
228 oldCtx = t->CurrentContexts[apiIndex];
229 if (ctx != oldCtx) {
230 if (oldCtx)
231 oldCtx->Binding = NULL;
232 if (ctx)
233 ctx->Binding = t;
234
235 t->CurrentContexts[apiIndex] = ctx;
236 }
237
238 return oldCtx;
239 }
240
241
242 /**
243 * Return true if the given context and surfaces can be made current.
244 */
245 static EGLBoolean
246 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
247 {
248 _EGLThreadInfo *t = _eglGetCurrentThread();
249 _EGLDisplay *dpy;
250 EGLint conflict_api;
251 EGLBoolean surfaceless;
252
253 if (_eglIsCurrentThreadDummy())
254 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
255
256 /* this is easy */
257 if (!ctx) {
258 if (draw || read)
259 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
260 return EGL_TRUE;
261 }
262
263 dpy = ctx->Resource.Display;
264 switch (_eglGetContextAPIBit(ctx)) {
265 case EGL_OPENGL_ES_BIT:
266 surfaceless = dpy->Extensions.KHR_surfaceless_gles1;
267 break;
268 case EGL_OPENGL_ES2_BIT:
269 surfaceless = dpy->Extensions.KHR_surfaceless_gles2;
270 break;
271 case EGL_OPENGL_BIT:
272 surfaceless = dpy->Extensions.KHR_surfaceless_opengl;
273 break;
274 default:
275 surfaceless = EGL_FALSE;
276 break;
277 }
278
279 if (!surfaceless && (draw == NULL || read == NULL))
280 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
281
282 /*
283 * The spec says
284 *
285 * "If ctx is current to some other thread, or if either draw or read are
286 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
287 * generated."
288 *
289 * and
290 *
291 * "at most one context may be bound to a particular surface at a given
292 * time"
293 */
294 if (ctx->Binding && ctx->Binding != t)
295 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
296 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
297 if (draw->CurrentContext->Binding != t ||
298 draw->CurrentContext->ClientAPI != ctx->ClientAPI)
299 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
300 }
301 if (read && read->CurrentContext && read->CurrentContext != ctx) {
302 if (read->CurrentContext->Binding != t ||
303 read->CurrentContext->ClientAPI != ctx->ClientAPI)
304 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
305 }
306
307 /* simply require the configs to be equal */
308 if ((draw && draw->Config != ctx->Config) ||
309 (read && read->Config != ctx->Config))
310 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
311
312 switch (ctx->ClientAPI) {
313 #ifdef EGL_VERSION_1_4
314 /* OpenGL and OpenGL ES are conflicting */
315 case EGL_OPENGL_ES_API:
316 conflict_api = EGL_OPENGL_API;
317 break;
318 case EGL_OPENGL_API:
319 conflict_api = EGL_OPENGL_ES_API;
320 break;
321 #endif
322 default:
323 conflict_api = -1;
324 break;
325 }
326
327 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
328 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
329
330 return EGL_TRUE;
331 }
332
333
334 /**
335 * Bind the context to the current thread and given surfaces. Return the
336 * previous bound context and surfaces. The caller should unreference the
337 * returned context and surfaces.
338 *
339 * Making a second call with the resources returned by the first call
340 * unsurprisingly undoes the first call, except for the resouce reference
341 * counts.
342 */
343 EGLBoolean
344 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
345 _EGLContext **old_ctx,
346 _EGLSurface **old_draw, _EGLSurface **old_read)
347 {
348 _EGLThreadInfo *t = _eglGetCurrentThread();
349 _EGLContext *prev_ctx;
350 _EGLSurface *prev_draw, *prev_read;
351
352 if (!_eglCheckMakeCurrent(ctx, draw, read))
353 return EGL_FALSE;
354
355 /* increment refcounts before binding */
356 _eglGetContext(ctx);
357 _eglGetSurface(draw);
358 _eglGetSurface(read);
359
360 /* bind the new context */
361 prev_ctx = _eglBindContextToThread(ctx, t);
362
363 /* break previous bindings */
364 if (prev_ctx) {
365 prev_draw = prev_ctx->DrawSurface;
366 prev_read = prev_ctx->ReadSurface;
367
368 if (prev_draw)
369 prev_draw->CurrentContext = NULL;
370 if (prev_read)
371 prev_read->CurrentContext = NULL;
372
373 prev_ctx->DrawSurface = NULL;
374 prev_ctx->ReadSurface = NULL;
375 }
376 else {
377 prev_draw = prev_read = NULL;
378 }
379
380 /* establish new bindings */
381 if (ctx) {
382 if (draw)
383 draw->CurrentContext = ctx;
384 if (read)
385 read->CurrentContext = ctx;
386
387 ctx->DrawSurface = draw;
388 ctx->ReadSurface = read;
389 }
390
391 assert(old_ctx && old_draw && old_read);
392 *old_ctx = prev_ctx;
393 *old_draw = prev_draw;
394 *old_read = prev_read;
395
396 return EGL_TRUE;
397 }