| 1 | /* |
| 2 | Copyright (c) 2012, Broadcom Europe Ltd |
| 3 | All rights reserved. |
| 4 | |
| 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
| 7 | * Redistributions of source code must retain the above copyright |
| 8 | notice, this list of conditions and the following disclaimer. |
| 9 | * Redistributions in binary form must reproduce the above copyright |
| 10 | notice, this list of conditions and the following disclaimer in the |
| 11 | documentation and/or other materials provided with the distribution. |
| 12 | * Neither the name of the copyright holder nor the |
| 13 | names of its contributors may be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
| 15 | |
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #define VCOS_LOG_CATEGORY (&egl_client_log_cat) |
| 29 | |
| 30 | #include "interface/khronos/common/khrn_int_common.h" |
| 31 | |
| 32 | #include "interface/khronos/common/khrn_client_rpc.h" |
| 33 | #include "interface/khronos/common/khrn_client_platform.h" |
| 34 | |
| 35 | #include "interface/khronos/egl/egl_client_surface.h" |
| 36 | #include "interface/khronos/egl/egl_client_config.h" |
| 37 | |
| 38 | #include "interface/khronos/common/khrn_client.h" |
| 39 | |
| 40 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
| 41 | #include "interface/khronos/wf/wfc_int.h" |
| 42 | #include "interface/khronos/wf/wfc_client_stream.h" |
| 43 | #endif |
| 44 | |
| 45 | #ifdef RPC_DIRECT |
| 46 | #include "interface/khronos/egl/egl_int_impl.h" |
| 47 | #endif |
| 48 | |
| 49 | #include <stdlib.h> |
| 50 | |
| 51 | |
| 52 | /* |
| 53 | surface_pool |
| 54 | |
| 55 | cache for a small number of pre-allocated surface objects |
| 56 | |
| 57 | Validity: |
| 58 | surfaces[i] is valid if allocated & (1<<i) |
| 59 | */ |
| 60 | |
| 61 | #define EGL_SURFACE_POOL_SIZE 2 |
| 62 | static struct |
| 63 | { |
| 64 | EGL_SURFACE_T surfaces[EGL_SURFACE_POOL_SIZE]; |
| 65 | uint32_t allocated; |
| 66 | } surface_pool; |
| 67 | |
| 68 | extern VCOS_LOG_CAT_T egl_client_log_cat; |
| 69 | |
| 70 | /* |
| 71 | EGL_SURFACE_T* egl_surface_pool_alloc(void) |
| 72 | |
| 73 | Implementation notes: |
| 74 | |
| 75 | We have a small static pool of structures (surface_pool) which we try and allocate out of |
| 76 | in order to reduce memory fragmentation. When we have run out of space in the pool we |
| 77 | resort to khrn_platform_malloc. |
| 78 | |
| 79 | Preconditions: |
| 80 | |
| 81 | Whoever calls this must initialise (or free) the returned structure in order to satisfy the invariant |
| 82 | on surface_pool. |
| 83 | |
| 84 | Postconditions: |
| 85 | |
| 86 | Return value is NULL or an uninitialised EGL_SURFACE_T structure, valid until egl_surface_pool_free |
| 87 | is called. |
| 88 | */ |
| 89 | |
| 90 | static EGL_SURFACE_T* egl_surface_pool_alloc(void) |
| 91 | { |
| 92 | int i = 0; |
| 93 | |
| 94 | while(surface_pool.allocated & (1 << i)) |
| 95 | i++; |
| 96 | |
| 97 | if (i < EGL_SURFACE_POOL_SIZE) |
| 98 | { |
| 99 | surface_pool.allocated |= 1 << i; |
| 100 | return &surface_pool.surfaces[i]; |
| 101 | } |
| 102 | else |
| 103 | { |
| 104 | return (EGL_SURFACE_T*)khrn_platform_malloc(sizeof(EGL_SURFACE_T), "EGL_SURFACE_T" ); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | static void egl_surface_pool_free(EGL_SURFACE_T* surface) |
| 109 | { |
| 110 | unsigned int i = 0; |
| 111 | |
| 112 | /* todo: this doesn't belong here */ |
| 113 | //semaphore now gets destroyed on async callback from VC |
| 114 | if (surface->avail_buffers_valid) |
| 115 | khronos_platform_semaphore_destroy(&surface->avail_buffers); |
| 116 | surface->avail_buffers_valid = false; |
| 117 | |
| 118 | i = (unsigned int) (surface - surface_pool.surfaces); |
| 119 | |
| 120 | if (i < EGL_SURFACE_POOL_SIZE) |
| 121 | { |
| 122 | surface_pool.allocated &= ~(1 << i); |
| 123 | } |
| 124 | else |
| 125 | { |
| 126 | khrn_platform_free((void*)surface); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | EGLBoolean egl_surface_check_attribs_window(const EGLint *attrib_list, EGLBoolean *linear, EGLBoolean *premult, EGLBoolean *single) |
| 132 | |
| 133 | TODO: are we actually supposed to validate our parameters and generate an |
| 134 | error if they're wrong? I can't find an explicit mention in the spec about it. |
| 135 | (except for EGL_WIDTH and EGL_HEIGHT in pbuffer) |
| 136 | |
| 137 | Preconditions: |
| 138 | |
| 139 | type in {WINDOW, PBUFFER, PIXMAP} |
| 140 | attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs |
| 141 | linear, premult are NULL or valid pointers |
| 142 | If type == WINDOW then single is NULL or a valid pointer |
| 143 | If type == PBUFFER then width, height, largest_pbuffer, texture_format, texture_target, mipmap_texture are NULL or valid pointers |
| 144 | |
| 145 | Postconditions: |
| 146 | |
| 147 | - |
| 148 | */ |
| 149 | |
| 150 | bool egl_surface_check_attribs( |
| 151 | EGL_SURFACE_TYPE_T type, |
| 152 | const EGLint *attrib_list, |
| 153 | bool *linear, |
| 154 | bool *premult, |
| 155 | bool *single, |
| 156 | int *width, |
| 157 | int *height, |
| 158 | bool *largest_pbuffer, |
| 159 | EGLenum *texture_format, |
| 160 | EGLenum *texture_target, |
| 161 | bool *mipmap_texture |
| 162 | ) |
| 163 | { |
| 164 | if (!attrib_list) |
| 165 | return true; |
| 166 | |
| 167 | while (*attrib_list != EGL_NONE) { |
| 168 | int name = *attrib_list++; |
| 169 | int value = *attrib_list++; |
| 170 | |
| 171 | switch (name) { |
| 172 | case EGL_VG_COLORSPACE: |
| 173 | if (value != EGL_VG_COLORSPACE_sRGB && value != EGL_VG_COLORSPACE_LINEAR) |
| 174 | return false; |
| 175 | if (value == EGL_VG_COLORSPACE_LINEAR && linear != NULL) |
| 176 | *linear = true; |
| 177 | break; |
| 178 | case EGL_VG_ALPHA_FORMAT: |
| 179 | if (value != EGL_VG_ALPHA_FORMAT_NONPRE && value != EGL_VG_ALPHA_FORMAT_PRE) |
| 180 | return false; |
| 181 | if (value == EGL_VG_ALPHA_FORMAT_PRE && premult != NULL) |
| 182 | *premult = true; |
| 183 | break; |
| 184 | |
| 185 | /* For WINDOW types only */ |
| 186 | case EGL_RENDER_BUFFER: |
| 187 | if (type != WINDOW || (value != EGL_SINGLE_BUFFER && value != EGL_BACK_BUFFER)) |
| 188 | return false; |
| 189 | if (value == EGL_SINGLE_BUFFER && single != NULL) |
| 190 | *single = true; |
| 191 | break; |
| 192 | |
| 193 | /* For PBUFFER types only */ |
| 194 | case EGL_WIDTH: |
| 195 | if (type != PBUFFER || value < 0) |
| 196 | return false; |
| 197 | if (width != NULL) |
| 198 | *width = value; |
| 199 | break; |
| 200 | case EGL_HEIGHT: |
| 201 | if (type != PBUFFER || value < 0) |
| 202 | return false; |
| 203 | if (height != NULL) |
| 204 | *height = value; |
| 205 | break; |
| 206 | case EGL_LARGEST_PBUFFER: |
| 207 | if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) |
| 208 | return false; |
| 209 | if (largest_pbuffer != NULL) |
| 210 | *largest_pbuffer = value; |
| 211 | break; |
| 212 | case EGL_TEXTURE_FORMAT: |
| 213 | if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_RGB && value != EGL_TEXTURE_RGBA)) |
| 214 | return false; |
| 215 | if (texture_format != NULL) |
| 216 | *texture_format = value; |
| 217 | break; |
| 218 | case EGL_TEXTURE_TARGET: |
| 219 | if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_2D)) |
| 220 | return false; |
| 221 | if (texture_target != NULL) |
| 222 | *texture_target = value; |
| 223 | break; |
| 224 | case EGL_MIPMAP_TEXTURE: |
| 225 | if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) |
| 226 | return false; |
| 227 | if (mipmap_texture != NULL) |
| 228 | *mipmap_texture = value; |
| 229 | break; |
| 230 | default: |
| 231 | return false; |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | return true; |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | EGL_SURFACE_T *egl_surface_create( |
| 240 | EGLSurface name, |
| 241 | EGL_SURFACE_TYPE_T type, |
| 242 | EGL_SURFACE_COLORSPACE_T colorspace, |
| 243 | EGL_SURFACE_ALPHAFORMAT_T alphaformat, |
| 244 | uint32_t buffers, |
| 245 | uint32_t width, |
| 246 | uint32_t height, |
| 247 | EGLConfig config, |
| 248 | EGLNativeWindowType win, |
| 249 | uint32_t serverwin, |
| 250 | bool largest_pbuffer, |
| 251 | bool mipmap_texture, |
| 252 | EGLenum texture_format, |
| 253 | EGLenum texture_target, |
| 254 | EGLNativePixmapType pixmap, |
| 255 | const uint32_t *pixmap_server_handle) |
| 256 | |
| 257 | Implementation notes: |
| 258 | |
| 259 | TODO: respect largest_pbuffer? |
| 260 | |
| 261 | Preconditions: |
| 262 | type in {WINDOW,PBUFFER,PIXMAP} |
| 263 | colorspace in {SRGB,LINEAR} |
| 264 | alphaformat in {NONPRE,PRE} |
| 265 | 1 <= buffers <= EGL_MAX_BUFFERS |
| 266 | 0 < width, 0 < height |
| 267 | If !largest_pbuffer then width <= EGL_CONFIG_MAX_WIDTH, height <= EGL_CONFIG_MAX_HEIGHT |
| 268 | config is a valid EGL config |
| 269 | |
| 270 | If type == WINDOW then |
| 271 | win is a valid client-side handle to window W |
| 272 | serverwin is a valid server-side handle to window W |
| 273 | else |
| 274 | win == 0 |
| 275 | serverwin == PLATFORM_WIN_NONE |
| 276 | |
| 277 | If type == PBBUFFER then |
| 278 | texture_format in {EGL_NO_TEXTURE, EGL_TEXTURE_RGB, EGL_TEXTURE_RGBA} |
| 279 | texture_target in {EGL_NO_TEXTURE, EGL_TEXTURE_2D} |
| 280 | else |
| 281 | largest_pbuffer == mipmap_texture == false |
| 282 | texture_format == texture_target == EGL_NO_TEXTURE |
| 283 | |
| 284 | If type == PIXMAP then |
| 285 | pixmap is a valid client-side handle to pixmap P |
| 286 | If pixmap is a server-side pixmap then |
| 287 | pixmap_server_handle is a pointer to two elements, representing a valid server-side handle to pixmap P |
| 288 | else |
| 289 | pixmap_server_handle == 0 |
| 290 | else |
| 291 | pixmap == pixmap_server_handle == 0 |
| 292 | |
| 293 | Postconditions: |
| 294 | Return value is NULL or an EGL_SURFACE_T structure, valid until egl_surface_free is called |
| 295 | |
| 296 | Invariants preserved: |
| 297 | All invaraints on EGL_SURFACE_T |
| 298 | */ |
| 299 | |
| 300 | EGL_SURFACE_T *egl_surface_create( |
| 301 | EGLSurface name, |
| 302 | EGL_SURFACE_TYPE_T type, |
| 303 | EGL_SURFACE_COLORSPACE_T colorspace, |
| 304 | EGL_SURFACE_ALPHAFORMAT_T alphaformat, |
| 305 | uint32_t buffers, |
| 306 | uint32_t width, |
| 307 | uint32_t height, |
| 308 | EGLConfig config, |
| 309 | EGLNativeWindowType win, |
| 310 | uint32_t serverwin, |
| 311 | bool largest_pbuffer, |
| 312 | bool texture_compatibility, |
| 313 | bool mipmap_texture, |
| 314 | EGLenum texture_format, |
| 315 | EGLenum texture_target, |
| 316 | EGLNativePixmapType pixmap, |
| 317 | const uint32_t *pixmap_server_handle) |
| 318 | { |
| 319 | KHRN_IMAGE_FORMAT_T color; |
| 320 | KHRN_IMAGE_FORMAT_T depth; |
| 321 | KHRN_IMAGE_FORMAT_T mask; |
| 322 | KHRN_IMAGE_FORMAT_T multi; |
| 323 | uint32_t configid; |
| 324 | uint32_t sem_name; |
| 325 | EGLint config_depth_bits; |
| 326 | EGLint config_stencil_bits; |
| 327 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
| 328 | |
| 329 | EGL_SURFACE_T *surface = egl_surface_pool_alloc(); |
| 330 | |
| 331 | //vcos_assert(width > 0 && height > 0); |
| 332 | vcos_assert((width <= EGL_CONFIG_MAX_WIDTH && height <= EGL_CONFIG_MAX_HEIGHT) || largest_pbuffer); |
| 333 | |
| 334 | if (!surface) { |
| 335 | return 0; |
| 336 | } |
| 337 | |
| 338 | /* TODO: respect largest_pbuffer? */ |
| 339 | |
| 340 | surface->name = name; |
| 341 | surface->type = type; |
| 342 | |
| 343 | surface->colorspace = colorspace; |
| 344 | surface->alphaformat = alphaformat; |
| 345 | |
| 346 | surface->config = config; |
| 347 | surface->win = win; |
| 348 | surface->width = width; |
| 349 | surface->height = height; |
| 350 | surface->swap_interval = 1; |
| 351 | |
| 352 | surface->base_width = width; |
| 353 | surface->base_height = height; |
| 354 | |
| 355 | surface->internal_handle = serverwin; |
| 356 | |
| 357 | surface->largest_pbuffer = largest_pbuffer; |
| 358 | surface->mipmap_texture = mipmap_texture; |
| 359 | surface->mipmap_level = 0; |
| 360 | surface->texture_format = texture_format; |
| 361 | surface->texture_target = texture_target; |
| 362 | surface->pixmap = pixmap; |
| 363 | surface->pixmap_server_handle[0] = 0; |
| 364 | surface->pixmap_server_handle[1] = (uint32_t)-1; |
| 365 | surface->server_owned = false; |
| 366 | surface->swap_behavior = buffers > 1 ? EGL_BUFFER_DESTROYED : EGL_BUFFER_PRESERVED; |
| 367 | surface->multisample_resolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT; |
| 368 | |
| 369 | surface->context_binding_count = 0; |
| 370 | surface->is_destroyed = false; |
| 371 | |
| 372 | #if EGL_KHR_lock_surface |
| 373 | surface->is_locked = false; |
| 374 | surface->mapped_buffer = 0; |
| 375 | #endif |
| 376 | |
| 377 | configid = egl_config_to_id(config); |
| 378 | color = egl_config_get_color_format(configid); |
| 379 | if (texture_compatibility) { color = khrn_image_to_tf_format(color); } |
| 380 | if (alphaformat == PRE) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_PRE); } |
| 381 | if (colorspace == LINEAR) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_LIN); } |
| 382 | depth = egl_config_get_depth_format(configid); |
| 383 | mask = egl_config_get_mask_format(configid); |
| 384 | multi = egl_config_get_multisample_format(configid); |
| 385 | |
| 386 | /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ |
| 387 | egl_config_get_attrib(configid, EGL_DEPTH_SIZE, &config_depth_bits); |
| 388 | egl_config_get_attrib(configid, EGL_STENCIL_SIZE, &config_stencil_bits); |
| 389 | |
| 390 | vcos_assert(color != IMAGE_FORMAT_INVALID); |
| 391 | |
| 392 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
| 393 | // Create stream for this window |
| 394 | if(type != PBUFFER) |
| 395 | { |
| 396 | WFCNativeStreamType stream = (WFCNativeStreamType) surface->internal_handle; |
| 397 | vcos_assert(stream != WFC_INVALID_HANDLE); |
| 398 | uint32_t failure = wfc_stream_create(stream, WFC_STREAM_FLAGS_EGL); |
| 399 | vcos_log_trace("Creating stream with handle %X" , stream); |
| 400 | vcos_assert(failure == 0); |
| 401 | } // if |
| 402 | #endif |
| 403 | |
| 404 | surface->buffers = buffers; |
| 405 | |
| 406 | if (pixmap_server_handle) { |
| 407 | vcos_assert(type == PIXMAP); |
| 408 | surface->pixmap_server_handle[0] = pixmap_server_handle[0]; |
| 409 | surface->pixmap_server_handle[1] = pixmap_server_handle[1]; |
| 410 | surface->serverbuffer = RPC_UINT_RES(RPC_CALL7_RES(eglIntCreateWrappedSurface_impl, |
| 411 | thread, |
| 412 | EGLINTCREATEWRAPPEDSURFACE_ID, |
| 413 | RPC_UINT(pixmap_server_handle[0]), |
| 414 | RPC_UINT(pixmap_server_handle[1]), |
| 415 | RPC_UINT(depth), |
| 416 | RPC_UINT(mask), |
| 417 | RPC_UINT(multi), |
| 418 | RPC_UINT(config_depth_bits), |
| 419 | RPC_UINT(config_stencil_bits))); |
| 420 | surface->avail_buffers_valid = false; |
| 421 | } else { |
| 422 | #ifdef __SYMBIAN32__ |
| 423 | uint32_t nbuff = 0; |
| 424 | surface->avail_buffers_valid = 0; |
| 425 | |
| 426 | if (surface->buffers > 1) { |
| 427 | uint64_t pid = rpc_get_client_id(thread); |
| 428 | int sem[3] = { (int)pid, (int)(pid >> 32), (int)name }; |
| 429 | if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) |
| 430 | surface->avail_buffers_valid = 1; |
| 431 | nbuff = (int)surface->avail_buffers; |
| 432 | } |
| 433 | |
| 434 | if (surface->buffers == 1 || surface->avail_buffers_valid) { |
| 435 | uint32_t results[3]; |
| 436 | |
| 437 | RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, |
| 438 | thread, |
| 439 | EGLINTCREATESURFACE_ID, |
| 440 | RPC_UINT(serverwin), |
| 441 | RPC_UINT(buffers), |
| 442 | RPC_UINT(width), |
| 443 | RPC_UINT(height), |
| 444 | RPC_UINT(color), |
| 445 | RPC_UINT(depth), |
| 446 | RPC_UINT(mask), |
| 447 | RPC_UINT(multi), |
| 448 | RPC_UINT(largest_pbuffer), |
| 449 | RPC_UINT(mipmap_texture), |
| 450 | RPC_UINT(config_depth_bits), |
| 451 | RPC_UINT(config_stencil_bits), |
| 452 | RPC_UINT((int)nbuff), |
| 453 | RPC_UINT(type), |
| 454 | results); |
| 455 | #else |
| 456 | surface->avail_buffers_valid = false; |
| 457 | |
| 458 | sem_name = KHRN_NO_SEMAPHORE; |
| 459 | #ifndef KHRONOS_EGL_PLATFORM_OPENWFC |
| 460 | if (surface->buffers > 1) { |
| 461 | uint64_t pid = rpc_get_client_id(thread); |
| 462 | int sem[3]; |
| 463 | sem[0] = (int)pid; sem[1] = (int)(pid >> 32); sem[2] = (int)name; |
| 464 | |
| 465 | sem_name = (int)name; |
| 466 | if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) |
| 467 | surface->avail_buffers_valid = true; |
| 468 | } |
| 469 | if (sem_name == KHRN_NO_SEMAPHORE || surface->avail_buffers_valid) { |
| 470 | #else |
| 471 | sem_name = (uint32_t)surface->internal_handle; |
| 472 | vcos_log_trace("Surface create has semaphore %X" , sem_name); |
| 473 | #endif |
| 474 | uint32_t results[3]; |
| 475 | |
| 476 | RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, |
| 477 | thread, |
| 478 | EGLINTCREATESURFACE_ID, |
| 479 | RPC_UINT(serverwin), |
| 480 | RPC_UINT(buffers), |
| 481 | RPC_UINT(width), |
| 482 | RPC_UINT(height), |
| 483 | RPC_UINT(color), |
| 484 | RPC_UINT(depth), |
| 485 | RPC_UINT(mask), |
| 486 | RPC_UINT(multi), |
| 487 | RPC_UINT(largest_pbuffer), |
| 488 | RPC_UINT(mipmap_texture), |
| 489 | RPC_UINT(config_depth_bits), |
| 490 | RPC_UINT(config_stencil_bits), |
| 491 | RPC_UINT(sem_name), |
| 492 | RPC_UINT(type), |
| 493 | results); |
| 494 | #endif |
| 495 | surface->width = results[0]; |
| 496 | surface->height = results[1]; |
| 497 | surface->serverbuffer = results[2]; |
| 498 | #ifndef KHRONOS_EGL_PLATFORM_OPENWFC |
| 499 | } else { |
| 500 | surface->serverbuffer = 0; |
| 501 | } |
| 502 | #endif |
| 503 | } |
| 504 | |
| 505 | if (surface->serverbuffer) |
| 506 | return surface; |
| 507 | else { |
| 508 | /* Server failed to create a surface due to out-of-memory or |
| 509 | we failed to create the named semaphore object. */ |
| 510 | egl_surface_pool_free(surface); |
| 511 | return 0; |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | #ifndef NO_OPENVG |
| 516 | |
| 517 | /* Either returns a valid EGL_SURFACE_T, or returns null and sets error appropriately */ |
| 518 | |
| 519 | EGL_SURFACE_T *egl_surface_from_vg_image( |
| 520 | VGImage vg_handle, |
| 521 | EGLSurface name, |
| 522 | EGLConfig config, |
| 523 | EGLBoolean largest_pbuffer, |
| 524 | EGLBoolean mipmap_texture, |
| 525 | EGLenum texture_format, |
| 526 | EGLenum texture_target, |
| 527 | EGLint *error) |
| 528 | { |
| 529 | KHRN_IMAGE_FORMAT_T color; |
| 530 | KHRN_IMAGE_FORMAT_T depth; |
| 531 | KHRN_IMAGE_FORMAT_T mask; |
| 532 | KHRN_IMAGE_FORMAT_T multi; |
| 533 | EGLint config_depth_bits; |
| 534 | EGLint config_stencil_bits; |
| 535 | uint32_t results[5]; |
| 536 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
| 537 | |
| 538 | EGL_SURFACE_T *surface = egl_surface_pool_alloc(); |
| 539 | |
| 540 | if (!surface) { |
| 541 | *error = EGL_BAD_ALLOC; |
| 542 | return 0; |
| 543 | } |
| 544 | |
| 545 | /* TODO: respect largest_pbuffer? */ |
| 546 | |
| 547 | surface->name = name; |
| 548 | surface->type = PBUFFER; |
| 549 | |
| 550 | surface->config = config; |
| 551 | surface->win = 0; |
| 552 | surface->swap_interval = 1; |
| 553 | |
| 554 | surface->largest_pbuffer = largest_pbuffer; |
| 555 | surface->mipmap_texture = mipmap_texture; |
| 556 | surface->mipmap_level = 0; |
| 557 | surface->texture_format = texture_format; |
| 558 | surface->texture_target = texture_target; |
| 559 | surface->pixmap = 0; |
| 560 | surface->pixmap_server_handle[0] = 0; |
| 561 | surface->pixmap_server_handle[1] = (uint32_t)-1; |
| 562 | surface->server_owned = false; |
| 563 | |
| 564 | surface->context_binding_count = 0; |
| 565 | surface->is_destroyed = false; |
| 566 | |
| 567 | #if EGL_KHR_lock_surface |
| 568 | surface->is_locked = false; |
| 569 | surface->mapped_buffer = 0; |
| 570 | #endif |
| 571 | |
| 572 | color = egl_config_get_color_format((int)(size_t)config - 1); |
| 573 | depth = egl_config_get_depth_format((int)(size_t)config - 1); |
| 574 | mask = egl_config_get_mask_format((int)(size_t)config - 1); |
| 575 | multi = egl_config_get_multisample_format((int)(size_t)config - 1); |
| 576 | |
| 577 | /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ |
| 578 | egl_config_get_attrib((int)(size_t)config - 1, EGL_DEPTH_SIZE, &config_depth_bits); |
| 579 | egl_config_get_attrib((int)(size_t)config - 1, EGL_STENCIL_SIZE, &config_stencil_bits); |
| 580 | |
| 581 | vcos_assert(color != IMAGE_FORMAT_INVALID); |
| 582 | |
| 583 | surface->buffers = 1; |
| 584 | |
| 585 | RPC_CALL9_OUT_CTRL(eglIntCreatePbufferFromVGImage_impl, |
| 586 | thread, |
| 587 | EGLINTCREATEPBUFFERFROMVGIMAGE_ID, |
| 588 | RPC_UINT(vg_handle), |
| 589 | RPC_UINT(color), |
| 590 | RPC_UINT(depth), |
| 591 | RPC_UINT(mask), |
| 592 | RPC_UINT(multi), |
| 593 | RPC_UINT(mipmap_texture), |
| 594 | RPC_UINT(config_depth_bits), |
| 595 | RPC_UINT(config_stencil_bits), |
| 596 | results); |
| 597 | |
| 598 | surface->avail_buffers_valid = false; |
| 599 | |
| 600 | if (results[0]) { |
| 601 | KHRN_IMAGE_FORMAT_T format = (KHRN_IMAGE_FORMAT_T)results[4]; |
| 602 | |
| 603 | surface->serverbuffer = results[0]; |
| 604 | surface->width = results[2]; |
| 605 | surface->height = results[3]; |
| 606 | |
| 607 | /* TODO: picking apart image formats like this seems messy */ |
| 608 | surface->colorspace = (format & IMAGE_FORMAT_LIN) ? LINEAR : SRGB; |
| 609 | surface->alphaformat = (format & IMAGE_FORMAT_PRE) ? PRE : NONPRE; |
| 610 | *error = EGL_SUCCESS; |
| 611 | return surface; |
| 612 | } else { |
| 613 | *error = results[1]; |
| 614 | egl_surface_pool_free(surface); |
| 615 | return 0; |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | #endif /* NO_OPENVG */ |
| 620 | |
| 621 | /* |
| 622 | void egl_surface_free(EGL_SURFACE_T *surface) |
| 623 | |
| 624 | Preconditions: |
| 625 | |
| 626 | surface is a valid EGL_SURFACE_T returned from egl_surface_create or egl_surface_from_vg_image |
| 627 | |
| 628 | Postconditions: |
| 629 | |
| 630 | surface is freed and any associated server-side resources are dereferenced. |
| 631 | */ |
| 632 | |
| 633 | void egl_surface_free(EGL_SURFACE_T *surface) |
| 634 | { |
| 635 | CLIENT_THREAD_STATE_T *thread; |
| 636 | |
| 637 | vcos_log_trace("egl_surface_free" ); |
| 638 | |
| 639 | thread = CLIENT_GET_THREAD_STATE(); |
| 640 | |
| 641 | if( surface->type == WINDOW ) { |
| 642 | vcos_log_trace("egl_surface_free: calling platform_destroy_winhandle..." ); |
| 643 | platform_destroy_winhandle( surface->win, surface->internal_handle ); |
| 644 | } |
| 645 | /* return value ignored -- read performed to ensure blocking. we want this to |
| 646 | * block so clients can safely destroy the surface's window as soon as the |
| 647 | * egl call that destroys the surface returns (usually eglDestroySurface, but |
| 648 | * could be eg eglMakeCurrent) */ |
| 649 | vcos_log_trace("egl_surface_free: calling eglIntDestroySurface_impl via RPC...; " |
| 650 | "thread = 0x%X; serverbuffer = 0x%X" , |
| 651 | (uint32_t) thread, (uint32_t) surface->serverbuffer); |
| 652 | (void)RPC_INT_RES(RPC_CALL1_RES(eglIntDestroySurface_impl, |
| 653 | thread, |
| 654 | EGLINTDESTROYSURFACE_ID, |
| 655 | RPC_UINT(surface->serverbuffer))); |
| 656 | |
| 657 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
| 658 | if(surface->internal_handle != PLATFORM_WIN_NONE) // TODO what about pbuffers? |
| 659 | { |
| 660 | vcos_log_trace("egl_surface_free: calling wfc_stream_destroy..." ); |
| 661 | wfc_stream_destroy((WFCNativeStreamType) surface->internal_handle); |
| 662 | } |
| 663 | #endif |
| 664 | |
| 665 | vcos_log_trace("egl_surface_free: calling egl_surface_pool_free..." ); |
| 666 | egl_surface_pool_free(surface); |
| 667 | |
| 668 | vcos_log_trace("egl_surface_free: end" ); |
| 669 | } |
| 670 | |
| 671 | EGLint egl_surface_get_render_buffer(EGL_SURFACE_T *surface) |
| 672 | { |
| 673 | switch (surface->type) { |
| 674 | case WINDOW: |
| 675 | if (surface->buffers == 1) |
| 676 | return EGL_SINGLE_BUFFER; |
| 677 | else |
| 678 | return EGL_BACK_BUFFER; |
| 679 | case PBUFFER: |
| 680 | return EGL_BACK_BUFFER; |
| 681 | case PIXMAP: |
| 682 | return EGL_SINGLE_BUFFER; |
| 683 | default: |
| 684 | UNREACHABLE(); |
| 685 | return EGL_NONE; |
| 686 | } |
| 687 | } |
| 688 | |
| 689 | EGLBoolean egl_surface_get_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) |
| 690 | { |
| 691 | switch (attrib) { |
| 692 | case EGL_VG_ALPHA_FORMAT: |
| 693 | if (surface->alphaformat == NONPRE) |
| 694 | *value = EGL_VG_ALPHA_FORMAT_NONPRE; |
| 695 | else |
| 696 | *value = EGL_VG_ALPHA_FORMAT_PRE; |
| 697 | return EGL_TRUE; |
| 698 | case EGL_VG_COLORSPACE: |
| 699 | if (surface->colorspace == SRGB) |
| 700 | *value = EGL_VG_COLORSPACE_sRGB; |
| 701 | else |
| 702 | *value = EGL_VG_COLORSPACE_LINEAR; |
| 703 | return EGL_TRUE; |
| 704 | case EGL_CONFIG_ID: |
| 705 | *value = (EGLint)(size_t)surface->config; |
| 706 | return EGL_TRUE; |
| 707 | case EGL_HEIGHT: |
| 708 | *value = surface->height; |
| 709 | return EGL_TRUE; |
| 710 | case EGL_HORIZONTAL_RESOLUTION: |
| 711 | case EGL_VERTICAL_RESOLUTION: |
| 712 | *value = EGL_UNKNOWN; |
| 713 | return EGL_TRUE; |
| 714 | case EGL_LARGEST_PBUFFER: |
| 715 | // For a window or pixmap surface, the contents of value are not modified. |
| 716 | if (surface->type == PBUFFER) |
| 717 | *value = surface->largest_pbuffer; |
| 718 | return EGL_TRUE; |
| 719 | case EGL_MIPMAP_TEXTURE: |
| 720 | // Querying EGL_MIPMAP_TEXTURE for a non-pbuffer surface is not |
| 721 | // an error, but value is not modified. |
| 722 | if (surface->type == PBUFFER) |
| 723 | *value = surface->mipmap_texture; |
| 724 | return EGL_TRUE; |
| 725 | case EGL_MIPMAP_LEVEL: |
| 726 | // Querying EGL_MIPMAP_LEVEL for a non-pbuffer surface is not |
| 727 | // an error, but value is not modified. |
| 728 | if (surface->type == PBUFFER) |
| 729 | *value = surface->mipmap_level; |
| 730 | return EGL_TRUE; |
| 731 | case EGL_PIXEL_ASPECT_RATIO: |
| 732 | *value = EGL_DISPLAY_SCALING; |
| 733 | return EGL_TRUE; |
| 734 | case EGL_RENDER_BUFFER: |
| 735 | *value = egl_surface_get_render_buffer(surface); |
| 736 | return EGL_TRUE; |
| 737 | case EGL_SWAP_BEHAVIOR: |
| 738 | *value = surface->swap_behavior; |
| 739 | return EGL_TRUE; |
| 740 | case EGL_MULTISAMPLE_RESOLVE: |
| 741 | *value = surface->multisample_resolve; |
| 742 | return EGL_TRUE; |
| 743 | case EGL_TEXTURE_FORMAT: |
| 744 | // Querying EGL_TEXTURE_FORMAT for a non-pbuffer surface is not |
| 745 | // an error, but value is not modified. |
| 746 | if (surface->type == PBUFFER) |
| 747 | *value = surface->texture_format; |
| 748 | return EGL_TRUE; |
| 749 | case EGL_TEXTURE_TARGET: |
| 750 | // Querying EGL_TEXTURE_TARGET for a non-pbuffer surface is not |
| 751 | // an error, but value is not modified. |
| 752 | if (surface->type == PBUFFER) |
| 753 | *value = surface->texture_target; |
| 754 | return EGL_TRUE; |
| 755 | case EGL_WIDTH: |
| 756 | *value = surface->width; |
| 757 | return EGL_TRUE; |
| 758 | default: |
| 759 | return EGL_FALSE; |
| 760 | } |
| 761 | } |
| 762 | |
| 763 | EGLint egl_surface_set_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint value) |
| 764 | { |
| 765 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
| 766 | switch (attrib) { |
| 767 | case EGL_MIPMAP_LEVEL: |
| 768 | if (surface->type == PBUFFER) { |
| 769 | RPC_CALL2(eglIntSelectMipmap_impl, |
| 770 | thread, |
| 771 | EGLINTSELECTMIPMAP_ID, |
| 772 | RPC_UINT(surface->serverbuffer), |
| 773 | RPC_INT(value)); |
| 774 | |
| 775 | surface->mipmap_level = value; |
| 776 | } |
| 777 | return EGL_SUCCESS; |
| 778 | case EGL_SWAP_BEHAVIOR: |
| 779 | switch (value) { |
| 780 | case EGL_BUFFER_PRESERVED: |
| 781 | case EGL_BUFFER_DESTROYED: |
| 782 | surface->swap_behavior = value; |
| 783 | return EGL_SUCCESS; |
| 784 | default: |
| 785 | return EGL_BAD_PARAMETER; |
| 786 | } |
| 787 | case EGL_MULTISAMPLE_RESOLVE: |
| 788 | switch (value) { |
| 789 | case EGL_MULTISAMPLE_RESOLVE_DEFAULT: |
| 790 | case EGL_MULTISAMPLE_RESOLVE_BOX: |
| 791 | surface->multisample_resolve = value; |
| 792 | return EGL_SUCCESS; |
| 793 | default: |
| 794 | return EGL_BAD_PARAMETER; |
| 795 | } |
| 796 | default: |
| 797 | return EGL_BAD_ATTRIBUTE; |
| 798 | } |
| 799 | } |
| 800 | |
| 801 | #if EGL_KHR_lock_surface |
| 802 | |
| 803 | EGLint egl_surface_get_mapped_buffer_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) |
| 804 | { |
| 805 | KHRN_IMAGE_FORMAT_T format; |
| 806 | bool is565; |
| 807 | |
| 808 | vcos_assert(surface); |
| 809 | |
| 810 | if (attrib == EGL_BITMAP_POINTER_KHR || attrib == EGL_BITMAP_PITCH_KHR) { |
| 811 | // Querying either of these causes the buffer to be mapped (if it isn't already) |
| 812 | // They also require that the surface is locked |
| 813 | |
| 814 | if (!surface->is_locked) { |
| 815 | return EGL_BAD_ACCESS; // TODO is this the right error? |
| 816 | } |
| 817 | |
| 818 | if (!surface->mapped_buffer) { |
| 819 | uint32_t size; |
| 820 | void *buffer; |
| 821 | format = egl_config_get_mapped_format((int)((intptr_t)surface->config - 1)); // type juggling to avoid pointer truncation warnings |
| 822 | size = khrn_image_get_size(format, surface->width, surface->height); |
| 823 | buffer = khrn_platform_malloc(size, "EGL_SURFACE_T.mapped_buffer" ); |
| 824 | |
| 825 | if (!buffer) { |
| 826 | return EGL_BAD_ALLOC; |
| 827 | } |
| 828 | |
| 829 | surface->mapped_buffer = buffer; |
| 830 | } |
| 831 | } |
| 832 | |
| 833 | if (!egl_config_is_lockable((int)((intptr_t)surface->config-1))) { // type juggling to avoid pointer truncation warnings |
| 834 | // Calling any of these on unlockable surfaces is allowed but returns undefined results |
| 835 | *value = 0; |
| 836 | return EGL_SUCCESS; |
| 837 | } |
| 838 | |
| 839 | format = egl_config_get_mapped_format((int)((intptr_t)surface->config-1)); // type juggling to avoid pointer truncation warnings |
| 840 | vcos_assert(format == RGB_565_RSO || format == ARGB_8888_RSO); |
| 841 | is565 = (format == RGB_565_RSO); // else 888 |
| 842 | |
| 843 | switch (attrib) { |
| 844 | case EGL_BITMAP_POINTER_KHR: |
| 845 | *value = (EGLint)(intptr_t)surface->mapped_buffer; // type juggling to avoid pointer truncation warnings |
| 846 | return EGL_SUCCESS; |
| 847 | case EGL_BITMAP_PITCH_KHR: |
| 848 | *value = khrn_image_get_stride(format, surface->width); |
| 849 | return EGL_SUCCESS; |
| 850 | case EGL_BITMAP_ORIGIN_KHR: |
| 851 | *value = EGL_LOWER_LEFT_KHR; // TODO: is this correct? |
| 852 | return EGL_SUCCESS; |
| 853 | case EGL_BITMAP_PIXEL_RED_OFFSET_KHR: |
| 854 | *value = is565 ? 11 : 0; // TODO: I've probably got these wrong too |
| 855 | return EGL_SUCCESS; |
| 856 | case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR: |
| 857 | *value = is565 ? 5 : 8; |
| 858 | return EGL_SUCCESS; |
| 859 | case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR: |
| 860 | *value = is565 ? 0 : 16; |
| 861 | return EGL_SUCCESS; |
| 862 | case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR: |
| 863 | *value = is565 ? 0 : 24; |
| 864 | return EGL_SUCCESS; |
| 865 | case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR: |
| 866 | *value = 0; |
| 867 | return EGL_SUCCESS; |
| 868 | default: |
| 869 | UNREACHABLE(); |
| 870 | return EGL_BAD_PARAMETER; |
| 871 | } |
| 872 | } |
| 873 | #endif |
| 874 | |
| 875 | |
| 876 | /* |
| 877 | void egl_surface_maybe_free(EGL_SURFACE_T *surface) |
| 878 | |
| 879 | Frees a surface together with its server-side resources if: |
| 880 | - it has been destroyed |
| 881 | - it is no longer current |
| 882 | |
| 883 | Implementation notes: |
| 884 | |
| 885 | - |
| 886 | |
| 887 | Preconditions: |
| 888 | |
| 889 | surface is a valid pointer |
| 890 | |
| 891 | Postconditions: |
| 892 | |
| 893 | Either: |
| 894 | - surface->is_destroyed is false (we don't change this), or |
| 895 | - surface->context_binding_count > 0, or |
| 896 | - surface has been deleted. |
| 897 | |
| 898 | Invariants preserved: |
| 899 | |
| 900 | - |
| 901 | |
| 902 | Invariants used: |
| 903 | |
| 904 | - |
| 905 | */ |
| 906 | |
| 907 | void egl_surface_maybe_free(EGL_SURFACE_T *surface) |
| 908 | { |
| 909 | vcos_assert(surface); |
| 910 | |
| 911 | if (!surface->is_destroyed) |
| 912 | return; |
| 913 | |
| 914 | if (surface->context_binding_count) |
| 915 | return; |
| 916 | |
| 917 | egl_surface_free(surface); |
| 918 | } |
| 919 | |