1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 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 "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 } 531