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