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