egl: Add extension infrastructure for EGL_EXT_buffer_age
[mesa.git] / src / egl / main / eglsurface.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 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 /**
32 * Surface-related functions.
33 */
34
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "egldisplay.h"
40 #include "egldriver.h"
41 #include "eglcontext.h"
42 #include "eglconfig.h"
43 #include "eglcurrent.h"
44 #include "egllog.h"
45 #include "eglsurface.h"
46
47
48 static void
49 _eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
50 {
51 EGLint bound = surf->Config->MaxSwapInterval;
52 if (interval >= bound) {
53 interval = bound;
54 }
55 else {
56 bound = surf->Config->MinSwapInterval;
57 if (interval < bound)
58 interval = bound;
59 }
60 surf->SwapInterval = interval;
61 }
62
63
64 #ifdef EGL_MESA_screen_surface
65 static EGLint
66 _eglParseScreenSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
67 {
68 EGLint i, err = EGL_SUCCESS;
69
70 if (!attrib_list)
71 return EGL_SUCCESS;
72
73 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
74 EGLint attr = attrib_list[i++];
75 EGLint val = attrib_list[i];
76
77 switch (attr) {
78 case EGL_WIDTH:
79 if (val < 0) {
80 err = EGL_BAD_PARAMETER;
81 break;
82 }
83 surf->Width = val;
84 break;
85 case EGL_HEIGHT:
86 if (val < 0) {
87 err = EGL_BAD_PARAMETER;
88 break;
89 }
90 surf->Height = val;
91 break;
92 default:
93 err = EGL_BAD_ATTRIBUTE;
94 break;
95 }
96
97 if (err != EGL_SUCCESS) {
98 _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
99 break;
100 }
101 }
102
103 return err;
104 }
105 #endif /* EGL_MESA_screen_surface */
106
107
108 /**
109 * Parse the list of surface attributes and return the proper error code.
110 */
111 static EGLint
112 _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
113 {
114 _EGLDisplay *dpy = surf->Resource.Display;
115 EGLint type = surf->Type;
116 EGLint texture_type = EGL_PBUFFER_BIT;
117 EGLint i, err = EGL_SUCCESS;
118
119 if (!attrib_list)
120 return EGL_SUCCESS;
121
122 #ifdef EGL_MESA_screen_surface
123 if (type == EGL_SCREEN_BIT_MESA)
124 return _eglParseScreenSurfaceAttribList(surf, attrib_list);
125 #endif
126
127 if (dpy->Extensions.NOK_texture_from_pixmap)
128 texture_type |= EGL_PIXMAP_BIT;
129
130 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
131 EGLint attr = attrib_list[i++];
132 EGLint val = attrib_list[i];
133
134 switch (attr) {
135 /* common attributes */
136 case EGL_VG_COLORSPACE:
137 switch (val) {
138 case EGL_VG_COLORSPACE_sRGB:
139 case EGL_VG_COLORSPACE_LINEAR:
140 break;
141 default:
142 err = EGL_BAD_ATTRIBUTE;
143 break;
144 }
145 if (err != EGL_SUCCESS)
146 break;
147 surf->VGColorspace = val;
148 break;
149 case EGL_VG_ALPHA_FORMAT:
150 switch (val) {
151 case EGL_VG_ALPHA_FORMAT_NONPRE:
152 case EGL_VG_ALPHA_FORMAT_PRE:
153 break;
154 default:
155 err = EGL_BAD_ATTRIBUTE;
156 break;
157 }
158 if (err != EGL_SUCCESS)
159 break;
160 surf->VGAlphaFormat = val;
161 break;
162 /* window surface attributes */
163 case EGL_RENDER_BUFFER:
164 if (type != EGL_WINDOW_BIT) {
165 err = EGL_BAD_ATTRIBUTE;
166 break;
167 }
168 if (val != EGL_BACK_BUFFER && val != EGL_SINGLE_BUFFER) {
169 err = EGL_BAD_ATTRIBUTE;
170 break;
171 }
172 surf->RenderBuffer = val;
173 break;
174 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
175 if (!dpy->Extensions.NV_post_sub_buffer ||
176 type != EGL_WINDOW_BIT) {
177 err = EGL_BAD_ATTRIBUTE;
178 break;
179 }
180 if (val != EGL_TRUE && val != EGL_FALSE) {
181 err = EGL_BAD_PARAMETER;
182 break;
183 }
184 surf->PostSubBufferSupportedNV = val;
185 break;
186 /* pbuffer surface attributes */
187 case EGL_WIDTH:
188 if (type != EGL_PBUFFER_BIT) {
189 err = EGL_BAD_ATTRIBUTE;
190 break;
191 }
192 if (val < 0) {
193 err = EGL_BAD_PARAMETER;
194 break;
195 }
196 surf->Width = val;
197 break;
198 case EGL_HEIGHT:
199 if (type != EGL_PBUFFER_BIT) {
200 err = EGL_BAD_ATTRIBUTE;
201 break;
202 }
203 if (val < 0) {
204 err = EGL_BAD_PARAMETER;
205 break;
206 }
207 surf->Height = val;
208 break;
209 case EGL_LARGEST_PBUFFER:
210 if (type != EGL_PBUFFER_BIT) {
211 err = EGL_BAD_ATTRIBUTE;
212 break;
213 }
214 surf->LargestPbuffer = !!val;
215 break;
216 /* for eglBindTexImage */
217 case EGL_TEXTURE_FORMAT:
218 if (!(type & texture_type)) {
219 err = EGL_BAD_ATTRIBUTE;
220 break;
221 }
222 switch (val) {
223 case EGL_TEXTURE_RGB:
224 case EGL_TEXTURE_RGBA:
225 case EGL_NO_TEXTURE:
226 break;
227 default:
228 err = EGL_BAD_ATTRIBUTE;
229 break;
230 }
231 if (err != EGL_SUCCESS)
232 break;
233 surf->TextureFormat = val;
234 break;
235 case EGL_TEXTURE_TARGET:
236 if (!(type & texture_type)) {
237 err = EGL_BAD_ATTRIBUTE;
238 break;
239 }
240 switch (val) {
241 case EGL_TEXTURE_2D:
242 case EGL_NO_TEXTURE:
243 break;
244 default:
245 err = EGL_BAD_ATTRIBUTE;
246 break;
247 }
248 if (err != EGL_SUCCESS)
249 break;
250 surf->TextureTarget = val;
251 break;
252 case EGL_MIPMAP_TEXTURE:
253 if (!(type & texture_type)) {
254 err = EGL_BAD_ATTRIBUTE;
255 break;
256 }
257 surf->MipmapTexture = !!val;
258 break;
259 /* no pixmap surface specific attributes */
260 default:
261 err = EGL_BAD_ATTRIBUTE;
262 break;
263 }
264
265 if (err != EGL_SUCCESS) {
266 _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
267 break;
268 }
269 }
270
271 return err;
272 }
273
274
275 /**
276 * Do error check on parameters and initialize the given _EGLSurface object.
277 * \return EGL_TRUE if no errors, EGL_FALSE otherwise.
278 */
279 EGLBoolean
280 _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
281 _EGLConfig *conf, const EGLint *attrib_list)
282 {
283 const char *func;
284 EGLint renderBuffer = EGL_BACK_BUFFER;
285 EGLint swapBehavior = EGL_BUFFER_PRESERVED;
286 EGLint err;
287
288 switch (type) {
289 case EGL_WINDOW_BIT:
290 func = "eglCreateWindowSurface";
291 swapBehavior = EGL_BUFFER_DESTROYED;
292 break;
293 case EGL_PIXMAP_BIT:
294 func = "eglCreatePixmapSurface";
295 renderBuffer = EGL_SINGLE_BUFFER;
296 break;
297 case EGL_PBUFFER_BIT:
298 func = "eglCreatePBufferSurface";
299 break;
300 #ifdef EGL_MESA_screen_surface
301 case EGL_SCREEN_BIT_MESA:
302 func = "eglCreateScreenSurface";
303 renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */
304 break;
305 #endif
306 default:
307 _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
308 return EGL_FALSE;
309 }
310
311 if ((conf->SurfaceType & type) == 0) {
312 /* The config can't be used to create a surface of this type */
313 _eglError(EGL_BAD_CONFIG, func);
314 return EGL_FALSE;
315 }
316
317 _eglInitResource(&surf->Resource, sizeof(*surf), dpy);
318 surf->Type = type;
319 surf->Config = conf;
320
321 surf->Width = 0;
322 surf->Height = 0;
323 surf->TextureFormat = EGL_NO_TEXTURE;
324 surf->TextureTarget = EGL_NO_TEXTURE;
325 surf->MipmapTexture = EGL_FALSE;
326 surf->LargestPbuffer = EGL_FALSE;
327 surf->RenderBuffer = renderBuffer;
328 surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
329 surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
330
331 surf->MipmapLevel = 0;
332 surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
333 surf->SwapBehavior = swapBehavior;
334
335 surf->HorizontalResolution = EGL_UNKNOWN;
336 surf->VerticalResolution = EGL_UNKNOWN;
337 surf->AspectRatio = EGL_UNKNOWN;
338
339 surf->PostSubBufferSupportedNV = EGL_FALSE;
340
341 /* the default swap interval is 1 */
342 _eglClampSwapInterval(surf, 1);
343
344 err = _eglParseSurfaceAttribList(surf, attrib_list);
345 if (err != EGL_SUCCESS)
346 return _eglError(err, func);
347
348 return EGL_TRUE;
349 }
350
351
352 EGLBoolean
353 _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
354 EGLint attribute, EGLint *value)
355 {
356 switch (attribute) {
357 case EGL_WIDTH:
358 *value = surface->Width;
359 break;
360 case EGL_HEIGHT:
361 *value = surface->Height;
362 break;
363 case EGL_CONFIG_ID:
364 *value = surface->Config->ConfigID;
365 break;
366 case EGL_LARGEST_PBUFFER:
367 *value = surface->LargestPbuffer;
368 break;
369 case EGL_TEXTURE_FORMAT:
370 /* texture attributes: only for pbuffers, no error otherwise */
371 if (surface->Type == EGL_PBUFFER_BIT)
372 *value = surface->TextureFormat;
373 break;
374 case EGL_TEXTURE_TARGET:
375 if (surface->Type == EGL_PBUFFER_BIT)
376 *value = surface->TextureTarget;
377 break;
378 case EGL_MIPMAP_TEXTURE:
379 if (surface->Type == EGL_PBUFFER_BIT)
380 *value = surface->MipmapTexture;
381 break;
382 case EGL_MIPMAP_LEVEL:
383 if (surface->Type == EGL_PBUFFER_BIT)
384 *value = surface->MipmapLevel;
385 break;
386 case EGL_SWAP_BEHAVIOR:
387 *value = surface->SwapBehavior;
388 break;
389 case EGL_RENDER_BUFFER:
390 *value = surface->RenderBuffer;
391 break;
392 case EGL_PIXEL_ASPECT_RATIO:
393 *value = surface->AspectRatio;
394 break;
395 case EGL_HORIZONTAL_RESOLUTION:
396 *value = surface->HorizontalResolution;
397 break;
398 case EGL_VERTICAL_RESOLUTION:
399 *value = surface->VerticalResolution;
400 break;
401 case EGL_MULTISAMPLE_RESOLVE:
402 *value = surface->MultisampleResolve;
403 break;
404 case EGL_VG_ALPHA_FORMAT:
405 *value = surface->VGAlphaFormat;
406 break;
407 case EGL_VG_COLORSPACE:
408 *value = surface->VGColorspace;
409 break;
410 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
411 *value = surface->PostSubBufferSupportedNV;
412 break;
413 case EGL_BUFFER_AGE_EXT:
414 if (!dpy->Extensions.EXT_buffer_age) {
415 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
416 return EGL_FALSE;
417 }
418 *value = drv->API.QueryBufferAge(drv, dpy, surface);
419 break;
420 default:
421 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
422 return EGL_FALSE;
423 }
424
425 return EGL_TRUE;
426 }
427
428
429 /**
430 * Default fallback routine - drivers might override this.
431 */
432 EGLBoolean
433 _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
434 EGLint attribute, EGLint value)
435 {
436 EGLint confval;
437 EGLint err = EGL_SUCCESS;
438
439 switch (attribute) {
440 case EGL_MIPMAP_LEVEL:
441 confval = surface->Config->RenderableType;
442 if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
443 err = EGL_BAD_PARAMETER;
444 break;
445 }
446 surface->MipmapLevel = value;
447 break;
448 case EGL_MULTISAMPLE_RESOLVE:
449 switch (value) {
450 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
451 break;
452 case EGL_MULTISAMPLE_RESOLVE_BOX:
453 confval = surface->Config->SurfaceType;
454 if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
455 err = EGL_BAD_MATCH;
456 break;
457 default:
458 err = EGL_BAD_ATTRIBUTE;
459 break;
460 }
461 if (err != EGL_SUCCESS)
462 break;
463 surface->MultisampleResolve = value;
464 break;
465 case EGL_SWAP_BEHAVIOR:
466 switch (value) {
467 case EGL_BUFFER_DESTROYED:
468 break;
469 case EGL_BUFFER_PRESERVED:
470 confval = surface->Config->SurfaceType;
471 if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
472 err = EGL_BAD_MATCH;
473 break;
474 default:
475 err = EGL_BAD_ATTRIBUTE;
476 break;
477 }
478 if (err != EGL_SUCCESS)
479 break;
480 surface->SwapBehavior = value;
481 break;
482 default:
483 err = EGL_BAD_ATTRIBUTE;
484 break;
485 }
486
487 if (err != EGL_SUCCESS)
488 return _eglError(err, "eglSurfaceAttrib");
489 return EGL_TRUE;
490 }
491
492
493 EGLBoolean
494 _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
495 EGLint buffer)
496 {
497 EGLint texture_type = EGL_PBUFFER_BIT;
498
499 /* Just do basic error checking and return success/fail.
500 * Drivers must implement the real stuff.
501 */
502
503 if (dpy->Extensions.NOK_texture_from_pixmap)
504 texture_type |= EGL_PIXMAP_BIT;
505
506 if (!(surface->Type & texture_type)) {
507 _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
508 return EGL_FALSE;
509 }
510
511 if (surface->TextureFormat == EGL_NO_TEXTURE) {
512 _eglError(EGL_BAD_MATCH, "eglBindTexImage");
513 return EGL_FALSE;
514 }
515
516 if (surface->TextureTarget == EGL_NO_TEXTURE) {
517 _eglError(EGL_BAD_MATCH, "eglBindTexImage");
518 return EGL_FALSE;
519 }
520
521 if (buffer != EGL_BACK_BUFFER) {
522 _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
523 return EGL_FALSE;
524 }
525
526 surface->BoundToTexture = EGL_TRUE;
527
528 return EGL_TRUE;
529 }
530
531
532 EGLBoolean
533 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
534 EGLint interval)
535 {
536 _eglClampSwapInterval(surf, interval);
537 return EGL_TRUE;
538 }