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