/* Copyright (c) 2012, Broadcom Europe Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define VCOS_LOG_CATEGORY (&egl_client_log_cat) #include "interface/khronos/common/khrn_int_common.h" #include "interface/khronos/common/khrn_client_rpc.h" #include "interface/khronos/common/khrn_client_platform.h" #include "interface/khronos/egl/egl_client_surface.h" #include "interface/khronos/egl/egl_client_config.h" #include "interface/khronos/common/khrn_client.h" #ifdef KHRONOS_EGL_PLATFORM_OPENWFC #include "interface/khronos/wf/wfc_int.h" #include "interface/khronos/wf/wfc_client_stream.h" #endif #ifdef RPC_DIRECT #include "interface/khronos/egl/egl_int_impl.h" #endif #include /* surface_pool cache for a small number of pre-allocated surface objects Validity: surfaces[i] is valid if allocated & (1<avail_buffers_valid) khronos_platform_semaphore_destroy(&surface->avail_buffers); surface->avail_buffers_valid = false; i = (unsigned int) (surface - surface_pool.surfaces); if (i < EGL_SURFACE_POOL_SIZE) { surface_pool.allocated &= ~(1 << i); } else { khrn_platform_free((void*)surface); } } /* EGLBoolean egl_surface_check_attribs_window(const EGLint *attrib_list, EGLBoolean *linear, EGLBoolean *premult, EGLBoolean *single) TODO: are we actually supposed to validate our parameters and generate an error if they're wrong? I can't find an explicit mention in the spec about it. (except for EGL_WIDTH and EGL_HEIGHT in pbuffer) Preconditions: type in {WINDOW, PBUFFER, PIXMAP} attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs linear, premult are NULL or valid pointers If type == WINDOW then single is NULL or a valid pointer If type == PBUFFER then width, height, largest_pbuffer, texture_format, texture_target, mipmap_texture are NULL or valid pointers Postconditions: - */ bool egl_surface_check_attribs( EGL_SURFACE_TYPE_T type, const EGLint *attrib_list, bool *linear, bool *premult, bool *single, int *width, int *height, bool *largest_pbuffer, EGLenum *texture_format, EGLenum *texture_target, bool *mipmap_texture ) { if (!attrib_list) return true; while (*attrib_list != EGL_NONE) { int name = *attrib_list++; int value = *attrib_list++; switch (name) { case EGL_VG_COLORSPACE: if (value != EGL_VG_COLORSPACE_sRGB && value != EGL_VG_COLORSPACE_LINEAR) return false; if (value == EGL_VG_COLORSPACE_LINEAR && linear != NULL) *linear = true; break; case EGL_VG_ALPHA_FORMAT: if (value != EGL_VG_ALPHA_FORMAT_NONPRE && value != EGL_VG_ALPHA_FORMAT_PRE) return false; if (value == EGL_VG_ALPHA_FORMAT_PRE && premult != NULL) *premult = true; break; /* For WINDOW types only */ case EGL_RENDER_BUFFER: if (type != WINDOW || (value != EGL_SINGLE_BUFFER && value != EGL_BACK_BUFFER)) return false; if (value == EGL_SINGLE_BUFFER && single != NULL) *single = true; break; /* For PBUFFER types only */ case EGL_WIDTH: if (type != PBUFFER || value < 0) return false; if (width != NULL) *width = value; break; case EGL_HEIGHT: if (type != PBUFFER || value < 0) return false; if (height != NULL) *height = value; break; case EGL_LARGEST_PBUFFER: if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) return false; if (largest_pbuffer != NULL) *largest_pbuffer = value; break; case EGL_TEXTURE_FORMAT: if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_RGB && value != EGL_TEXTURE_RGBA)) return false; if (texture_format != NULL) *texture_format = value; break; case EGL_TEXTURE_TARGET: if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_2D)) return false; if (texture_target != NULL) *texture_target = value; break; case EGL_MIPMAP_TEXTURE: if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) return false; if (mipmap_texture != NULL) *mipmap_texture = value; break; default: return false; } } return true; } /* EGL_SURFACE_T *egl_surface_create( EGLSurface name, EGL_SURFACE_TYPE_T type, EGL_SURFACE_COLORSPACE_T colorspace, EGL_SURFACE_ALPHAFORMAT_T alphaformat, uint32_t buffers, uint32_t width, uint32_t height, EGLConfig config, EGLNativeWindowType win, uint32_t serverwin, bool largest_pbuffer, bool mipmap_texture, EGLenum texture_format, EGLenum texture_target, EGLNativePixmapType pixmap, const uint32_t *pixmap_server_handle) Implementation notes: TODO: respect largest_pbuffer? Preconditions: type in {WINDOW,PBUFFER,PIXMAP} colorspace in {SRGB,LINEAR} alphaformat in {NONPRE,PRE} 1 <= buffers <= EGL_MAX_BUFFERS 0 < width, 0 < height If !largest_pbuffer then width <= EGL_CONFIG_MAX_WIDTH, height <= EGL_CONFIG_MAX_HEIGHT config is a valid EGL config If type == WINDOW then win is a valid client-side handle to window W serverwin is a valid server-side handle to window W else win == 0 serverwin == PLATFORM_WIN_NONE If type == PBBUFFER then texture_format in {EGL_NO_TEXTURE, EGL_TEXTURE_RGB, EGL_TEXTURE_RGBA} texture_target in {EGL_NO_TEXTURE, EGL_TEXTURE_2D} else largest_pbuffer == mipmap_texture == false texture_format == texture_target == EGL_NO_TEXTURE If type == PIXMAP then pixmap is a valid client-side handle to pixmap P If pixmap is a server-side pixmap then pixmap_server_handle is a pointer to two elements, representing a valid server-side handle to pixmap P else pixmap_server_handle == 0 else pixmap == pixmap_server_handle == 0 Postconditions: Return value is NULL or an EGL_SURFACE_T structure, valid until egl_surface_free is called Invariants preserved: All invaraints on EGL_SURFACE_T */ EGL_SURFACE_T *egl_surface_create( EGLSurface name, EGL_SURFACE_TYPE_T type, EGL_SURFACE_COLORSPACE_T colorspace, EGL_SURFACE_ALPHAFORMAT_T alphaformat, uint32_t buffers, uint32_t width, uint32_t height, EGLConfig config, EGLNativeWindowType win, uint32_t serverwin, bool largest_pbuffer, bool texture_compatibility, bool mipmap_texture, EGLenum texture_format, EGLenum texture_target, EGLNativePixmapType pixmap, const uint32_t *pixmap_server_handle) { KHRN_IMAGE_FORMAT_T color; KHRN_IMAGE_FORMAT_T depth; KHRN_IMAGE_FORMAT_T mask; KHRN_IMAGE_FORMAT_T multi; uint32_t configid; uint32_t sem_name; EGLint config_depth_bits; EGLint config_stencil_bits; CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); EGL_SURFACE_T *surface = egl_surface_pool_alloc(); //vcos_assert(width > 0 && height > 0); vcos_assert((width <= EGL_CONFIG_MAX_WIDTH && height <= EGL_CONFIG_MAX_HEIGHT) || largest_pbuffer); if (!surface) { return 0; } /* TODO: respect largest_pbuffer? */ surface->name = name; surface->type = type; surface->colorspace = colorspace; surface->alphaformat = alphaformat; surface->config = config; surface->win = win; surface->width = width; surface->height = height; surface->swap_interval = 1; surface->base_width = width; surface->base_height = height; surface->internal_handle = serverwin; surface->largest_pbuffer = largest_pbuffer; surface->mipmap_texture = mipmap_texture; surface->mipmap_level = 0; surface->texture_format = texture_format; surface->texture_target = texture_target; surface->pixmap = pixmap; surface->pixmap_server_handle[0] = 0; surface->pixmap_server_handle[1] = (uint32_t)-1; surface->server_owned = false; surface->swap_behavior = buffers > 1 ? EGL_BUFFER_DESTROYED : EGL_BUFFER_PRESERVED; surface->multisample_resolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT; surface->context_binding_count = 0; surface->is_destroyed = false; #if EGL_KHR_lock_surface surface->is_locked = false; surface->mapped_buffer = 0; #endif configid = egl_config_to_id(config); color = egl_config_get_color_format(configid); if (texture_compatibility) { color = khrn_image_to_tf_format(color); } if (alphaformat == PRE) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_PRE); } if (colorspace == LINEAR) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_LIN); } depth = egl_config_get_depth_format(configid); mask = egl_config_get_mask_format(configid); multi = egl_config_get_multisample_format(configid); /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ egl_config_get_attrib(configid, EGL_DEPTH_SIZE, &config_depth_bits); egl_config_get_attrib(configid, EGL_STENCIL_SIZE, &config_stencil_bits); vcos_assert(color != IMAGE_FORMAT_INVALID); #ifdef KHRONOS_EGL_PLATFORM_OPENWFC // Create stream for this window if(type != PBUFFER) { WFCNativeStreamType stream = (WFCNativeStreamType) surface->internal_handle; vcos_assert(stream != WFC_INVALID_HANDLE); uint32_t failure = wfc_stream_create(stream, WFC_STREAM_FLAGS_EGL); vcos_log_trace("Creating stream with handle %X", stream); vcos_assert(failure == 0); } // if #endif surface->buffers = buffers; if (pixmap_server_handle) { vcos_assert(type == PIXMAP); surface->pixmap_server_handle[0] = pixmap_server_handle[0]; surface->pixmap_server_handle[1] = pixmap_server_handle[1]; surface->serverbuffer = RPC_UINT_RES(RPC_CALL7_RES(eglIntCreateWrappedSurface_impl, thread, EGLINTCREATEWRAPPEDSURFACE_ID, RPC_UINT(pixmap_server_handle[0]), RPC_UINT(pixmap_server_handle[1]), RPC_UINT(depth), RPC_UINT(mask), RPC_UINT(multi), RPC_UINT(config_depth_bits), RPC_UINT(config_stencil_bits))); surface->avail_buffers_valid = false; } else { #ifdef __SYMBIAN32__ uint32_t nbuff = 0; surface->avail_buffers_valid = 0; if (surface->buffers > 1) { uint64_t pid = rpc_get_client_id(thread); int sem[3] = { (int)pid, (int)(pid >> 32), (int)name }; if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) surface->avail_buffers_valid = 1; nbuff = (int)surface->avail_buffers; } if (surface->buffers == 1 || surface->avail_buffers_valid) { uint32_t results[3]; RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, thread, EGLINTCREATESURFACE_ID, RPC_UINT(serverwin), RPC_UINT(buffers), RPC_UINT(width), RPC_UINT(height), RPC_UINT(color), RPC_UINT(depth), RPC_UINT(mask), RPC_UINT(multi), RPC_UINT(largest_pbuffer), RPC_UINT(mipmap_texture), RPC_UINT(config_depth_bits), RPC_UINT(config_stencil_bits), RPC_UINT((int)nbuff), RPC_UINT(type), results); #else surface->avail_buffers_valid = false; sem_name = KHRN_NO_SEMAPHORE; #ifndef KHRONOS_EGL_PLATFORM_OPENWFC if (surface->buffers > 1) { uint64_t pid = rpc_get_client_id(thread); int sem[3]; sem[0] = (int)pid; sem[1] = (int)(pid >> 32); sem[2] = (int)name; sem_name = (int)name; if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) surface->avail_buffers_valid = true; } if (sem_name == KHRN_NO_SEMAPHORE || surface->avail_buffers_valid) { #else sem_name = (uint32_t)surface->internal_handle; vcos_log_trace("Surface create has semaphore %X", sem_name); #endif uint32_t results[3]; RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, thread, EGLINTCREATESURFACE_ID, RPC_UINT(serverwin), RPC_UINT(buffers), RPC_UINT(width), RPC_UINT(height), RPC_UINT(color), RPC_UINT(depth), RPC_UINT(mask), RPC_UINT(multi), RPC_UINT(largest_pbuffer), RPC_UINT(mipmap_texture), RPC_UINT(config_depth_bits), RPC_UINT(config_stencil_bits), RPC_UINT(sem_name), RPC_UINT(type), results); #endif surface->width = results[0]; surface->height = results[1]; surface->serverbuffer = results[2]; #ifndef KHRONOS_EGL_PLATFORM_OPENWFC } else { surface->serverbuffer = 0; } #endif } if (surface->serverbuffer) return surface; else { /* Server failed to create a surface due to out-of-memory or we failed to create the named semaphore object. */ egl_surface_pool_free(surface); return 0; } } #ifndef NO_OPENVG /* Either returns a valid EGL_SURFACE_T, or returns null and sets error appropriately */ EGL_SURFACE_T *egl_surface_from_vg_image( VGImage vg_handle, EGLSurface name, EGLConfig config, EGLBoolean largest_pbuffer, EGLBoolean mipmap_texture, EGLenum texture_format, EGLenum texture_target, EGLint *error) { KHRN_IMAGE_FORMAT_T color; KHRN_IMAGE_FORMAT_T depth; KHRN_IMAGE_FORMAT_T mask; KHRN_IMAGE_FORMAT_T multi; EGLint config_depth_bits; EGLint config_stencil_bits; uint32_t results[5]; CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); EGL_SURFACE_T *surface = egl_surface_pool_alloc(); if (!surface) { *error = EGL_BAD_ALLOC; return 0; } /* TODO: respect largest_pbuffer? */ surface->name = name; surface->type = PBUFFER; surface->config = config; surface->win = 0; surface->swap_interval = 1; surface->largest_pbuffer = largest_pbuffer; surface->mipmap_texture = mipmap_texture; surface->mipmap_level = 0; surface->texture_format = texture_format; surface->texture_target = texture_target; surface->pixmap = 0; surface->pixmap_server_handle[0] = 0; surface->pixmap_server_handle[1] = (uint32_t)-1; surface->server_owned = false; surface->context_binding_count = 0; surface->is_destroyed = false; #if EGL_KHR_lock_surface surface->is_locked = false; surface->mapped_buffer = 0; #endif color = egl_config_get_color_format((int)(size_t)config - 1); depth = egl_config_get_depth_format((int)(size_t)config - 1); mask = egl_config_get_mask_format((int)(size_t)config - 1); multi = egl_config_get_multisample_format((int)(size_t)config - 1); /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ egl_config_get_attrib((int)(size_t)config - 1, EGL_DEPTH_SIZE, &config_depth_bits); egl_config_get_attrib((int)(size_t)config - 1, EGL_STENCIL_SIZE, &config_stencil_bits); vcos_assert(color != IMAGE_FORMAT_INVALID); surface->buffers = 1; RPC_CALL9_OUT_CTRL(eglIntCreatePbufferFromVGImage_impl, thread, EGLINTCREATEPBUFFERFROMVGIMAGE_ID, RPC_UINT(vg_handle), RPC_UINT(color), RPC_UINT(depth), RPC_UINT(mask), RPC_UINT(multi), RPC_UINT(mipmap_texture), RPC_UINT(config_depth_bits), RPC_UINT(config_stencil_bits), results); surface->avail_buffers_valid = false; if (results[0]) { KHRN_IMAGE_FORMAT_T format = (KHRN_IMAGE_FORMAT_T)results[4]; surface->serverbuffer = results[0]; surface->width = results[2]; surface->height = results[3]; /* TODO: picking apart image formats like this seems messy */ surface->colorspace = (format & IMAGE_FORMAT_LIN) ? LINEAR : SRGB; surface->alphaformat = (format & IMAGE_FORMAT_PRE) ? PRE : NONPRE; *error = EGL_SUCCESS; return surface; } else { *error = results[1]; egl_surface_pool_free(surface); return 0; } } #endif /* NO_OPENVG */ /* void egl_surface_free(EGL_SURFACE_T *surface) Preconditions: surface is a valid EGL_SURFACE_T returned from egl_surface_create or egl_surface_from_vg_image Postconditions: surface is freed and any associated server-side resources are dereferenced. */ void egl_surface_free(EGL_SURFACE_T *surface) { CLIENT_THREAD_STATE_T *thread; vcos_log_trace("egl_surface_free"); thread = CLIENT_GET_THREAD_STATE(); if( surface->type == WINDOW ) { vcos_log_trace("egl_surface_free: calling platform_destroy_winhandle..."); platform_destroy_winhandle( surface->win, surface->internal_handle ); } /* return value ignored -- read performed to ensure blocking. we want this to * block so clients can safely destroy the surface's window as soon as the * egl call that destroys the surface returns (usually eglDestroySurface, but * could be eg eglMakeCurrent) */ vcos_log_trace("egl_surface_free: calling eglIntDestroySurface_impl via RPC...; " "thread = 0x%X; serverbuffer = 0x%X", (uint32_t) thread, (uint32_t) surface->serverbuffer); (void)RPC_INT_RES(RPC_CALL1_RES(eglIntDestroySurface_impl, thread, EGLINTDESTROYSURFACE_ID, RPC_UINT(surface->serverbuffer))); #ifdef KHRONOS_EGL_PLATFORM_OPENWFC if(surface->internal_handle != PLATFORM_WIN_NONE) // TODO what about pbuffers? { vcos_log_trace("egl_surface_free: calling wfc_stream_destroy..."); wfc_stream_destroy((WFCNativeStreamType) surface->internal_handle); } #endif vcos_log_trace("egl_surface_free: calling egl_surface_pool_free..."); egl_surface_pool_free(surface); vcos_log_trace("egl_surface_free: end"); } EGLint egl_surface_get_render_buffer(EGL_SURFACE_T *surface) { switch (surface->type) { case WINDOW: if (surface->buffers == 1) return EGL_SINGLE_BUFFER; else return EGL_BACK_BUFFER; case PBUFFER: return EGL_BACK_BUFFER; case PIXMAP: return EGL_SINGLE_BUFFER; default: UNREACHABLE(); return EGL_NONE; } } EGLBoolean egl_surface_get_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) { switch (attrib) { case EGL_VG_ALPHA_FORMAT: if (surface->alphaformat == NONPRE) *value = EGL_VG_ALPHA_FORMAT_NONPRE; else *value = EGL_VG_ALPHA_FORMAT_PRE; return EGL_TRUE; case EGL_VG_COLORSPACE: if (surface->colorspace == SRGB) *value = EGL_VG_COLORSPACE_sRGB; else *value = EGL_VG_COLORSPACE_LINEAR; return EGL_TRUE; case EGL_CONFIG_ID: *value = (EGLint)(size_t)surface->config; return EGL_TRUE; case EGL_HEIGHT: *value = surface->height; return EGL_TRUE; case EGL_HORIZONTAL_RESOLUTION: case EGL_VERTICAL_RESOLUTION: *value = EGL_UNKNOWN; return EGL_TRUE; case EGL_LARGEST_PBUFFER: // For a window or pixmap surface, the contents of value are not modified. if (surface->type == PBUFFER) *value = surface->largest_pbuffer; return EGL_TRUE; case EGL_MIPMAP_TEXTURE: // Querying EGL_MIPMAP_TEXTURE for a non-pbuffer surface is not // an error, but value is not modified. if (surface->type == PBUFFER) *value = surface->mipmap_texture; return EGL_TRUE; case EGL_MIPMAP_LEVEL: // Querying EGL_MIPMAP_LEVEL for a non-pbuffer surface is not // an error, but value is not modified. if (surface->type == PBUFFER) *value = surface->mipmap_level; return EGL_TRUE; case EGL_PIXEL_ASPECT_RATIO: *value = EGL_DISPLAY_SCALING; return EGL_TRUE; case EGL_RENDER_BUFFER: *value = egl_surface_get_render_buffer(surface); return EGL_TRUE; case EGL_SWAP_BEHAVIOR: *value = surface->swap_behavior; return EGL_TRUE; case EGL_MULTISAMPLE_RESOLVE: *value = surface->multisample_resolve; return EGL_TRUE; case EGL_TEXTURE_FORMAT: // Querying EGL_TEXTURE_FORMAT for a non-pbuffer surface is not // an error, but value is not modified. if (surface->type == PBUFFER) *value = surface->texture_format; return EGL_TRUE; case EGL_TEXTURE_TARGET: // Querying EGL_TEXTURE_TARGET for a non-pbuffer surface is not // an error, but value is not modified. if (surface->type == PBUFFER) *value = surface->texture_target; return EGL_TRUE; case EGL_WIDTH: *value = surface->width; return EGL_TRUE; default: return EGL_FALSE; } } EGLint egl_surface_set_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint value) { CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); switch (attrib) { case EGL_MIPMAP_LEVEL: if (surface->type == PBUFFER) { RPC_CALL2(eglIntSelectMipmap_impl, thread, EGLINTSELECTMIPMAP_ID, RPC_UINT(surface->serverbuffer), RPC_INT(value)); surface->mipmap_level = value; } return EGL_SUCCESS; case EGL_SWAP_BEHAVIOR: switch (value) { case EGL_BUFFER_PRESERVED: case EGL_BUFFER_DESTROYED: surface->swap_behavior = value; return EGL_SUCCESS; default: return EGL_BAD_PARAMETER; } case EGL_MULTISAMPLE_RESOLVE: switch (value) { case EGL_MULTISAMPLE_RESOLVE_DEFAULT: case EGL_MULTISAMPLE_RESOLVE_BOX: surface->multisample_resolve = value; return EGL_SUCCESS; default: return EGL_BAD_PARAMETER; } default: return EGL_BAD_ATTRIBUTE; } } #if EGL_KHR_lock_surface EGLint egl_surface_get_mapped_buffer_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) { KHRN_IMAGE_FORMAT_T format; bool is565; vcos_assert(surface); if (attrib == EGL_BITMAP_POINTER_KHR || attrib == EGL_BITMAP_PITCH_KHR) { // Querying either of these causes the buffer to be mapped (if it isn't already) // They also require that the surface is locked if (!surface->is_locked) { return EGL_BAD_ACCESS; // TODO is this the right error? } if (!surface->mapped_buffer) { uint32_t size; void *buffer; format = egl_config_get_mapped_format((int)((intptr_t)surface->config - 1)); // type juggling to avoid pointer truncation warnings size = khrn_image_get_size(format, surface->width, surface->height); buffer = khrn_platform_malloc(size, "EGL_SURFACE_T.mapped_buffer"); if (!buffer) { return EGL_BAD_ALLOC; } surface->mapped_buffer = buffer; } } if (!egl_config_is_lockable((int)((intptr_t)surface->config-1))) { // type juggling to avoid pointer truncation warnings // Calling any of these on unlockable surfaces is allowed but returns undefined results *value = 0; return EGL_SUCCESS; } format = egl_config_get_mapped_format((int)((intptr_t)surface->config-1)); // type juggling to avoid pointer truncation warnings vcos_assert(format == RGB_565_RSO || format == ARGB_8888_RSO); is565 = (format == RGB_565_RSO); // else 888 switch (attrib) { case EGL_BITMAP_POINTER_KHR: *value = (EGLint)(intptr_t)surface->mapped_buffer; // type juggling to avoid pointer truncation warnings return EGL_SUCCESS; case EGL_BITMAP_PITCH_KHR: *value = khrn_image_get_stride(format, surface->width); return EGL_SUCCESS; case EGL_BITMAP_ORIGIN_KHR: *value = EGL_LOWER_LEFT_KHR; // TODO: is this correct? return EGL_SUCCESS; case EGL_BITMAP_PIXEL_RED_OFFSET_KHR: *value = is565 ? 11 : 0; // TODO: I've probably got these wrong too return EGL_SUCCESS; case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR: *value = is565 ? 5 : 8; return EGL_SUCCESS; case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR: *value = is565 ? 0 : 16; return EGL_SUCCESS; case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR: *value = is565 ? 0 : 24; return EGL_SUCCESS; case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR: *value = 0; return EGL_SUCCESS; default: UNREACHABLE(); return EGL_BAD_PARAMETER; } } #endif /* void egl_surface_maybe_free(EGL_SURFACE_T *surface) Frees a surface together with its server-side resources if: - it has been destroyed - it is no longer current Implementation notes: - Preconditions: surface is a valid pointer Postconditions: Either: - surface->is_destroyed is false (we don't change this), or - surface->context_binding_count > 0, or - surface has been deleted. Invariants preserved: - Invariants used: - */ void egl_surface_maybe_free(EGL_SURFACE_T *surface) { vcos_assert(surface); if (!surface->is_destroyed) return; if (surface->context_binding_count) return; egl_surface_free(surface); }