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