1 /************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe (at) 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 299 surf->Width = 0; 300 surf->Height = 0; 301 surf->TextureFormat = EGL_NO_TEXTURE; 302 surf->TextureTarget = EGL_NO_TEXTURE; 303 surf->MipmapTexture = EGL_FALSE; 304 surf->LargestPbuffer = EGL_FALSE; 305 surf->RenderBuffer = renderBuffer; 306 surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE; 307 surf->VGColorspace = EGL_VG_COLORSPACE_sRGB; 308 surf->GLColorspace = EGL_GL_COLORSPACE_LINEAR_KHR; 309 310 surf->MipmapLevel = 0; 311 surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT; 312 surf->SwapBehavior = swapBehavior; 313 314 surf->HorizontalResolution = EGL_UNKNOWN; 315 surf->VerticalResolution = EGL_UNKNOWN; 316 surf->AspectRatio = EGL_UNKNOWN; 317 318 surf->PostSubBufferSupportedNV = EGL_FALSE; 319 320 /* the default swap interval is 1 */ 321 _eglClampSwapInterval(surf, 1); 322 323 err = _eglParseSurfaceAttribList(surf, attrib_list); 324 if (err != EGL_SUCCESS) 325 return _eglError(err, func); 326 327 /* if EGL_LARGEST_PBUFFER in use, clamp width and height */ 328 if (surf->LargestPbuffer) { 329 surf->Width = MIN2(surf->Width, _EGL_MAX_PBUFFER_WIDTH); 330 surf->Height = MIN2(surf->Height, _EGL_MAX_PBUFFER_HEIGHT); 331 } 332 333 return EGL_TRUE; 334 } 335 336 337 EGLBoolean 338 _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, 339 EGLint attribute, EGLint *value) 340 { 341 switch (attribute) { 342 case EGL_WIDTH: 343 *value = surface->Width; 344 break; 345 case EGL_HEIGHT: 346 *value = surface->Height; 347 break; 348 case EGL_CONFIG_ID: 349 *value = surface->Config->ConfigID; 350 break; 351 case EGL_LARGEST_PBUFFER: 352 if (surface->Type == EGL_PBUFFER_BIT) 353 *value = surface->LargestPbuffer; 354 break; 355 case EGL_TEXTURE_FORMAT: 356 /* texture attributes: only for pbuffers, no error otherwise */ 357 if (surface->Type == EGL_PBUFFER_BIT) 358 *value = surface->TextureFormat; 359 break; 360 case EGL_TEXTURE_TARGET: 361 if (surface->Type == EGL_PBUFFER_BIT) 362 *value = surface->TextureTarget; 363 break; 364 case EGL_MIPMAP_TEXTURE: 365 if (surface->Type == EGL_PBUFFER_BIT) 366 *value = surface->MipmapTexture; 367 break; 368 case EGL_MIPMAP_LEVEL: 369 if (surface->Type == EGL_PBUFFER_BIT) 370 *value = surface->MipmapLevel; 371 break; 372 case EGL_SWAP_BEHAVIOR: 373 *value = surface->SwapBehavior; 374 break; 375 case EGL_RENDER_BUFFER: 376 *value = surface->RenderBuffer; 377 break; 378 case EGL_PIXEL_ASPECT_RATIO: 379 *value = surface->AspectRatio; 380 break; 381 case EGL_HORIZONTAL_RESOLUTION: 382 *value = surface->HorizontalResolution; 383 break; 384 case EGL_VERTICAL_RESOLUTION: 385 *value = surface->VerticalResolution; 386 break; 387 case EGL_MULTISAMPLE_RESOLVE: 388 *value = surface->MultisampleResolve; 389 break; 390 case EGL_VG_ALPHA_FORMAT: 391 *value = surface->VGAlphaFormat; 392 break; 393 case EGL_VG_COLORSPACE: 394 *value = surface->VGColorspace; 395 break; 396 case EGL_GL_COLORSPACE_KHR: 397 if (!dpy->Extensions.KHR_gl_colorspace) { 398 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); 399 return EGL_FALSE; 400 } 401 *value = surface->GLColorspace; 402 break; 403 case EGL_POST_SUB_BUFFER_SUPPORTED_NV: 404 *value = surface->PostSubBufferSupportedNV; 405 break; 406 case EGL_BUFFER_AGE_EXT: 407 if (!dpy->Extensions.EXT_buffer_age) { 408 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); 409 return EGL_FALSE; 410 } 411 *value = drv->API.QueryBufferAge(drv, dpy, surface); 412 break; 413 default: 414 _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); 415 return EGL_FALSE; 416 } 417 418 return EGL_TRUE; 419 } 420 421 422 /** 423 * Default fallback routine - drivers might override this. 424 */ 425 EGLBoolean 426 _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, 427 EGLint attribute, EGLint value) 428 { 429 EGLint confval; 430 EGLint err = EGL_SUCCESS; 431 EGLint all_es_bits = EGL_OPENGL_ES_BIT | 432 EGL_OPENGL_ES2_BIT | 433 EGL_OPENGL_ES3_BIT_KHR; 434 435 switch (attribute) { 436 case EGL_MIPMAP_LEVEL: 437 confval = surface->Config->RenderableType; 438 if (!(confval & all_es_bits)) { 439 err = EGL_BAD_PARAMETER; 440 break; 441 } 442 surface->MipmapLevel = value; 443 break; 444 case EGL_MULTISAMPLE_RESOLVE: 445 switch (value) { 446 case EGL_MULTISAMPLE_RESOLVE_DEFAULT: 447 break; 448 case EGL_MULTISAMPLE_RESOLVE_BOX: 449 confval = surface->Config->SurfaceType; 450 if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_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->MultisampleResolve = value; 460 break; 461 case EGL_SWAP_BEHAVIOR: 462 switch (value) { 463 case EGL_BUFFER_DESTROYED: 464 break; 465 case EGL_BUFFER_PRESERVED: 466 confval = surface->Config->SurfaceType; 467 if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) 468 err = EGL_BAD_MATCH; 469 break; 470 default: 471 err = EGL_BAD_ATTRIBUTE; 472 break; 473 } 474 if (err != EGL_SUCCESS) 475 break; 476 surface->SwapBehavior = value; 477 break; 478 default: 479 err = EGL_BAD_ATTRIBUTE; 480 break; 481 } 482 483 if (err != EGL_SUCCESS) 484 return _eglError(err, "eglSurfaceAttrib"); 485 return EGL_TRUE; 486 } 487 488 489 EGLBoolean 490 _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, 491 EGLint buffer) 492 { 493 EGLint texture_type = EGL_PBUFFER_BIT; 494 495 /* Just do basic error checking and return success/fail. 496 * Drivers must implement the real stuff. 497 */ 498 499 if (dpy->Extensions.NOK_texture_from_pixmap) 500 texture_type |= EGL_PIXMAP_BIT; 501 502 if (!(surface->Type & texture_type)) { 503 _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); 504 return EGL_FALSE; 505 } 506 507 if (surface->TextureFormat == EGL_NO_TEXTURE) { 508 _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 509 return EGL_FALSE; 510 } 511 512 if (surface->TextureTarget == EGL_NO_TEXTURE) { 513 _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 514 return EGL_FALSE; 515 } 516 517 if (buffer != EGL_BACK_BUFFER) { 518 _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); 519 return EGL_FALSE; 520 } 521 522 surface->BoundToTexture = EGL_TRUE; 523 524 return EGL_TRUE; 525 } 526 527 EGLBoolean 528 _eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, 529 EGLint buffer) 530 { 531 /* Just do basic error checking and return success/fail. 532 * Drivers must implement the real stuff. 533 */ 534 535 EGLint texture_type = EGL_PBUFFER_BIT; 536 537 if (surf == EGL_NO_SURFACE) 538 { 539 _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); 540 return EGL_FALSE; 541 } 542 543 if (!surf->BoundToTexture) 544 { 545 /* Not an error, simply nothing to do */ 546 return EGL_TRUE; 547 } 548 549 if (surf->TextureFormat == EGL_NO_TEXTURE) 550 { 551 _eglError(EGL_BAD_MATCH, "eglReleaseTexImage"); 552 return EGL_FALSE; 553 } 554 555 if (buffer != EGL_BACK_BUFFER) 556 { 557 _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); 558 return EGL_FALSE; 559 } 560 561 if (dpy->Extensions.NOK_texture_from_pixmap) 562 texture_type |= EGL_PIXMAP_BIT; 563 564 if (!(surf->Type & texture_type)) 565 { 566 _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); 567 return EGL_FALSE; 568 } 569 570 surf->BoundToTexture = EGL_FALSE; 571 572 return EGL_TRUE; 573 } 574 575 576 EGLBoolean 577 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, 578 EGLint interval) 579 { 580 _eglClampSwapInterval(surf, interval); 581 return EGL_TRUE; 582 } 583