mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-12 10:15:54 +00:00
919 lines
29 KiB
C
919 lines
29 KiB
C
/*
|
|
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 <stdlib.h>
|
|
|
|
|
|
/*
|
|
surface_pool
|
|
|
|
cache for a small number of pre-allocated surface objects
|
|
|
|
Validity:
|
|
surfaces[i] is valid if allocated & (1<<i)
|
|
*/
|
|
|
|
#define EGL_SURFACE_POOL_SIZE 2
|
|
static struct
|
|
{
|
|
EGL_SURFACE_T surfaces[EGL_SURFACE_POOL_SIZE];
|
|
uint32_t allocated;
|
|
} surface_pool;
|
|
|
|
extern VCOS_LOG_CAT_T egl_client_log_cat;
|
|
|
|
/*
|
|
EGL_SURFACE_T* egl_surface_pool_alloc(void)
|
|
|
|
Implementation notes:
|
|
|
|
We have a small static pool of structures (surface_pool) which we try and allocate out of
|
|
in order to reduce memory fragmentation. When we have run out of space in the pool we
|
|
resort to khrn_platform_malloc.
|
|
|
|
Preconditions:
|
|
|
|
Whoever calls this must initialise (or free) the returned structure in order to satisfy the invariant
|
|
on surface_pool.
|
|
|
|
Postconditions:
|
|
|
|
Return value is NULL or an uninitialised EGL_SURFACE_T structure, valid until egl_surface_pool_free
|
|
is called.
|
|
*/
|
|
|
|
static EGL_SURFACE_T* egl_surface_pool_alloc(void)
|
|
{
|
|
int i = 0;
|
|
|
|
while(surface_pool.allocated & (1 << i))
|
|
i++;
|
|
|
|
if (i < EGL_SURFACE_POOL_SIZE)
|
|
{
|
|
surface_pool.allocated |= 1 << i;
|
|
return &surface_pool.surfaces[i];
|
|
}
|
|
else
|
|
{
|
|
return (EGL_SURFACE_T*)khrn_platform_malloc(sizeof(EGL_SURFACE_T), "EGL_SURFACE_T");
|
|
}
|
|
}
|
|
|
|
static void egl_surface_pool_free(EGL_SURFACE_T* surface)
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
/* todo: this doesn't belong here */
|
|
//semaphore now gets destroyed on async callback from VC
|
|
if (surface->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);
|
|
}
|