egl/android: support for EGL_KHR_partial_update
[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 attr = EGL_NONE;
75 EGLint val = EGL_NONE;
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 attr = attrib_list[i++];
85 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 switch (val) {
193 case EGL_TEXTURE_RGB:
194 case EGL_TEXTURE_RGBA:
195 case EGL_NO_TEXTURE:
196 break;
197 default:
198 err = EGL_BAD_ATTRIBUTE;
199 break;
200 }
201 if (err != EGL_SUCCESS)
202 break;
203 surf->TextureFormat = val;
204 break;
205 case EGL_TEXTURE_TARGET:
206 if (!(type & texture_type)) {
207 err = EGL_BAD_ATTRIBUTE;
208 break;
209 }
210
211 switch (val) {
212 case EGL_TEXTURE_2D:
213 case EGL_NO_TEXTURE:
214 break;
215 default:
216 err = EGL_BAD_ATTRIBUTE;
217 break;
218 }
219 if (err != EGL_SUCCESS)
220 break;
221 surf->TextureTarget = val;
222 break;
223 case EGL_MIPMAP_TEXTURE:
224 if (!(type & texture_type)) {
225 err = EGL_BAD_ATTRIBUTE;
226 break;
227 }
228 surf->MipmapTexture = !!val;
229 break;
230 /* no pixmap surface specific attributes */
231 default:
232 err = EGL_BAD_ATTRIBUTE;
233 break;
234 }
235
236 if (err != EGL_SUCCESS)
237 break;
238 }
239
240 if (err == EGL_SUCCESS && type == EGL_PBUFFER_BIT) {
241 if ((surf->TextureTarget == EGL_NO_TEXTURE && surf->TextureFormat != EGL_NO_TEXTURE) ||
242 (surf->TextureFormat == EGL_NO_TEXTURE && surf->TextureTarget != EGL_NO_TEXTURE)) {
243 attr = surf->TextureTarget == EGL_NO_TEXTURE ? EGL_TEXTURE_TARGET : EGL_TEXTURE_FORMAT;
244 err = EGL_BAD_MATCH;
245 }
246 }
247
248 if (err != EGL_SUCCESS)
249 _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
250
251 return err;
252 }
253
254
255 /**
256 * Do error check on parameters and initialize the given _EGLSurface object.
257 * \return EGL_TRUE if no errors, EGL_FALSE otherwise.
258 */
259 EGLBoolean
260 _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
261 _EGLConfig *conf, const EGLint *attrib_list)
262 {
263 const char *func;
264 EGLint renderBuffer = EGL_BACK_BUFFER;
265 EGLint swapBehavior = EGL_BUFFER_DESTROYED;
266 EGLint err;
267
268 /* Swap behavior can be preserved only if config supports this. */
269 if (conf->SurfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
270 swapBehavior = EGL_BUFFER_PRESERVED;
271
272 switch (type) {
273 case EGL_WINDOW_BIT:
274 func = "eglCreateWindowSurface";
275 swapBehavior = EGL_BUFFER_DESTROYED;
276 break;
277 case EGL_PIXMAP_BIT:
278 func = "eglCreatePixmapSurface";
279 renderBuffer = EGL_SINGLE_BUFFER;
280 break;
281 case EGL_PBUFFER_BIT:
282 func = "eglCreatePBufferSurface";
283 break;
284 default:
285 _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
286 return EGL_FALSE;
287 }
288
289 if ((conf->SurfaceType & type) == 0) {
290 /* The config can't be used to create a surface of this type */
291 _eglError(EGL_BAD_MATCH, func);
292 return EGL_FALSE;
293 }
294
295 _eglInitResource(&surf->Resource, sizeof(*surf), dpy);
296 surf->Type = type;
297 surf->Config = conf;
298 surf->Lost = EGL_FALSE;
299
300 surf->Width = 0;
301 surf->Height = 0;
302 surf->TextureFormat = EGL_NO_TEXTURE;
303 surf->TextureTarget = EGL_NO_TEXTURE;
304 surf->MipmapTexture = EGL_FALSE;
305 surf->LargestPbuffer = EGL_FALSE;
306 surf->RenderBuffer = renderBuffer;
307 surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
308 surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
309 surf->GLColorspace = EGL_GL_COLORSPACE_LINEAR_KHR;
310
311 surf->MipmapLevel = 0;
312 surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
313 surf->SwapBehavior = swapBehavior;
314
315 surf->HorizontalResolution = EGL_UNKNOWN;
316 surf->VerticalResolution = EGL_UNKNOWN;
317 surf->AspectRatio = EGL_UNKNOWN;
318
319 surf->PostSubBufferSupportedNV = EGL_FALSE;
320 surf->SetDamageRegionCalled = EGL_FALSE;
321 surf->BufferAgeRead = EGL_FALSE;
322
323 /* the default swap interval is 1 */
324 _eglClampSwapInterval(surf, 1);
325
326 err = _eglParseSurfaceAttribList(surf, attrib_list);
327 if (err != EGL_SUCCESS)
328 return _eglError(err, func);
329
330 /* if EGL_LARGEST_PBUFFER in use, clamp width and height */
331 if (surf->LargestPbuffer) {
332 surf->Width = MIN2(surf->Width, _EGL_MAX_PBUFFER_WIDTH);
333 surf->Height = MIN2(surf->Height, _EGL_MAX_PBUFFER_HEIGHT);
334 }
335
336 return EGL_TRUE;
337 }
338
339
340 EGLBoolean
341 _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
342 EGLint attribute, EGLint *value)
343 {
344 switch (attribute) {
345 case EGL_WIDTH:
346 *value = surface->Width;
347 break;
348 case EGL_HEIGHT:
349 *value = surface->Height;
350 break;
351 case EGL_CONFIG_ID:
352 *value = surface->Config->ConfigID;
353 break;
354 case EGL_LARGEST_PBUFFER:
355 if (surface->Type == EGL_PBUFFER_BIT)
356 *value = surface->LargestPbuffer;
357 break;
358 case EGL_TEXTURE_FORMAT:
359 /* texture attributes: only for pbuffers, no error otherwise */
360 if (surface->Type == EGL_PBUFFER_BIT)
361 *value = surface->TextureFormat;
362 break;
363 case EGL_TEXTURE_TARGET:
364 if (surface->Type == EGL_PBUFFER_BIT)
365 *value = surface->TextureTarget;
366 break;
367 case EGL_MIPMAP_TEXTURE:
368 if (surface->Type == EGL_PBUFFER_BIT)
369 *value = surface->MipmapTexture;
370 break;
371 case EGL_MIPMAP_LEVEL:
372 if (surface->Type == EGL_PBUFFER_BIT)
373 *value = surface->MipmapLevel;
374 break;
375 case EGL_SWAP_BEHAVIOR:
376 *value = surface->SwapBehavior;
377 break;
378 case EGL_RENDER_BUFFER:
379 *value = surface->RenderBuffer;
380 break;
381 case EGL_PIXEL_ASPECT_RATIO:
382 *value = surface->AspectRatio;
383 break;
384 case EGL_HORIZONTAL_RESOLUTION:
385 *value = surface->HorizontalResolution;
386 break;
387 case EGL_VERTICAL_RESOLUTION:
388 *value = surface->VerticalResolution;
389 break;
390 case EGL_MULTISAMPLE_RESOLVE:
391 *value = surface->MultisampleResolve;
392 break;
393 case EGL_VG_ALPHA_FORMAT:
394 *value = surface->VGAlphaFormat;
395 break;
396 case EGL_VG_COLORSPACE:
397 *value = surface->VGColorspace;
398 break;
399 case EGL_GL_COLORSPACE_KHR:
400 if (!dpy->Extensions.KHR_gl_colorspace) {
401 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
402 return EGL_FALSE;
403 }
404 *value = surface->GLColorspace;
405 break;
406 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
407 *value = surface->PostSubBufferSupportedNV;
408 break;
409 case EGL_BUFFER_AGE_EXT:
410 if (!dpy->Extensions.EXT_buffer_age) {
411 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
412 return EGL_FALSE;
413 }
414 _EGLContext *ctx = _eglGetCurrentContext();
415 EGLint result = drv->API.QueryBufferAge(drv, dpy, surface);
416 /* error happened */
417 if (result < 0)
418 return EGL_FALSE;
419 if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
420 ctx->DrawSurface != surface) {
421 _eglError(EGL_BAD_SURFACE, "eglQuerySurface");
422 return EGL_FALSE;
423 }
424 *value = result;
425 surface->BufferAgeRead = EGL_TRUE;
426 break;
427 default:
428 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
429 return EGL_FALSE;
430 }
431
432 return EGL_TRUE;
433 }
434
435
436 /**
437 * Default fallback routine - drivers might override this.
438 */
439 EGLBoolean
440 _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
441 EGLint attribute, EGLint value)
442 {
443 EGLint confval;
444 EGLint err = EGL_SUCCESS;
445 EGLint all_es_bits = EGL_OPENGL_ES_BIT |
446 EGL_OPENGL_ES2_BIT |
447 EGL_OPENGL_ES3_BIT_KHR;
448
449 switch (attribute) {
450 case EGL_MIPMAP_LEVEL:
451 confval = surface->Config->RenderableType;
452 if (!(confval & all_es_bits)) {
453 err = EGL_BAD_PARAMETER;
454 break;
455 }
456 surface->MipmapLevel = value;
457 break;
458 case EGL_MULTISAMPLE_RESOLVE:
459 switch (value) {
460 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
461 break;
462 case EGL_MULTISAMPLE_RESOLVE_BOX:
463 confval = surface->Config->SurfaceType;
464 if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
465 err = EGL_BAD_MATCH;
466 break;
467 default:
468 err = EGL_BAD_ATTRIBUTE;
469 break;
470 }
471 if (err != EGL_SUCCESS)
472 break;
473 surface->MultisampleResolve = value;
474 break;
475 case EGL_SWAP_BEHAVIOR:
476 switch (value) {
477 case EGL_BUFFER_DESTROYED:
478 break;
479 case EGL_BUFFER_PRESERVED:
480 confval = surface->Config->SurfaceType;
481 if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
482 err = EGL_BAD_MATCH;
483 break;
484 default:
485 err = EGL_BAD_ATTRIBUTE;
486 break;
487 }
488 if (err != EGL_SUCCESS)
489 break;
490 surface->SwapBehavior = value;
491 break;
492 default:
493 err = EGL_BAD_ATTRIBUTE;
494 break;
495 }
496
497 if (err != EGL_SUCCESS)
498 return _eglError(err, "eglSurfaceAttrib");
499 return EGL_TRUE;
500 }
501
502
503 EGLBoolean
504 _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
505 EGLint buffer)
506 {
507 EGLint texture_type = EGL_PBUFFER_BIT;
508
509 /* Just do basic error checking and return success/fail.
510 * Drivers must implement the real stuff.
511 */
512
513 if (dpy->Extensions.NOK_texture_from_pixmap)
514 texture_type |= EGL_PIXMAP_BIT;
515
516 if (!(surface->Type & texture_type)) {
517 _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
518 return EGL_FALSE;
519 }
520
521 if (surface->TextureFormat == EGL_NO_TEXTURE) {
522 _eglError(EGL_BAD_MATCH, "eglBindTexImage");
523 return EGL_FALSE;
524 }
525
526 if (surface->TextureTarget == EGL_NO_TEXTURE) {
527 _eglError(EGL_BAD_MATCH, "eglBindTexImage");
528 return EGL_FALSE;
529 }
530
531 if (buffer != EGL_BACK_BUFFER) {
532 _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
533 return EGL_FALSE;
534 }
535
536 surface->BoundToTexture = EGL_TRUE;
537
538 return EGL_TRUE;
539 }
540
541 EGLBoolean
542 _eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
543 EGLint buffer)
544 {
545 /* Just do basic error checking and return success/fail.
546 * Drivers must implement the real stuff.
547 */
548
549 EGLint texture_type = EGL_PBUFFER_BIT;
550
551 if (surf == EGL_NO_SURFACE)
552 {
553 _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
554 return EGL_FALSE;
555 }
556
557 if (!surf->BoundToTexture)
558 {
559 /* Not an error, simply nothing to do */
560 return EGL_TRUE;
561 }
562
563 if (surf->TextureFormat == EGL_NO_TEXTURE)
564 {
565 _eglError(EGL_BAD_MATCH, "eglReleaseTexImage");
566 return EGL_FALSE;
567 }
568
569 if (buffer != EGL_BACK_BUFFER)
570 {
571 _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
572 return EGL_FALSE;
573 }
574
575 if (dpy->Extensions.NOK_texture_from_pixmap)
576 texture_type |= EGL_PIXMAP_BIT;
577
578 if (!(surf->Type & texture_type))
579 {
580 _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
581 return EGL_FALSE;
582 }
583
584 surf->BoundToTexture = EGL_FALSE;
585
586 return EGL_TRUE;
587 }
588
589
590 EGLBoolean
591 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
592 EGLint interval)
593 {
594 _eglClampSwapInterval(surf, interval);
595 return EGL_TRUE;
596 }