This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
BasedOnStyle: InheritParentConfig
DisableFormat: false
ColumnLimit: 80
AlwaysBreakAfterReturnType: All
File diff suppressed because it is too large. Load diff
+631
View File
@@ -0,0 +1,631 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Kristian Høgsberg <[email protected]>
*/
#ifndef EGL_DRI2_INCLUDED
#define EGL_DRI2_INCLUDED
#include <stdbool.h>
#include <stdint.h>
#ifdef HAVE_X11_PLATFORM
#include <X11/Xlib-xcb.h>
#include <xcb/randr.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include "loader_dri_helper.h"
#ifdef HAVE_LIBDRM
#include "loader_dri3_helper.h"
#endif
#endif
#ifdef HAVE_WAYLAND_PLATFORM
#include "loader_wayland_helper.h"
/* forward declarations to avoid pulling wayland headers everywhere */
struct wl_egl_window;
struct wl_event_queue;
struct wl_callback;
struct wl_display;
struct wl_drm;
struct wl_registry;
struct wl_shm;
struct wl_surface;
struct wl_fixes;
struct zwp_linux_dmabuf_v1;
struct zwp_linux_dmabuf_feedback_v1;
#endif
#include <GL/gl.h>
#include "mesa_interface.h"
#include "kopper_interface.h"
#ifdef HAVE_DRM_PLATFORM
#include <gbm_driint.h>
#endif
#ifdef HAVE_ANDROID_PLATFORM
#define LOG_TAG "EGL-DRI2"
#include <hardware/gralloc.h>
#include "util/u_gralloc/u_gralloc.h"
#if ANDROID_API_LEVEL >= 26
#include <vndk/window.h>
#else
#include <system/window.h>
#endif
#endif /* HAVE_ANDROID_PLATFORM */
#include "eglconfig.h"
#include "eglcontext.h"
#include "eglcurrent.h"
#include "egldevice.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "eglimage.h"
#include "egllog.h"
#include "eglsurface.h"
#include "eglsync.h"
#include "util/bitset.h"
#include "util/u_dynarray.h"
#include "util/u_vector.h"
#include "util/format/u_format.h"
struct wl_buffer;
struct dri2_egl_display_vtbl {
/* mandatory on Wayland, unused otherwise */
int (*authenticate)(_EGLDisplay *disp, uint32_t id);
/* mandatory */
_EGLSurface *(*create_window_surface)(_EGLDisplay *disp, _EGLConfig *config,
void *native_window,
const EGLint *attrib_list);
/* optional */
_EGLSurface *(*create_pixmap_surface)(_EGLDisplay *disp, _EGLConfig *config,
void *native_pixmap,
const EGLint *attrib_list);
/* optional */
_EGLSurface *(*create_pbuffer_surface)(_EGLDisplay *disp, _EGLConfig *config,
const EGLint *attrib_list);
/* mandatory */
EGLBoolean (*destroy_surface)(_EGLDisplay *disp, _EGLSurface *surface);
/* optional */
EGLBoolean (*swap_interval)(_EGLDisplay *disp, _EGLSurface *surf,
EGLint interval);
/* mandatory */
_EGLImage *(*create_image)(_EGLDisplay *disp, _EGLContext *ctx,
EGLenum target, EGLClientBuffer buffer,
const EGLint *attr_list);
/* mandatory */
EGLBoolean (*swap_buffers)(_EGLDisplay *disp, _EGLSurface *surf);
/* optional - falls back to .swap_buffers */
EGLBoolean (*swap_buffers_with_damage)(_EGLDisplay *disp,
_EGLSurface *surface,
const EGLint *rects, EGLint n_rects);
/* optional */
EGLBoolean (*copy_buffers)(_EGLDisplay *disp, _EGLSurface *surf,
void *native_pixmap_target);
/* optional */
EGLint (*query_buffer_age)(_EGLDisplay *disp, _EGLSurface *surf);
/* optional */
EGLBoolean (*query_surface)(_EGLDisplay *disp, _EGLSurface *surf,
EGLint attribute, EGLint *value);
/* optional */
struct wl_buffer *(*create_wayland_buffer_from_image)(_EGLDisplay *disp,
_EGLImage *img);
/* optional */
EGLBoolean (*get_sync_values)(_EGLDisplay *display, _EGLSurface *surface,
EGLuint64KHR *ust, EGLuint64KHR *msc,
EGLuint64KHR *sbc);
/* optional */
EGLBoolean (*get_msc_rate)(_EGLDisplay *display, _EGLSurface *surface,
EGLint *numerator, EGLint *denominator);
/* mandatory */
struct dri_drawable *(*get_dri_drawable)(_EGLSurface *surf);
/* optional */
void (*close_screen_notify)(_EGLDisplay *disp);
/* Used in EGL_KHR_mutable_render_buffer to update the native window's
* shared buffer mode.
* optional
*/
bool (*set_shared_buffer_mode)(_EGLDisplay *disp, _EGLSurface *surf,
bool mode);
};
#ifdef HAVE_WAYLAND_PLATFORM
struct dri2_wl_formats {
unsigned int num_formats;
/* Bitmap referencing dri2_wl_visuals */
unsigned int *formats_bitmap;
/* Array of vectors. Contains one modifier vector per format */
struct u_vector *modifiers;
};
struct dmabuf_feedback_format_table {
unsigned int size;
struct {
uint32_t format;
uint32_t padding; /* unused */
uint64_t modifier;
} *data;
};
struct dmabuf_feedback_tranche {
dev_t target_device;
uint32_t flags;
struct dri2_wl_formats formats;
};
struct dmabuf_feedback {
dev_t main_device;
struct dmabuf_feedback_format_table format_table;
struct util_dynarray tranches;
struct dmabuf_feedback_tranche pending_tranche;
};
#endif
struct dri2_egl_display {
const struct dri2_egl_display_vtbl *vtbl;
mtx_t lock;
struct dri_screen *dri_screen_render_gpu;
/* dri_screen_display_gpu holds display GPU in case of prime gpu offloading
* else dri_screen_render_gpu and dri_screen_display_gpu is same. In case of
* prime gpu offloading, if display and render driver names are different
* (potentially not compatible), dri_screen_display_gpu will be NULL but
* fd_display_gpu will still hold fd for display driver.
*/
struct dri_screen *dri_screen_display_gpu;
bool own_dri_screen;
const struct dri_config **driver_configs;
/* fd of the GPU used for rendering. */
int fd_render_gpu;
/* fd of the GPU used for display. If the same GPU is used for display
* and rendering, then fd_render_gpu == fd_display_gpu (no need to use
* os_same_file_description).
*/
int fd_display_gpu;
/* dri2_initialize/dri2_terminate increment/decrement this count, so does
* dri2_make_current (tracks if there are active contexts/surfaces). */
int ref_count;
bool has_compression_modifiers;
bool own_device;
bool kopper;
bool swrast;
bool swrast_not_kms;
int min_swap_interval;
int max_swap_interval;
int default_swap_interval;
#ifdef HAVE_DRM_PLATFORM
struct gbm_dri_device *gbm_dri;
#endif
char *driver_name;
const __DRIextension **loader_extensions;
bool has_dmabuf_import;
bool has_dmabuf_export;
bool explicit_modifiers;
bool multibuffers_available;
#ifdef HAVE_X11_PLATFORM
xcb_connection_t *conn;
xcb_screen_t *screen;
bool swap_available;
#ifdef HAVE_LIBDRM
struct loader_screen_resources screen_resources;
#endif
#endif
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_display *wl_dpy;
struct wl_display *wl_dpy_wrapper;
struct wl_registry *wl_registry;
#ifdef HAVE_BIND_WL_DISPLAY
struct wl_drm *wl_server_drm;
struct wl_drm *wl_drm;
uint32_t wl_drm_version, wl_drm_name;
bool authenticated;
uint32_t capabilities;
#endif
struct wl_shm *wl_shm;
struct wl_event_queue *wl_queue;
struct wl_fixes *wl_fixes;
struct zwp_linux_dmabuf_v1 *wl_dmabuf;
struct wp_presentation *wp_presentation;
struct dri2_wl_formats formats;
struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
struct dmabuf_feedback_format_table format_table;
char *device_name;
bool is_render_node;
clockid_t presentation_clock_id;
#endif
#ifdef HAVE_ANDROID_PLATFORM
struct u_gralloc *gralloc;
/* gralloc vendor usage bit for front rendering */
uint32_t front_rendering_usage;
bool has_native_fence_fd;
bool pure_swrast;
#endif
};
struct dri2_egl_context {
_EGLContext base;
struct dri_context *dri_context;
};
struct dri2_egl_surface {
_EGLSurface base;
struct dri_drawable *dri_drawable;
__DRIbuffer buffers[5];
bool have_fake_front;
#ifdef HAVE_X11_PLATFORM
xcb_drawable_t drawable;
xcb_xfixes_region_t region;
int depth;
int bytes_per_pixel;
xcb_gcontext_t gc;
xcb_gcontext_t swapgc;
#endif
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_egl_window *wl_win;
int dx;
int dy;
struct wl_event_queue *wl_queue;
struct loader_wayland_surface wayland_surface;
struct wl_display *wl_dpy_wrapper;
struct wl_drm *wl_drm_wrapper;
struct wl_callback *throttle_callback;
struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback;
struct loader_wayland_presentation wayland_presentation;
bool compositor_using_another_device;
int format;
bool resized;
bool received_dmabuf_feedback;
#endif
#ifdef HAVE_DRM_PLATFORM
struct gbm_dri_surface *gbm_surf;
unsigned excess_bo_frames;
#endif
#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)
struct dri2_egl_buffer {
#ifdef HAVE_WAYLAND_PLATFORM
struct loader_wayland_buffer wayland_buffer;
bool wl_release;
struct dri_image *dri_image;
/* for is_different_gpu case. NULL else */
struct dri_image *linear_copy;
/* for swrast */
void *data;
int data_size;
#endif
#ifdef HAVE_DRM_PLATFORM
struct gbm_bo *bo;
#endif
bool locked;
int age;
} color_buffers[4], *back, *current;
#endif
#ifdef HAVE_ANDROID_PLATFORM
struct ANativeWindow *window;
struct ANativeWindowBuffer *buffer;
/* in-fence associated with buffer, -1 once passed down to dri layer: */
int in_fence_fd;
struct dri_image *dri_image_back;
struct dri_image *dri_image_front;
/* Used to record all the buffers created by ANativeWindow and their ages.
* Allocate number of color_buffers based on query to android bufferqueue
* and save color_buffers_count.
*/
int color_buffers_count;
struct {
struct ANativeWindowBuffer *buffer;
int age;
} *color_buffers, *back;
uint32_t gralloc_usage;
#endif
/* surfaceless and device */
struct dri_image *front;
enum pipe_format visual;
int out_fence_fd;
EGLBoolean enable_out_fence;
/* swrast device */
char *swrast_device_buffer;
};
struct dri2_egl_config {
_EGLConfig base;
const struct dri_config *dri_config[2][2];
};
struct dri2_egl_image {
_EGLImage base;
struct dri_image *dri_image;
};
struct dri2_egl_sync {
_EGLSync base;
mtx_t mutex;
cnd_t cond;
int refcount;
void *fence;
};
/* standard typecasts */
_EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
_EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
_EGL_DRIVER_TYPECAST(dri2_egl_sync, _EGLSync, obj)
static inline struct dri2_egl_display *
dri2_egl_display_lock(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
if (dri2_dpy)
mtx_lock(&dri2_dpy->lock);
return dri2_dpy;
}
static inline EGLBoolean
dri2_egl_error_unlock(struct dri2_egl_display *dri2_dpy, EGLint err,
const char *msg)
{
mtx_unlock(&dri2_dpy->lock);
return _eglError(err, msg);
}
extern const __DRIimageLookupExtension image_lookup_extension;
extern const __DRIswrastLoaderExtension swrast_pbuffer_loader_extension;
extern const __DRIkopperLoaderExtension kopper_pbuffer_loader_extension;
void
dri2_detect_swrast_kopper(_EGLDisplay *disp);
/* Helper for platforms not using dri2_create_screen */
void
dri2_setup_screen(_EGLDisplay *disp);
void
dri2_setup_swap_interval(_EGLDisplay *disp, int max_swap_interval);
EGLBoolean
dri2_create_screen(_EGLDisplay *disp);
EGLBoolean
dri2_setup_device(_EGLDisplay *disp, EGLBoolean software);
struct dri_drawable *
dri2_surface_get_dri_drawable(_EGLSurface *surf);
GLboolean
dri2_validate_egl_image(void *image, void *data);
struct dri_image *
dri2_lookup_egl_image_validated(void *image, void *data);
void
dri2_get_shifts_and_sizes(const struct dri_config *config, int *shifts,
unsigned int *sizes);
enum pipe_format
dri2_image_format_for_pbuffer_config(struct dri2_egl_display *dri2_dpy,
const struct dri_config *config);
struct dri2_egl_config *
dri2_add_config(_EGLDisplay *disp, const struct dri_config *dri_config,
EGLint surface_type, const EGLint *attr_list);
void
dri2_add_pbuffer_configs_for_visuals(_EGLDisplay *disp);
EGLint
dri2_from_dri_compression_rate(enum __DRIFixedRateCompression rate);
enum __DRIFixedRateCompression
dri2_to_dri_compression_rate(EGLint rate);
_EGLImage *
dri2_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list);
_EGLImage *
dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer buffer, const EGLint *attr_list);
_EGLImage *
dri2_create_image_from_dri(_EGLDisplay *disp, struct dri_image *dri_image);
#ifdef HAVE_X11_PLATFORM
EGLBoolean
dri2_initialize_x11(_EGLDisplay *disp);
void
dri2_teardown_x11(struct dri2_egl_display *dri2_dpy);
unsigned int
dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth);
#else
static inline EGLBoolean
dri2_initialize_x11(_EGLDisplay *disp)
{
return _eglError(EGL_NOT_INITIALIZED, "X11 platform not built");
}
static inline void
dri2_teardown_x11(struct dri2_egl_display *dri2_dpy)
{
}
static inline unsigned int
dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth)
{
return 0;
}
#endif
#ifdef HAVE_DRM_PLATFORM
EGLBoolean
dri2_initialize_drm(_EGLDisplay *disp);
void
dri2_teardown_drm(struct dri2_egl_display *dri2_dpy);
#else
static inline EGLBoolean
dri2_initialize_drm(_EGLDisplay *disp)
{
return _eglError(EGL_NOT_INITIALIZED, "GBM/DRM platform not built");
}
static inline void
dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
{
}
#endif
#ifdef HAVE_WAYLAND_PLATFORM
EGLBoolean
dri2_initialize_wayland(_EGLDisplay *disp);
void
dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy);
bool
dri2_wl_is_format_supported(void *user_data, uint32_t format);
#else
static inline EGLBoolean
dri2_initialize_wayland(_EGLDisplay *disp)
{
return _eglError(EGL_NOT_INITIALIZED, "Wayland platform not built");
}
static inline void
dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
{
}
#endif
#ifdef HAVE_ANDROID_PLATFORM
EGLBoolean
dri2_initialize_android(_EGLDisplay *disp);
#else
static inline EGLBoolean
dri2_initialize_android(_EGLDisplay *disp)
{
return _eglError(EGL_NOT_INITIALIZED, "Android platform not built");
}
#endif
EGLBoolean
dri2_initialize_surfaceless(_EGLDisplay *disp);
EGLBoolean
dri2_initialize_device(_EGLDisplay *disp);
static inline void
dri2_teardown_device(struct dri2_egl_display *dri2_dpy)
{ /* noop */
}
void
dri2_flush_drawable_for_swapbuffers_flags(
_EGLDisplay *disp, _EGLSurface *draw,
enum __DRI2throttleReason throttle_reason);
void
dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw);
const struct dri_config *
dri2_get_dri_config(struct dri2_egl_config *conf, EGLint surface_type,
EGLenum colorspace);
#include "dri_util.h"
static inline void
dri2_set_WL_bind_wayland_display(_EGLDisplay *disp)
{
#ifdef HAVE_BIND_WL_DISPLAY
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
disp->Extensions.WL_bind_wayland_display =
dri2_dpy->fd_render_gpu >= 0 &&
dri2_dpy->has_dmabuf_import && dri2_dpy->has_dmabuf_export;
#endif
}
void
dri2_display_destroy(_EGLDisplay *disp);
struct dri2_egl_display *
dri2_display_create(_EGLDisplay *disp);
EGLBoolean
dri2_init_surface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type,
_EGLConfig *conf, const EGLint *attrib_list,
EGLBoolean enable_out_fence, void *native_surface);
void
dri2_fini_surface(_EGLSurface *surf);
EGLBoolean
dri2_create_drawable(struct dri2_egl_display *dri2_dpy,
const struct dri_config *config,
struct dri2_egl_surface *dri2_surf, void *loaderPrivate);
static inline uint64_t
combine_u32_into_u64(uint32_t hi, uint32_t lo)
{
return (((uint64_t)hi) << 32) | (((uint64_t)lo) & 0xffffffff);
}
#endif /* EGL_DRI2_INCLUDED */
File diff suppressed because it is too large. Load diff
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright © 2021, Google Inc.
* Copyright (C) 2021, GlobalLogic Ukraine
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef EGL_ANDROID_INCLUDED
#define EGL_ANDROID_INCLUDED
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include "mesa_interface.h"
#include "egl_dri2.h"
#if ANDROID_API_LEVEL < 26
/* Shim layer to map ANativeWindow_* onto the legacy system internal APIs */
enum ANativeWindowQuery {
ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS = 3,
ANATIVEWINDOW_QUERY_DEFAULT_WIDTH = 6,
ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT = 7,
};
static inline void
ANativeWindow_acquire(struct ANativeWindow *window)
{
window->common.incRef(&window->common);
}
static inline void
ANativeWindow_release(struct ANativeWindow *window)
{
window->common.decRef(&window->common);
}
static inline int32_t
ANativeWindow_getFormat(struct ANativeWindow *window)
{
int32_t format = 0;
int res = window->query(window, NATIVE_WINDOW_FORMAT, &format);
return res < 0 ? res : format;
}
static inline int
ANativeWindow_dequeueBuffer(struct ANativeWindow *window,
struct ANativeWindowBuffer **buffer, int *fenceFd)
{
return window->dequeueBuffer(window, buffer, fenceFd);
}
static inline int
ANativeWindow_queueBuffer(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer, int fenceFd)
{
return window->queueBuffer(window, buffer, fenceFd);
}
static inline int
ANativeWindow_cancelBuffer(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer, int fenceFd)
{
return window->cancelBuffer(window, buffer, fenceFd);
}
static inline int
ANativeWindow_setUsage(struct ANativeWindow *window, uint64_t usage)
{
return native_window_set_usage(window, usage);
}
static inline int
ANativeWindow_setSharedBufferMode(struct ANativeWindow *window,
bool sharedBufferMode)
{
return native_window_set_shared_buffer_mode(window, sharedBufferMode);
}
static inline int
ANativeWindow_setSwapInterval(struct ANativeWindow *window, int interval)
{
return window->setSwapInterval(window, interval);
}
static inline int
ANativeWindow_query(const struct ANativeWindow *window,
enum ANativeWindowQuery what, int *value)
{
switch (what) {
case ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS:
case ANATIVEWINDOW_QUERY_DEFAULT_WIDTH:
case ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT:
break;
default:
return -EINVAL;
}
return window->query(window, (int)what, value);
}
#endif // ANDROID_API_LEVEL < 26
#endif /* EGL_ANDROID_INCLUDED */
+372
View File
@@ -0,0 +1,372 @@
/*
* Mesa 3-D graphics library
*
* Copyright 2018 Collabora
*
* Based on platform_surfaceless, which has:
*
* Copyright (c) 2014 The Chromium OS Authors.
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#endif
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "util/u_debug.h"
#include "egl_dri2.h"
#include "kopper_interface.h"
#include "loader.h"
#include "dri_util.h"
static struct dri_image *
device_alloc_image(struct dri2_egl_display *dri2_dpy,
struct dri2_egl_surface *dri2_surf)
{
return dri_create_image(
dri2_dpy->dri_screen_render_gpu, dri2_surf->base.Width,
dri2_surf->base.Height, dri2_surf->visual, NULL, 0, 0, NULL);
}
static void
device_free_images(struct dri2_egl_surface *dri2_surf)
{
if (dri2_surf->front) {
dri2_destroy_image(dri2_surf->front);
dri2_surf->front = NULL;
}
free(dri2_surf->swrast_device_buffer);
dri2_surf->swrast_device_buffer = NULL;
}
static int
device_image_get_buffers(struct dri_drawable *driDrawable, unsigned int format,
uint32_t *stamp, void *loaderPrivate,
uint32_t buffer_mask, struct __DRIimageList *buffers)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
buffers->image_mask = 0;
buffers->front = NULL;
buffers->back = NULL;
/* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
* the spec states that they have a back buffer but no front buffer, in
* contrast to pixmaps, which have a front buffer but no back buffer.
*
* Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
* from the spec, following the precedent of Mesa's EGL X11 platform. The
* X11 platform correctly assigns pbuffers to single-buffered configs, but
* assigns the pbuffer a front buffer instead of a back buffer.
*
* Pbuffers in the X11 platform mostly work today, so let's just copy its
* behavior instead of trying to fix (and hence potentially breaking) the
* world.
*/
if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
if (!dri2_surf->front)
dri2_surf->front = device_alloc_image(dri2_dpy, dri2_surf);
buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
buffers->front = dri2_surf->front;
}
return 1;
}
static _EGLSurface *
dri2_device_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct dri2_egl_surface *dri2_surf;
const struct dri_config *config;
/* Make sure to calloc so all pointers
* are originally NULL.
*/
dri2_surf = calloc(1, sizeof *dri2_surf);
if (!dri2_surf) {
_eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
return NULL;
}
if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
false, NULL))
goto cleanup_surface;
config = dri2_get_dri_config(dri2_conf, type, dri2_surf->base.GLColorspace);
if (!config) {
_eglError(EGL_BAD_MATCH,
"Unsupported surfacetype/colorspace configuration");
goto cleanup_surface;
}
dri2_surf->visual = dri2_image_format_for_pbuffer_config(dri2_dpy, config);
if (dri2_surf->visual == PIPE_FORMAT_NONE)
goto cleanup_surface;
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
goto cleanup_surface;
return &dri2_surf->base;
cleanup_surface:
free(dri2_surf);
return NULL;
}
static EGLBoolean
device_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
device_free_images(dri2_surf);
driDestroyDrawable(dri2_surf->dri_drawable);
dri2_fini_surface(surf);
free(dri2_surf);
return EGL_TRUE;
}
static _EGLSurface *
dri2_device_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
const EGLint *attrib_list)
{
return dri2_device_create_surface(disp, EGL_PBUFFER_BIT, conf, attrib_list);
}
static const struct dri2_egl_display_vtbl dri2_device_display_vtbl = {
.create_pbuffer_surface = dri2_device_create_pbuffer_surface,
.destroy_surface = device_destroy_surface,
.create_image = dri2_create_image_khr,
.get_dri_drawable = dri2_surface_get_dri_drawable,
};
static void
device_flush_front_buffer(struct dri_drawable *driDrawable, void *loaderPrivate)
{
}
static unsigned
device_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
{
/* Note: loaderPrivate is _EGLDisplay* */
switch (cap) {
case DRI_LOADER_CAP_FP16:
return 1;
default:
return 0;
}
}
static const __DRIimageLoaderExtension image_loader_extension = {
.base = {__DRI_IMAGE_LOADER, 2},
.getBuffers = device_image_get_buffers,
.flushFrontBuffer = device_flush_front_buffer,
.getCapability = device_get_capability,
};
static const __DRIextension *image_loader_extensions[] = {
&image_loader_extension.base,
&image_lookup_extension.base,
&kopper_pbuffer_loader_extension.base,
NULL,
};
static const __DRIextension *swrast_loader_extensions[] = {
&swrast_pbuffer_loader_extension.base,
&image_lookup_extension.base,
&kopper_pbuffer_loader_extension.base,
NULL,
};
static int
device_get_fd(_EGLDisplay *disp, _EGLDevice *dev)
{
#ifdef HAVE_LIBDRM
int fd = disp->Options.fd;
bool kms_swrast = disp->Options.ForceSoftware;
/* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
* and invalid one is 0.
*/
if (fd) {
/* According to the spec - if the FD does not match the EGLDevice
* behaviour is undefined.
*
* Add a trivial sanity check since it doesn't cost us anything.
*/
if (dev != _eglFindDevice(fd, false))
return -1;
/* kms_swrast only work with primary node. It used to work with render
* node in the past because some downstream kernel carry a patch to enable
* dumb bo ioctl on render nodes.
*/
char *node = kms_swrast ? drmGetPrimaryDeviceNameFromFd(fd)
: drmGetRenderDeviceNameFromFd(fd);
/* Don't close the internal fd, get render node one based on it. */
fd = loader_open_device(node);
free(node);
return fd;
}
const char *node = _eglQueryDeviceStringEXT(
dev, kms_swrast ? EGL_DRM_DEVICE_FILE_EXT : EGL_DRM_RENDER_NODE_FILE_EXT);
return loader_open_device(node);
#else
_eglLog(_EGL_FATAL,
"Driver bug: Built without libdrm, yet using a HW device");
return -1;
#endif
}
static bool
device_probe_device(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
dri2_dpy->fd_render_gpu = device_get_fd(disp, disp->Device);
if (dri2_dpy->fd_render_gpu < 0)
return false;
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd_render_gpu);
if (!dri2_dpy->driver_name)
goto err_name;
/* this is software fallback */
if (disp->Options.ForceSoftware) {
/* When doing software rendering, some times user still want to explicitly
* choose the render node device since cross node import doesn't work between
* vgem/virtio_gpu yet. It would be nice to have a new EXTENSION for this.
* For now, just fallback to kms_swrast. */
if (strcmp(dri2_dpy->driver_name, "vgem") == 0 ||
strcmp(dri2_dpy->driver_name, "virtio_gpu") == 0) {
free(dri2_dpy->driver_name);
_eglLog(_EGL_WARNING, "NEEDS EXTENSION: falling back to kms_swrast");
dri2_dpy->driver_name = strdup("kms_swrast");
} else if (strcmp(dri2_dpy->driver_name, "vmwgfx")) {
/* this is software fallback; deny progress since a hardware device was requested */
return false;
}
}
dri2_detect_swrast_kopper(disp);
dri2_dpy->loader_extensions = image_loader_extensions;
return true;
err_name:
close(dri2_dpy->fd_render_gpu);
dri2_dpy->fd_render_gpu = dri2_dpy->fd_display_gpu = -1;
return false;
}
static bool
device_probe_device_sw(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
dri2_dpy->fd_render_gpu = -1;
dri2_dpy->fd_display_gpu = -1;
dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast");
if (!dri2_dpy->driver_name)
return false;
/* HACK: should be driver_swrast_null */
dri2_detect_swrast_kopper(disp);
dri2_dpy->loader_extensions = swrast_loader_extensions;
return true;
}
EGLBoolean
dri2_initialize_device(_EGLDisplay *disp)
{
const char *err;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
bool request_software =
debug_get_bool_option("LIBGL_ALWAYS_SOFTWARE", false);
/* Extension requires a PlatformDisplay - the EGLDevice. */
disp->Device = disp->PlatformDisplay;
if (request_software)
_eglLog(_EGL_WARNING, "Not allowed to force software rendering when "
"API explicitly selects a hardware device.");
err = "DRI2: failed to load driver";
/* device-drm platform cannot be explicit sw (because explicit sw is llvmpipe) */
if (!request_software && _eglDeviceSupports(disp->Device, _EGL_DEVICE_DRM)) {
if (!device_probe_device(disp))
goto cleanup;
} else if (request_software || _eglDeviceSupports(disp->Device, _EGL_DEVICE_SOFTWARE)) {
if (!device_probe_device_sw(disp))
goto cleanup;
} else {
_eglLog(_EGL_FATAL,
"Driver bug: exposed device is neither DRM nor SOFTWARE one");
return EGL_FALSE;
}
if (!dri2_create_screen(disp)) {
err = "DRI2: failed to create screen";
goto cleanup;
}
dri2_setup_screen(disp);
#ifdef HAVE_WAYLAND_PLATFORM
dri2_dpy->device_name =
loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
#endif
dri2_set_WL_bind_wayland_display(disp);
dri2_add_pbuffer_configs_for_visuals(disp);
/* Fill vtbl last to prevent accidentally calling virtual function during
* initialization.
*/
dri2_dpy->vtbl = &dri2_device_display_vtbl;
return EGL_TRUE;
cleanup:
return _eglError(EGL_NOT_INITIALIZED, err);
}
+733
View File
@@ -0,0 +1,733 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Kristian Høgsberg <[email protected]>
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <xf86drm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "util/os_file.h"
#include "main/glconfig.h"
#include "egl_dri2.h"
#include "egldevice.h"
#include "eglglobals.h"
#include "loader.h"
#include "dri_util.h"
static struct gbm_bo *
lock_front_buffer(struct gbm_surface *_surf)
{
struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
struct dri2_egl_surface *dri2_surf = surf->dri_private;
struct gbm_dri_device *device = gbm_dri_device(_surf->gbm);
struct gbm_bo *bo;
if (dri2_surf->current == NULL) {
_eglError(EGL_BAD_SURFACE, "no front buffer");
return NULL;
}
bo = dri2_surf->current->bo;
if (!device->swrast) {
dri2_surf->current->locked = true;
dri2_surf->current = NULL;
}
return bo;
}
static void
release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
{
struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
struct dri2_egl_surface *dri2_surf = surf->dri_private;
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (dri2_surf->color_buffers[i].bo == bo) {
dri2_surf->color_buffers[i].locked = false;
break;
}
}
}
static int
has_free_buffers(struct gbm_surface *_surf)
{
struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
struct dri2_egl_surface *dri2_surf = surf->dri_private;
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
if (!dri2_surf->color_buffers[i].locked)
return 1;
return 0;
}
static bool
dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
const struct dri_config *config,
struct gbm_surface *surface)
{
const struct gl_config *gl_config = (struct gl_config *) config;
const struct gbm_dri_visual *visual = NULL;
int i;
/* Check that the EGLConfig being used to render to the surface is
* compatible with the surface format. Since mixing ARGB and XRGB of
* otherwise-compatible formats is relatively common, explicitly allow
* this.
*/
for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
visual = &dri2_dpy->gbm_dri->visual_table[i];
if (visual->gbm_format == surface->v0.format)
break;
}
if (i == dri2_dpy->gbm_dri->num_visuals)
return false;
const struct util_format_description *fmt_c =
util_format_description(gl_config->color_format);
const struct util_format_description *fmt_s =
util_format_description(visual->pipe_format);
if (util_is_format_compatible(fmt_c, fmt_s) ||
util_is_format_compatible(fmt_s, fmt_c))
return true;
return false;
}
static _EGLSurface *
dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_surface, const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct dri2_egl_surface *dri2_surf;
struct gbm_surface *surface = native_surface;
struct gbm_dri_surface *surf;
const struct dri_config *config;
dri2_surf = calloc(1, sizeof *dri2_surf);
if (!dri2_surf) {
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
return NULL;
}
if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
attrib_list, false, native_surface))
goto cleanup_surf;
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
dri2_surf->base.GLColorspace);
if (!config) {
_eglError(EGL_BAD_MATCH,
"Unsupported surfacetype/colorspace configuration");
goto cleanup_surf;
}
if (!dri2_drm_config_is_compatible(dri2_dpy, config, surface)) {
_eglError(EGL_BAD_MATCH, "EGL config not compatible with GBM format");
goto cleanup_surf;
}
surf = gbm_dri_surface(surface);
dri2_surf->gbm_surf = surf;
dri2_surf->base.Width = surf->base.v0.width;
dri2_surf->base.Height = surf->base.v0.height;
surf->dri_private = dri2_surf;
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf))
goto cleanup_surf;
return &dri2_surf->base;
cleanup_surf:
free(dri2_surf);
return NULL;
}
static _EGLSurface *
dri2_drm_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_window, const EGLint *attrib_list)
{
/* From the EGL_MESA_platform_gbm spec, version 5:
*
* It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
* that belongs to the GBM platform. Any such call fails and generates
* EGL_BAD_PARAMETER.
*/
_eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
return NULL;
}
static EGLBoolean
dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
driDestroyDrawable(dri2_surf->dri_drawable);
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (dri2_surf->color_buffers[i].bo)
gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
}
dri2_fini_surface(surf);
free(surf);
return EGL_TRUE;
}
static void
destroy_oldest_unused_bo(struct dri2_egl_surface *dri2_surf)
{
struct dri2_egl_buffer *oldest_buffer = NULL;
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
struct dri2_egl_buffer *buffer = &dri2_surf->color_buffers[i];
if (buffer->locked ||
buffer == dri2_surf->back ||
buffer == dri2_surf->current)
continue;
if (!oldest_buffer || buffer->age > oldest_buffer->age)
oldest_buffer = buffer;
}
gbm_bo_destroy(oldest_buffer->bo);
oldest_buffer->bo = NULL;
oldest_buffer->age = 0;
dri2_surf->excess_bo_frames = 0;
}
static int
get_back_bo(struct dri2_egl_surface *dri2_surf)
{
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
int min_age = 0, max_age = 0;
if (dri2_surf->back == NULL) {
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (!dri2_surf->color_buffers[i].locked) {
int age = dri2_surf->color_buffers[i].age;
if (!min_age || age < min_age)
min_age = age;
if (!max_age || age > max_age) {
dri2_surf->back = &dri2_surf->color_buffers[i];
max_age = age;
}
}
}
if (min_age && min_age < max_age) {
if (++dri2_surf->excess_bo_frames == 1000)
destroy_oldest_unused_bo(dri2_surf);
} else {
dri2_surf->excess_bo_frames = 0;
}
}
if (dri2_surf->back == NULL)
return -1;
if (dri2_surf->back->bo == NULL) {
if (surf->base.v0.modifiers && surf->base.v0.flags)
dri2_surf->back->bo = gbm_bo_create_with_modifiers2(
&dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
surf->base.v0.format, surf->base.v0.modifiers, surf->base.v0.count,
surf->base.v0.flags);
else if (surf->base.v0.modifiers)
dri2_surf->back->bo = gbm_bo_create_with_modifiers(
&dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
surf->base.v0.format, surf->base.v0.modifiers, surf->base.v0.count);
else {
unsigned flags = surf->base.v0.flags;
if (dri2_surf->base.ProtectedContent)
flags |= GBM_BO_USE_PROTECTED;
dri2_surf->back->bo =
gbm_bo_create(&dri2_dpy->gbm_dri->base, surf->base.v0.width,
surf->base.v0.height, surf->base.v0.format, flags);
}
}
if (dri2_surf->back->bo == NULL)
return -1;
return 0;
}
static int
get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
{
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
if (dri2_surf->current == NULL) {
assert(!dri2_surf->color_buffers[0].locked);
dri2_surf->current = &dri2_surf->color_buffers[0];
}
if (dri2_surf->current->bo == NULL)
dri2_surf->current->bo = gbm_bo_create(
&dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
surf->base.v0.format, surf->base.v0.flags);
if (dri2_surf->current->bo == NULL)
return -1;
return 0;
}
static int
dri2_drm_image_get_buffers(struct dri_drawable *driDrawable, unsigned int format,
uint32_t *stamp, void *loaderPrivate,
uint32_t buffer_mask, struct __DRIimageList *buffers)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct gbm_dri_bo *bo;
if (get_back_bo(dri2_surf) < 0)
return 0;
bo = gbm_dri_bo(dri2_surf->back->bo);
buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
buffers->back = bo->image;
return 1;
}
static void
dri2_drm_flush_front_buffer(struct dri_drawable *driDrawable, void *loaderPrivate)
{
(void)driDrawable;
(void)loaderPrivate;
}
static EGLBoolean
dri2_drm_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
if (dri2_dpy->swrast_not_kms) {
driSwapBuffers(dri2_surf->dri_drawable);
return EGL_TRUE;
}
if (dri2_surf->current)
_eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
if (dri2_surf->color_buffers[i].age > 0)
dri2_surf->color_buffers[i].age++;
/* Flushing must be done before get_back_bo to make sure glthread's
* unmarshalling thread is idle otherwise it might concurrently
* call get_back_bo (eg: through dri2_drm_image_get_buffers).
*/
dri2_flush_drawable_for_swapbuffers(disp, draw);
dri_invalidate_drawable(dri2_surf->dri_drawable);
/* Make sure we have a back buffer in case we're swapping without
* ever rendering. */
if (get_back_bo(dri2_surf) < 0)
return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
dri2_surf->current = dri2_surf->back;
dri2_surf->current->age = 1;
dri2_surf->back = NULL;
return EGL_TRUE;
}
static EGLint
dri2_drm_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
{
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
if (get_back_bo(dri2_surf) < 0) {
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
return -1;
}
return dri2_surf->back->age;
}
static _EGLImage *
dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer buffer,
const EGLint *attr_list)
{
struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *)buffer);
struct dri2_egl_image *dri2_img;
dri2_img = malloc(sizeof *dri2_img);
if (!dri2_img) {
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
return NULL;
}
_eglInitImage(&dri2_img->base, disp);
dri2_img->dri_image = dri2_dup_image(dri_bo->image, dri2_img);
if (dri2_img->dri_image == NULL) {
free(dri2_img);
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
return NULL;
}
return &dri2_img->base;
}
static _EGLImage *
dri2_drm_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list)
{
switch (target) {
case EGL_NATIVE_PIXMAP_KHR:
return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
default:
return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
}
}
static int
dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
return drmAuthMagic(dri2_dpy->fd_render_gpu, id);
}
static void
swrast_put_image2(struct dri_drawable *driDrawable, int op, int x, int y, int width,
int height, int stride, char *data, void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
int internal_stride;
struct gbm_dri_bo *bo;
uint32_t bpp;
int x_bytes, width_bytes;
char *src, *dst;
if (op != __DRI_SWRAST_IMAGE_OP_DRAW && op != __DRI_SWRAST_IMAGE_OP_SWAP)
return;
if (get_swrast_front_bo(dri2_surf) < 0)
return;
bo = gbm_dri_bo(dri2_surf->current->bo);
bpp = gbm_bo_get_bpp(&bo->base);
if (bpp == 0)
return;
x_bytes = x * (bpp >> 3);
width_bytes = width * (bpp >> 3);
if (gbm_dri_bo_map_dumb(bo) == NULL)
return;
internal_stride = bo->base.v0.stride;
dst = bo->map + x_bytes + (y * internal_stride);
src = data;
for (int i = 0; i < height; i++) {
memcpy(dst, src, width_bytes);
dst += internal_stride;
src += stride;
}
gbm_dri_bo_unmap_dumb(bo);
}
static void
swrast_get_image(struct dri_drawable *driDrawable, int x, int y, int width,
int height, char *data, void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
int internal_stride, stride;
struct gbm_dri_bo *bo;
uint32_t bpp;
int x_bytes, width_bytes;
char *src, *dst;
if (get_swrast_front_bo(dri2_surf) < 0)
return;
bo = gbm_dri_bo(dri2_surf->current->bo);
bpp = gbm_bo_get_bpp(&bo->base);
if (bpp == 0)
return;
x_bytes = x * (bpp >> 3);
width_bytes = width * (bpp >> 3);
internal_stride = bo->base.v0.stride;
stride = width_bytes;
if (gbm_dri_bo_map_dumb(bo) == NULL)
return;
dst = data;
src = bo->map + x_bytes + (y * internal_stride);
for (int i = 0; i < height; i++) {
memcpy(dst, src, width_bytes);
dst += stride;
src += internal_stride;
}
gbm_dri_bo_unmap_dumb(bo);
}
static void
drm_add_configs_for_visuals(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
const struct gbm_dri_visual *visuals = dri2_dpy->gbm_dri->visual_table;
int num_visuals = dri2_dpy->gbm_dri->num_visuals;
unsigned int format_count[num_visuals];
memset(format_count, 0, num_visuals * sizeof(unsigned int));
for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
const struct dri_config *config = dri2_dpy->driver_configs[i];
struct gl_config *gl_config = (struct gl_config *) config;
for (unsigned j = 0; j < num_visuals; j++) {
struct dri2_egl_config *dri2_conf;
EGLint config_group = 0;
if (visuals[j].pipe_format != gl_config->color_format)
continue;
/* Put the 16 bpc rgb[a] unorm formats into a lower priority EGL config
* group 1, so they don't get preferably chosen by eglChooseConfig().
*/
if (util_format_is_unorm16(util_format_description(visuals[j].pipe_format)))
config_group = 1;
const EGLint attr_list[] = {
EGL_NATIVE_VISUAL_ID,
visuals[j].gbm_format,
EGL_CONFIG_SELECT_GROUP_EXT,
config_group,
EGL_NONE,
};
dri2_conf =
dri2_add_config(disp, dri2_dpy->driver_configs[i], EGL_WINDOW_BIT,
attr_list);
if (dri2_conf)
format_count[j]++;
}
}
for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
if (!format_count[i]) {
struct gbm_format_name_desc desc;
_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
gbm_format_get_name(visuals[i].gbm_format, &desc));
}
}
}
static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
.authenticate = dri2_drm_authenticate,
.create_window_surface = dri2_drm_create_window_surface,
.create_pixmap_surface = dri2_drm_create_pixmap_surface,
.destroy_surface = dri2_drm_destroy_surface,
.create_image = dri2_drm_create_image_khr,
.swap_buffers = dri2_drm_swap_buffers,
.query_buffer_age = dri2_drm_query_buffer_age,
.get_dri_drawable = dri2_surface_get_dri_drawable,
};
static int
get_fd_render_gpu_drm(struct gbm_dri_device *gbm_dri, int fd_display_gpu)
{
/* This doesn't make sense for the software case. */
assert(!gbm_dri->software);
/* Render-capable device, so just return the same fd. */
if (loader_is_device_render_capable(fd_display_gpu))
return fd_display_gpu;
/* Display-only device, so return a compatible render-only device. */
return dri_query_compatible_render_only_device_fd(fd_display_gpu);
}
EGLBoolean
dri2_initialize_drm(_EGLDisplay *disp)
{
struct gbm_device *gbm;
const char *err;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
gbm = disp->PlatformDisplay;
if (gbm == NULL) {
if (disp->Device) {
drmDevicePtr drm = _eglDeviceDrm(disp->Device);
if (!_eglDeviceSupports(disp->Device, _EGL_DEVICE_DRM)) {
err = "DRI2: Device isn't of _EGL_DEVICE_DRM type";
goto cleanup;
}
if (!(drm->available_nodes & (1 << DRM_NODE_PRIMARY))) {
err = "DRI2: Device does not have DRM_NODE_PRIMARY node";
goto cleanup;
}
dri2_dpy->fd_display_gpu =
loader_open_device(drm->nodes[DRM_NODE_PRIMARY]);
} else {
_EGLDevice *dev_list = _eglGlobal.DeviceList;
drmDevicePtr drm;
while (dev_list) {
if (!_eglDeviceSupports(dev_list, _EGL_DEVICE_DRM))
goto next;
drm = _eglDeviceDrm(dev_list);
if (!(drm->available_nodes & (1 << DRM_NODE_PRIMARY)))
goto next;
dri2_dpy->fd_display_gpu =
loader_open_device(drm->nodes[DRM_NODE_PRIMARY]);
if (dri2_dpy->fd_display_gpu < 0)
goto next;
break;
next:
dev_list = _eglDeviceNext(dev_list);
}
}
gbm = gbm_create_device(dri2_dpy->fd_display_gpu);
if (gbm == NULL) {
err = "DRI2: failed to create gbm device";
goto cleanup;
}
dri2_dpy->own_device = true;
} else {
dri2_dpy->fd_display_gpu = os_dupfd_cloexec(gbm_device_get_fd(gbm));
if (dri2_dpy->fd_display_gpu < 0) {
err = "DRI2: failed to fcntl() existing gbm device";
goto cleanup;
}
}
dri2_dpy->gbm_dri = gbm_dri_device(gbm);
if (!dri2_dpy->gbm_dri->software) {
dri2_dpy->fd_render_gpu =
get_fd_render_gpu_drm(dri2_dpy->gbm_dri, dri2_dpy->fd_display_gpu);
if (dri2_dpy->fd_render_gpu < 0) {
err = "DRI2: failed to get compatible render device";
goto cleanup;
}
}
if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
err = "DRI2: gbm device using incorrect/incompatible backend";
goto cleanup;
}
dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
dri2_detect_swrast_kopper(disp);
dri2_dpy->dri_screen_render_gpu = dri2_dpy->gbm_dri->screen;
dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
dri2_dpy->gbm_dri->validate_image = dri2_validate_egl_image;
dri2_dpy->gbm_dri->lookup_image_validated = dri2_lookup_egl_image_validated;
dri2_dpy->gbm_dri->lookup_user_data = disp;
dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
dri2_dpy->gbm_dri->base.v0.surface_lock_front_buffer = lock_front_buffer;
dri2_dpy->gbm_dri->base.v0.surface_release_buffer = release_buffer;
dri2_dpy->gbm_dri->base.v0.surface_has_free_buffers = has_free_buffers;
if (!dri2_setup_device(disp, dri2_dpy->gbm_dri->software)) {
err = "DRI2: failed to setup EGLDevice";
goto cleanup;
}
dri2_setup_screen(disp);
drm_add_configs_for_visuals(disp);
disp->Extensions.KHR_image_pixmap = EGL_TRUE;
disp->Extensions.EXT_buffer_age = EGL_TRUE;
#ifdef HAVE_WAYLAND_PLATFORM
dri2_dpy->device_name =
loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
#endif
dri2_set_WL_bind_wayland_display(disp);
/* Fill vtbl last to prevent accidentally calling virtual function during
* initialization.
*/
dri2_dpy->vtbl = &dri2_drm_display_vtbl;
return EGL_TRUE;
cleanup:
return _eglError(EGL_NOT_INITIALIZED, err);
}
void
dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
{
if (dri2_dpy->own_device)
gbm_device_destroy(&dri2_dpy->gbm_dri->base);
}
+420
View File
@@ -0,0 +1,420 @@
/*
* Mesa 3-D graphics library
*
* Copyright (c) 2014 The Chromium OS Authors.
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pipe/p_screen.h"
#include "util/libdrm.h"
#include <sys/stat.h>
#include <sys/types.h>
#include "egl_dri2.h"
#include "eglglobals.h"
#include "kopper_interface.h"
#include "loader.h"
#include "loader_dri_helper.h"
#include "dri_util.h"
#include "dri_screen.h"
static struct dri_image *
surfaceless_alloc_image(struct dri2_egl_display *dri2_dpy,
struct dri2_egl_surface *dri2_surf)
{
return dri_create_image(
dri2_dpy->dri_screen_render_gpu, dri2_surf->base.Width,
dri2_surf->base.Height, dri2_surf->visual, NULL, 0, 0, NULL);
}
static void
surfaceless_free_images(struct dri2_egl_surface *dri2_surf)
{
if (dri2_surf->front) {
dri2_destroy_image(dri2_surf->front);
dri2_surf->front = NULL;
}
free(dri2_surf->swrast_device_buffer);
dri2_surf->swrast_device_buffer = NULL;
}
static int
surfaceless_image_get_buffers(struct dri_drawable *driDrawable, unsigned int format,
uint32_t *stamp, void *loaderPrivate,
uint32_t buffer_mask,
struct __DRIimageList *buffers)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
buffers->image_mask = 0;
buffers->front = NULL;
buffers->back = NULL;
/* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
* the spec states that they have a back buffer but no front buffer, in
* contrast to pixmaps, which have a front buffer but no back buffer.
*
* Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
* from the spec, following the precedent of Mesa's EGL X11 platform. The
* X11 platform correctly assigns pbuffers to single-buffered configs, but
* assigns the pbuffer a front buffer instead of a back buffer.
*
* Pbuffers in the X11 platform mostly work today, so let's just copy its
* behavior instead of trying to fix (and hence potentially breaking) the
* world.
*/
if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
if (!dri2_surf->front) {
dri2_surf->front = surfaceless_alloc_image(dri2_dpy, dri2_surf);
if (!dri2_surf->front)
return 0;
}
buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
buffers->front = dri2_surf->front;
}
return 1;
}
static _EGLSurface *
dri2_surfaceless_create_surface(_EGLDisplay *disp, EGLint type,
_EGLConfig *conf, const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct dri2_egl_surface *dri2_surf;
const struct dri_config *config;
/* Make sure to calloc so all pointers
* are originally NULL.
*/
dri2_surf = calloc(1, sizeof *dri2_surf);
if (!dri2_surf) {
_eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
return NULL;
}
if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
false, NULL))
goto cleanup_surface;
config = dri2_get_dri_config(dri2_conf, type, dri2_surf->base.GLColorspace);
if (!config) {
_eglError(EGL_BAD_MATCH,
"Unsupported surfacetype/colorspace configuration");
goto cleanup_surface;
}
dri2_surf->visual = dri2_image_format_for_pbuffer_config(dri2_dpy, config);
if (dri2_surf->visual == PIPE_FORMAT_NONE)
goto cleanup_surface;
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
goto cleanup_surface;
return &dri2_surf->base;
cleanup_surface:
free(dri2_surf);
return NULL;
}
static EGLBoolean
surfaceless_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
surfaceless_free_images(dri2_surf);
driDestroyDrawable(dri2_surf->dri_drawable);
dri2_fini_surface(surf);
free(dri2_surf);
return EGL_TRUE;
}
static _EGLSurface *
dri2_surfaceless_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
const EGLint *attrib_list)
{
return dri2_surfaceless_create_surface(disp, EGL_PBUFFER_BIT, conf,
attrib_list);
}
static const struct dri2_egl_display_vtbl dri2_surfaceless_display_vtbl = {
.create_pbuffer_surface = dri2_surfaceless_create_pbuffer_surface,
.destroy_surface = surfaceless_destroy_surface,
.create_image = dri2_create_image_khr,
.get_dri_drawable = dri2_surface_get_dri_drawable,
};
static void
surfaceless_flush_front_buffer(struct dri_drawable *driDrawable, void *loaderPrivate)
{
}
static unsigned
surfaceless_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
{
/* Note: loaderPrivate is _EGLDisplay* */
switch (cap) {
case DRI_LOADER_CAP_FP16:
return 1;
case DRI_LOADER_CAP_RGBA_ORDERING:
return 1;
default:
return 0;
}
}
static const __DRIimageLoaderExtension image_loader_extension = {
.base = {__DRI_IMAGE_LOADER, 2},
.getBuffers = surfaceless_image_get_buffers,
.flushFrontBuffer = surfaceless_flush_front_buffer,
.getCapability = surfaceless_get_capability,
};
static const __DRIextension *image_loader_extensions[] = {
&image_loader_extension.base, &image_lookup_extension.base, NULL,
};
static const __DRIextension *swrast_loader_extensions[] = {
&swrast_pbuffer_loader_extension.base, &image_loader_extension.base,
&image_lookup_extension.base, NULL,
};
static const __DRIextension *kopper_loader_extensions[] = {
&kopper_pbuffer_loader_extension.base, &image_lookup_extension.base,
&image_lookup_extension.base, NULL,
};
static bool
surfaceless_probe_device(_EGLDisplay *disp, bool swrast, bool zink)
{
const unsigned node_type = swrast ? DRM_NODE_PRIMARY : DRM_NODE_RENDER;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
_EGLDevice *dev_list = _eglGlobal.DeviceList;
drmDevicePtr device;
while (dev_list) {
if (!_eglDeviceSupports(dev_list, _EGL_DEVICE_DRM))
goto next;
if (_eglHasAttrib(disp, EGL_DEVICE_EXT) && dev_list != disp->Device) {
goto next;
}
device = _eglDeviceDrm(dev_list);
assert(device);
if (!(device->available_nodes & (1 << node_type)))
goto next;
dri2_dpy->fd_render_gpu = loader_open_device(device->nodes[node_type]);
if (dri2_dpy->fd_render_gpu < 0)
goto next;
#ifdef HAVE_WAYLAND_PLATFORM
loader_get_user_preferred_fd(&dri2_dpy->fd_render_gpu,
&dri2_dpy->fd_display_gpu);
if (dri2_dpy->fd_render_gpu != dri2_dpy->fd_display_gpu) {
free(dri2_dpy->device_name);
dri2_dpy->device_name =
loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
if (!dri2_dpy->device_name) {
_eglError(EGL_BAD_ALLOC, "surfaceless-egl: failed to get device name "
"for requested GPU");
goto retry;
}
}
/* we have to do the check now, because loader_get_user_preferred_fd
* will return a render-node when the requested gpu is different
* to the server, but also if the client asks for the same gpu than
* the server by requesting its pci-id */
dri2_dpy->is_render_node =
drmGetNodeTypeFromFd(dri2_dpy->fd_render_gpu) == DRM_NODE_RENDER;
#endif
char *driver_name = loader_get_driver_for_fd(dri2_dpy->fd_render_gpu);
disp->Device = dev_list;
if (swrast) {
/* Use kms swrast only with vgem / virtio_gpu.
* virtio-gpu fallbacks to software rendering when 3D features
* are unavailable since 6c5ab, and kms_swrast is more
* feature complete than swrast.
*/
if (driver_name && (strcmp(driver_name, "vgem") == 0 ||
strcmp(driver_name, "virtio_gpu") == 0))
dri2_dpy->driver_name = strdup("kms_swrast");
free(driver_name);
} else {
/* Use the given hardware driver */
dri2_dpy->driver_name = driver_name;
}
if (dri2_dpy->driver_name) {
dri2_detect_swrast_kopper(disp);
if (dri2_dpy->kopper)
dri2_dpy->loader_extensions = kopper_loader_extensions;
else if (swrast)
dri2_dpy->loader_extensions = swrast_loader_extensions;
else
dri2_dpy->loader_extensions = image_loader_extensions;
if (!dri2_create_screen(disp)) {
_eglLog(_EGL_WARNING, "DRI2: failed to create screen");
goto retry;
}
if (!dri2_dpy->dri_screen_render_gpu->base.screen->caps.graphics) {
_eglLog(_EGL_DEBUG, "DRI2: Driver %s doesn't support graphics, skipping.", dri2_dpy->driver_name);
if (dri2_dpy->dri_screen_display_gpu != dri2_dpy->dri_screen_render_gpu) {
driDestroyScreen(dri2_dpy->dri_screen_display_gpu);
dri2_dpy->dri_screen_display_gpu = NULL;
}
driDestroyScreen(dri2_dpy->dri_screen_render_gpu);
dri2_dpy->dri_screen_render_gpu = NULL;
dri2_dpy->own_dri_screen = false;
goto retry;
}
break;
}
retry:
free(dri2_dpy->driver_name);
dri2_dpy->driver_name = NULL;
if (dri2_dpy->fd_display_gpu != dri2_dpy->fd_render_gpu)
close(dri2_dpy->fd_display_gpu);
dri2_dpy->fd_display_gpu = -1;
close(dri2_dpy->fd_render_gpu);
dri2_dpy->fd_render_gpu = -1;
next:
dev_list = _eglDeviceNext(dev_list);
}
if (!dev_list)
return false;
return true;
}
static bool
surfaceless_probe_device_sw(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct _egl_device *device = _eglFindDevice(dri2_dpy->fd_render_gpu, true);
dri2_dpy->fd_render_gpu = -1;
if (_eglHasAttrib(disp, EGL_DEVICE_EXT) && disp->Device != device) {
return false;
}
disp->Device = device;
assert(disp->Device);
dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast");
if (!dri2_dpy->driver_name)
return false;
dri2_detect_swrast_kopper(disp);
if (dri2_dpy->kopper)
dri2_dpy->loader_extensions = kopper_loader_extensions;
else
dri2_dpy->loader_extensions = swrast_loader_extensions;
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
if (!dri2_create_screen(disp)) {
_eglLog(_EGL_WARNING, "DRI2: failed to create screen");
free(dri2_dpy->driver_name);
dri2_dpy->driver_name = NULL;
return false;
}
return true;
}
EGLBoolean
dri2_initialize_surfaceless(_EGLDisplay *disp)
{
const char *err;
bool driver_loaded = false;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
/* When ForceSoftware is false, we try the HW driver. When ForceSoftware
* is true, we try kms_swrast and swrast in order.
*/
driver_loaded = surfaceless_probe_device(disp, disp->Options.ForceSoftware,
disp->Options.Zink);
if (!driver_loaded && disp->Options.ForceSoftware) {
_eglLog(_EGL_DEBUG, "Falling back to surfaceless swrast without DRM.");
driver_loaded = surfaceless_probe_device_sw(disp);
}
if (!driver_loaded) {
err = "DRI2: failed to load driver";
goto cleanup;
}
dri2_setup_screen(disp);
#ifdef HAVE_WAYLAND_PLATFORM
dri2_dpy->device_name =
loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
#endif
dri2_set_WL_bind_wayland_display(disp);
dri2_add_pbuffer_configs_for_visuals(disp);
/* Fill vtbl last to prevent accidentally calling virtual function during
* initialization.
*/
dri2_dpy->vtbl = &dri2_surfaceless_display_vtbl;
return EGL_TRUE;
cleanup:
return _eglError(EGL_NOT_INITIALIZED, err);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright 2022 Yonggang Luo
* SPDX-License-Identifier: MIT
*
*/
#ifndef EGL_X11_INCLUDED
#define EGL_X11_INCLUDED
#include "egl_dri2.h"
uint32_t
dri2_fourcc_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth);
EGLBoolean
dri2_x11_get_msc_rate(_EGLDisplay *display, _EGLSurface *surface,
EGLint *numerator, EGLint *denominator);
#endif
+565
View File
@@ -0,0 +1,565 @@
/*
* Copyright © 2015 Boyan Ding
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <xcb/dri3.h>
#include <xcb/present.h>
#include <xcb/xcb.h>
#if defined(HAVE_WAYLAND_PLATFORM)
#include "util/libdrm.h"
#endif
#include "drm-uapi/drm_fourcc.h"
#include "util/macros.h"
#include "egl_dri2.h"
#include "platform_x11_dri3.h"
#include "loader.h"
#include "x11_dri3.h"
#include "loader_dri3_helper.h"
static struct dri3_egl_surface *
loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw)
{
size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
return (struct dri3_egl_surface *)(((void *)draw) - offset);
}
static void
egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw, int width,
int height)
{
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
dri3_surf->surf.base.Width = width;
dri3_surf->surf.base.Height = height;
}
static bool
egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
{
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
_EGLContext *ctx = _eglGetCurrentContext();
return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
}
static struct dri_context *
egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
{
_EGLContext *ctx = _eglGetCurrentContext();
struct dri2_egl_context *dri2_ctx;
if (!ctx)
return NULL;
dri2_ctx = dri2_egl_context(ctx);
return dri2_ctx->dri_context;
}
static struct dri_screen *
egl_dri3_get_dri_screen(void)
{
_EGLContext *ctx = _eglGetCurrentContext();
struct dri2_egl_context *dri2_ctx;
if (!ctx)
return NULL;
dri2_ctx = dri2_egl_context(ctx);
return dri2_egl_display(dri2_ctx->base.Resource.Display)
->dri_screen_render_gpu;
}
static void
egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
{
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
_EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
}
static const struct loader_dri3_vtable egl_dri3_vtable = {
.set_drawable_size = egl_dri3_set_drawable_size,
.in_current_context = egl_dri3_in_current_context,
.get_dri_context = egl_dri3_get_dri_context,
.get_dri_screen = egl_dri3_get_dri_screen,
.flush_drawable = egl_dri3_flush_drawable,
};
static EGLBoolean
dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
if (surf->Type == EGL_PBUFFER_BIT)
xcb_free_pixmap(dri2_dpy->conn, drawable);
dri2_fini_surface(surf);
free(surf);
return EGL_TRUE;
}
static EGLBoolean
dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
dri3_surf->surf.base.SwapInterval = interval;
loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
return EGL_TRUE;
}
static enum loader_dri3_drawable_type
egl_to_loader_dri3_drawable_type(EGLint type)
{
switch (type) {
case EGL_WINDOW_BIT:
return LOADER_DRI3_DRAWABLE_WINDOW;
case EGL_PIXMAP_BIT:
return LOADER_DRI3_DRAWABLE_PIXMAP;
case EGL_PBUFFER_BIT:
return LOADER_DRI3_DRAWABLE_PBUFFER;
default:
return LOADER_DRI3_DRAWABLE_UNKNOWN;
}
}
static _EGLSurface *
dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
void *native_surface, const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct dri3_egl_surface *dri3_surf;
const struct dri_config *dri_config;
xcb_drawable_t drawable;
dri3_surf = calloc(1, sizeof *dri3_surf);
if (!dri3_surf) {
_eglError(EGL_BAD_ALLOC, "dri3_create_surface");
return NULL;
}
if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list,
false, native_surface))
goto cleanup_surf;
if (type == EGL_PBUFFER_BIT) {
drawable = xcb_generate_id(dri2_dpy->conn);
xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, drawable,
dri2_dpy->screen->root, dri3_surf->surf.base.Width,
dri3_surf->surf.base.Height);
} else {
STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
drawable = (uintptr_t)native_surface;
}
dri_config =
dri2_get_dri_config(dri2_conf, type, dri3_surf->surf.base.GLColorspace);
if (!dri_config) {
_eglError(EGL_BAD_MATCH,
"Unsupported surfacetype/colorspace configuration");
goto cleanup_pixmap;
}
if (loader_dri3_drawable_init(
dri2_dpy->conn, drawable, egl_to_loader_dri3_drawable_type(type),
dri2_dpy->dri_screen_render_gpu, dri2_dpy->dri_screen_display_gpu,
dri2_dpy->multibuffers_available, true, dri_config,
&egl_dri3_vtable,
&dri3_surf->loader_drawable)) {
_eglError(EGL_BAD_ALLOC, "dri3_surface_create");
goto cleanup_pixmap;
}
if (dri3_surf->surf.base.ProtectedContent &&
dri2_dpy->fd_render_gpu != dri2_dpy->fd_display_gpu) {
_eglError(EGL_BAD_ALLOC, "dri3_surface_create");
goto cleanup_pixmap;
}
dri3_surf->loader_drawable.is_protected_content =
dri3_surf->surf.base.ProtectedContent;
return &dri3_surf->surf.base;
cleanup_pixmap:
if (type == EGL_PBUFFER_BIT)
xcb_free_pixmap(dri2_dpy->conn, drawable);
cleanup_surf:
free(dri3_surf);
return NULL;
}
static int
dri3_authenticate(_EGLDisplay *disp, uint32_t id)
{
#ifdef HAVE_WAYLAND_PLATFORM
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
if (!dri2_dpy->swrast) {
_eglLog(_EGL_WARNING,
"Wayland client render node authentication is unnecessary");
return 0;
}
_eglLog(_EGL_WARNING,
"Wayland client primary node authentication isn't supported");
#endif
return -1;
}
/**
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
*/
static _EGLSurface *
dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_window, const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
_EGLSurface *surf;
surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf, native_window,
attrib_list);
if (surf != NULL)
dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
return surf;
}
static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_pixmap, const EGLint *attrib_list)
{
return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf, native_pixmap,
attrib_list);
}
static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
const EGLint *attrib_list)
{
return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf, NULL, attrib_list);
}
static EGLBoolean
dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
(int64_t *)ust, (int64_t *)msc,
(int64_t *)sbc)
? EGL_TRUE
: EGL_FALSE;
}
static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer buffer, const EGLint *attr_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img;
xcb_drawable_t drawable;
xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
unsigned int fourcc;
drawable = (xcb_drawable_t)(uintptr_t)buffer;
bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
bp_reply =
xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn, bp_cookie, NULL);
if (!bp_reply) {
_eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
return NULL;
}
fourcc = dri2_fourcc_for_depth(dri2_dpy, bp_reply->depth);
if (fourcc == DRM_FORMAT_INVALID) {
_eglError(EGL_BAD_PARAMETER,
"dri3_create_image_khr: unsupported pixmap depth");
free(bp_reply);
return EGL_NO_IMAGE_KHR;
}
dri2_img = malloc(sizeof *dri2_img);
if (!dri2_img) {
_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
free(bp_reply);
return EGL_NO_IMAGE_KHR;
}
_eglInitImage(&dri2_img->base, disp);
dri2_img->dri_image = loader_dri3_create_image(
dri2_dpy->conn, bp_reply, fourcc, dri2_dpy->dri_screen_render_gpu,
dri2_img);
free(bp_reply);
return &dri2_img->base;
}
static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer buffer,
const EGLint *attr_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img;
xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
xcb_drawable_t drawable;
unsigned int fourcc;
drawable = (xcb_drawable_t)(uintptr_t)buffer;
bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
bp_reply =
xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn, bp_cookie, NULL);
if (!bp_reply) {
_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
return EGL_NO_IMAGE_KHR;
}
fourcc = dri2_fourcc_for_depth(dri2_dpy, bp_reply->depth);
if (fourcc == DRM_FORMAT_INVALID) {
_eglError(EGL_BAD_PARAMETER,
"dri3_create_image_khr: unsupported pixmap depth");
free(bp_reply);
return EGL_NO_IMAGE_KHR;
}
dri2_img = malloc(sizeof *dri2_img);
if (!dri2_img) {
_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
free(bp_reply);
return EGL_NO_IMAGE_KHR;
}
_eglInitImage(&dri2_img->base, disp);
dri2_img->dri_image = loader_dri3_create_image_from_buffers(
dri2_dpy->conn, bp_reply, fourcc, dri2_dpy->dri_screen_render_gpu,
dri2_img);
free(bp_reply);
if (!dri2_img->dri_image) {
_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
free(dri2_img);
return EGL_NO_IMAGE_KHR;
}
return &dri2_img->base;
}
static _EGLImage *
dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
switch (target) {
case EGL_NATIVE_PIXMAP_KHR:
if (dri2_dpy->multibuffers_available)
return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
attr_list);
return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
default:
return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
}
}
/**
* Called by the driver when it needs to update the real front buffer with the
* contents of its fake front buffer.
*/
static void
dri3_flush_front_buffer(struct dri_drawable *driDrawable, void *loaderPrivate)
{
struct loader_dri3_drawable *draw = loaderPrivate;
(void)driDrawable;
/* There does not seem to be any kind of consensus on whether we should
* support front-buffer rendering or not:
* http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
*/
if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW)
_eglLog(_EGL_WARNING,
"FIXME: egl/x11 doesn't support front buffer rendering.");
}
const __DRIimageLoaderExtension dri3_image_loader_extension = {
.base = {__DRI_IMAGE_LOADER, 1},
.getBuffers = loader_dri3_get_buffers,
.flushFrontBuffer = dri3_flush_front_buffer,
};
static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
const EGLint *rects, EGLint n_rects)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
return loader_dri3_swap_buffers_msc(
&dri3_surf->loader_drawable, 0, 0, 0, 0, rects, n_rects,
draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
}
static EGLBoolean
dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
{
return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
}
static EGLBoolean
dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf,
void *native_pixmap_target)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
xcb_pixmap_t target;
STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
target = (uintptr_t)native_pixmap_target;
loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
dri3_surf->loader_drawable.drawable);
return EGL_TRUE;
}
static int
dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
}
static EGLBoolean
dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute,
EGLint *value)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
switch (attribute) {
case EGL_WIDTH:
case EGL_HEIGHT:
loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
break;
default:
break;
}
return _eglQuerySurface(disp, surf, attribute, value);
}
static struct dri_drawable *
dri3_get_dri_drawable(_EGLSurface *surf)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
return dri3_surf->loader_drawable.dri_drawable;
}
static void
dri3_close_screen_notify(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
loader_dri3_close_screen(dri2_dpy->dri_screen_render_gpu);
}
struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
.authenticate = dri3_authenticate,
.create_window_surface = dri3_create_window_surface,
.create_pixmap_surface = dri3_create_pixmap_surface,
.create_pbuffer_surface = dri3_create_pbuffer_surface,
.destroy_surface = dri3_destroy_surface,
.create_image = dri3_create_image_khr,
.swap_interval = dri3_set_swap_interval,
.swap_buffers = dri3_swap_buffers,
.swap_buffers_with_damage = dri3_swap_buffers_with_damage,
.copy_buffers = dri3_copy_buffers,
.query_buffer_age = dri3_query_buffer_age,
.query_surface = dri3_query_surface,
.get_sync_values = dri3_get_sync_values,
.get_msc_rate = dri2_x11_get_msc_rate,
.get_dri_drawable = dri3_get_dri_drawable,
.close_screen_notify = dri3_close_screen_notify,
};
bool
dri3_x11_connect(struct dri2_egl_display *dri2_dpy, bool swrast)
{
dri2_dpy->fd_render_gpu =
x11_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
if (dri2_dpy->fd_render_gpu < 0) {
int conn_error = xcb_connection_has_error(dri2_dpy->conn);
if (!swrast) {
_eglLog(_EGL_WARNING, "DRI3 error: Could not get DRI3 device");
_eglLog(_EGL_WARNING, "Ensure your X server supports DRI3 to get accelerated rendering");
if (conn_error)
_eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
}
return false;
}
loader_get_user_preferred_fd(&dri2_dpy->fd_render_gpu,
&dri2_dpy->fd_display_gpu);
if (!dri2_dpy->driver_name)
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd_render_gpu);
if (!dri2_dpy->driver_name) {
_eglLog(_EGL_WARNING, "DRI3: No driver found");
close(dri2_dpy->fd_render_gpu);
dri2_dpy->fd_render_gpu = -1;
return false;
}
#ifdef HAVE_WAYLAND_PLATFORM
/* Only try to get a render device name since dri3 doesn't provide a
* mechanism for authenticating client opened device node fds. If this
* fails then don't advertise the extension. */
dri2_dpy->device_name =
drmGetRenderDeviceNameFromFd(dri2_dpy->fd_render_gpu);
#endif
return true;
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright © 2015 Boyan Ding
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef EGL_X11_DRI3_INCLUDED
#define EGL_X11_DRI3_INCLUDED
#include "platform_x11.h"
#if !defined(HAVE_LIBDRM)
#include "loader_dri3_helper.h"
#endif
_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)
struct dri3_egl_surface {
struct dri2_egl_surface surf;
struct loader_dri3_drawable loader_drawable;
};
extern const __DRIimageLoaderExtension dri3_image_loader_extension;
extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;
bool
dri3_x11_connect(struct dri2_egl_display *dri2_dpy, bool swrast);
#endif
+7
View File
@@ -0,0 +1,7 @@
[*.cpp]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
+523
View File
@@ -0,0 +1,523 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 2014 Adrián Arroyo Calle <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <dlfcn.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
#include "eglconfig.h"
#include "eglcontext.h"
#include "eglcurrent.h"
#include "egldevice.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "eglimage.h"
#include "egllog.h"
#include "eglsurface.h"
#include "egltypedefs.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "state_tracker/st_context.h"
#include "util/u_atomic.h"
#include "mesa/glapi/glapi/glapi.h"
#include "hgl/hgl_sw_winsys.h"
#include "hgl_context.h"
#include <Bitmap.h>
extern "C" {
#include "target-helpers/inline_sw_helper.h"
}
#if MESA_DEBUG
#define TRACE(x...) printf("egl_haiku: " x)
#define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
#else
#define TRACE(x...)
#define CALLED()
#endif
#define ERROR(x...) printf("egl_haiku: " x)
_EGL_DRIVER_STANDARD_TYPECASTS(haiku_egl)
struct haiku_egl_display {
int ref_count;
struct hgl_display *disp;
};
struct haiku_egl_config {
_EGLConfig base;
};
struct haiku_egl_context {
_EGLContext base;
struct hgl_context *ctx;
};
struct haiku_egl_surface {
_EGLSurface base;
struct hgl_buffer *fb;
struct pipe_fence_handle *throttle_fence;
};
// #pragma mark EGLSurface
// Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
static _EGLSurface *
haiku_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_window, const EGLint *attrib_list)
{
printf("haiku_create_window_surface\n");
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
struct haiku_egl_surface *wgl_surf =
(struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
if (!wgl_surf)
return NULL;
if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf,
attrib_list, NULL)) {
free(wgl_surf);
return NULL;
}
struct st_visual visual;
hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
wgl_surf->fb =
hgl_create_st_framebuffer(hgl_dpy->disp, &visual, native_window);
if (!wgl_surf->fb) {
free(wgl_surf);
return NULL;
}
// Unset and delete previously set bitmap if any.
delete ((BitmapHook *)native_window)->SetBitmap(NULL);
return &wgl_surf->base;
}
static _EGLSurface *
haiku_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
void *native_pixmap, const EGLint *attrib_list)
{
printf("haiku_create_pixmap_surface\n");
return NULL;
}
static _EGLSurface *
haiku_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
const EGLint *attrib_list)
{
printf("haiku_create_pbuffer_surface\n");
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
struct haiku_egl_surface *wgl_surf =
(struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
if (!wgl_surf)
return NULL;
if (!_eglInitSurface(&wgl_surf->base, disp, EGL_PBUFFER_BIT, conf,
attrib_list, NULL)) {
free(wgl_surf);
return NULL;
}
struct st_visual visual;
hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
wgl_surf->fb = hgl_create_st_framebuffer(hgl_dpy->disp, &visual, NULL);
if (!wgl_surf->fb) {
free(wgl_surf);
return NULL;
}
wgl_surf->fb->newWidth = wgl_surf->base.Width;
wgl_surf->fb->newHeight = wgl_surf->base.Height;
p_atomic_inc(&wgl_surf->fb->base.stamp);
return &wgl_surf->base;
}
static EGLBoolean
haiku_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
if (_eglPutSurface(surf)) {
struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
// Unset bitmap to release ownership. Bitmap will be deleted later
// when destroying framebuffer.
BitmapHook *bitmapHook = (BitmapHook*)hgl_surf->fb->winsysContext;
if (bitmapHook != NULL)
bitmapHook->SetBitmap(NULL);
hgl_destroy_st_framebuffer(hgl_surf->fb);
free(surf);
}
return EGL_TRUE;
}
static void
update_size(struct hgl_buffer *buffer)
{
uint32_t newWidth, newHeight;
((BitmapHook *)buffer->winsysContext)->GetSize(newWidth, newHeight);
if (buffer->newWidth != newWidth || buffer->newHeight != newHeight) {
buffer->newWidth = newWidth;
buffer->newHeight = newHeight;
p_atomic_inc(&buffer->base.stamp);
}
}
static EGLBoolean
haiku_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf)
{
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
struct haiku_egl_context *hgl_ctx = haiku_egl_context(surf->CurrentContext);
if (hgl_ctx == NULL)
return EGL_FALSE;
struct st_context *st = hgl_ctx->ctx->st;
struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
struct hgl_buffer *buffer = hgl_surf->fb;
auto &frontBuffer = buffer->textures[ST_ATTACHMENT_FRONT_LEFT];
auto &backBuffer = buffer->textures[ST_ATTACHMENT_BACK_LEFT];
// Inform ST of a flush if double buffering is used
if (backBuffer != NULL)
st->pipe->flush_resource(st->pipe, backBuffer);
_mesa_glthread_finish(st->ctx);
struct pipe_fence_handle *new_fence = NULL;
st_context_flush(st, ST_FLUSH_FRONT, &new_fence, NULL, NULL);
if (hgl_surf->throttle_fence) {
screen->fence_finish(screen, NULL, hgl_surf->throttle_fence,
OS_TIMEOUT_INFINITE);
screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
}
hgl_surf->throttle_fence = new_fence;
// flush back buffer and swap buffers if double buffering is used
if (backBuffer != NULL) {
screen->flush_frontbuffer(screen, st->pipe, backBuffer, 0, 0,
buffer->winsysContext, 1, NULL);
std::swap(frontBuffer, backBuffer);
p_atomic_inc(&buffer->base.stamp);
}
// XXX: right front / back if HGL_STEREO?
update_size(buffer);
st_context_invalidate_state(st, ST_INVALIDATE_FB_STATE);
return EGL_TRUE;
}
// #pragma mark EGLDisplay
static EGLBoolean
haiku_add_configs_for_visuals(_EGLDisplay *disp)
{
CALLED();
struct haiku_egl_config *conf;
conf = (struct haiku_egl_config *)calloc(1, sizeof(*conf));
if (!conf)
return _eglError(EGL_BAD_ALLOC, "haiku_add_configs_for_visuals");
_eglInitConfig(&conf->base, disp, 1);
TRACE("Config inited\n");
conf->base.RedSize = 8;
conf->base.BlueSize = 8;
conf->base.GreenSize = 8;
conf->base.LuminanceSize = 0;
conf->base.AlphaSize = 8;
conf->base.ColorBufferType = EGL_RGB_BUFFER;
conf->base.BufferSize = conf->base.RedSize + conf->base.GreenSize +
conf->base.BlueSize + conf->base.AlphaSize;
conf->base.ConfigCaveat = EGL_NONE;
conf->base.ConfigID = 1;
conf->base.BindToTextureRGB = EGL_FALSE;
conf->base.BindToTextureRGBA = EGL_FALSE;
conf->base.StencilSize = 0;
conf->base.TransparentType = EGL_NONE;
conf->base.NativeRenderable = EGL_TRUE; // Let's say yes
conf->base.NativeVisualID = 0; // No visual
conf->base.NativeVisualType = EGL_NONE; // No visual
conf->base.RenderableType = 0x8;
conf->base.SampleBuffers = 0; // TODO: How to get the right value ?
conf->base.Samples = conf->base.SampleBuffers == 0 ? 0 : 0;
conf->base.DepthSize = 24; // TODO: How to get the right value ?
conf->base.Level = 0;
conf->base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
conf->base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
conf->base.MaxPbufferPixels = 0; // TODO: How to get the right value ?
conf->base.SurfaceType = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT;
TRACE("Config configuated\n");
if (!_eglValidateConfig(&conf->base, EGL_FALSE)) {
_eglLog(_EGL_DEBUG, "Haiku: failed to validate config");
goto cleanup;
}
TRACE("Validated config\n");
_eglLinkConfig(&conf->base);
if (!_eglGetArraySize(disp->Configs)) {
_eglLog(_EGL_WARNING, "Haiku: failed to create any config");
goto cleanup;
}
TRACE("Config successful\n");
return EGL_TRUE;
cleanup:
free(conf);
return EGL_FALSE;
}
static void
haiku_display_destroy(_EGLDisplay *disp)
{
if (!disp)
return;
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
assert(hgl_dpy->ref_count > 0);
if (!p_atomic_dec_zero(&hgl_dpy->ref_count))
return;
struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
hgl_destroy_display(hgl_dpy->disp);
hgl_dpy->disp = NULL;
screen->destroy(screen); // destroy will deallocate object
free(hgl_dpy);
}
static EGLBoolean
haiku_initialize_impl(_EGLDisplay *disp, void *platformDisplay)
{
struct haiku_egl_display *hgl_dpy;
hgl_dpy =
(struct haiku_egl_display *)calloc(1, sizeof(struct haiku_egl_display));
if (!hgl_dpy)
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
hgl_dpy->ref_count = 1;
disp->DriverData = (void *)hgl_dpy;
struct sw_winsys *winsys = hgl_create_sw_winsys();
struct pipe_screen *screen = sw_screen_create(winsys);
hgl_dpy->disp = hgl_create_display(screen);
disp->ClientAPIs = 0;
if (_eglIsApiValid(EGL_OPENGL_API))
disp->ClientAPIs |= EGL_OPENGL_BIT;
if (_eglIsApiValid(EGL_OPENGL_ES_API))
disp->ClientAPIs |=
EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
disp->Extensions.KHR_no_config_context = EGL_TRUE;
disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
disp->Extensions.MESA_query_driver = EGL_TRUE;
/* Report back to EGL the bitmask of priorities supported */
disp->Extensions.IMG_context_priority =
hgl_dpy->disp->fscreen->screen->caps.context_priority_mask;
disp->Extensions.NV_context_priority_realtime =
disp->Extensions.IMG_context_priority &
(1 << __EGL_CONTEXT_PRIORITY_REALTIME_BIT);
disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
if (hgl_dpy->disp->fscreen->screen->is_format_supported(
hgl_dpy->disp->fscreen->screen, PIPE_FORMAT_B8G8R8A8_SRGB,
PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_RENDER_TARGET))
disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
disp->Extensions.KHR_create_context = EGL_TRUE;
disp->Extensions.KHR_reusable_sync = EGL_TRUE;
haiku_add_configs_for_visuals(disp);
return EGL_TRUE;
}
static EGLBoolean
haiku_initialize(_EGLDisplay *disp)
{
EGLBoolean ret = EGL_FALSE;
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
if (hgl_dpy) {
hgl_dpy->ref_count++;
return EGL_TRUE;
}
switch (disp->Platform) {
case _EGL_PLATFORM_SURFACELESS:
case _EGL_PLATFORM_HAIKU:
ret = haiku_initialize_impl(disp, NULL);
break;
case _EGL_PLATFORM_DEVICE:
ret = haiku_initialize_impl(disp, disp->PlatformDisplay);
break;
default:
UNREACHABLE("Callers ensure we cannot get here.");
return EGL_FALSE;
}
if (!ret)
return EGL_FALSE;
hgl_dpy = haiku_egl_display(disp);
return EGL_TRUE;
}
static EGLBoolean
haiku_terminate(_EGLDisplay *disp)
{
haiku_display_destroy(disp);
return EGL_TRUE;
}
// #pragma mark EGLContext
static _EGLContext *
haiku_create_context(_EGLDisplay *disp, _EGLConfig *conf,
_EGLContext *share_list, const EGLint *attrib_list)
{
CALLED();
struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
struct st_visual visual;
hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
struct haiku_egl_context *context =
(struct haiku_egl_context *)calloc(1, sizeof(*context));
if (!context) {
_eglError(EGL_BAD_ALLOC, "haiku_create_context");
return NULL;
}
if (!_eglInitContext(&context->base, disp, conf, share_list, attrib_list))
goto cleanup;
context->ctx = hgl_create_context(
hgl_dpy->disp, &visual,
share_list == NULL ? NULL : haiku_egl_context(share_list)->ctx->st);
if (context->ctx == NULL)
goto cleanup;
return &context->base;
cleanup:
free(context);
return NULL;
}
static EGLBoolean
haiku_destroy_context(_EGLDisplay *disp, _EGLContext *ctx)
{
if (_eglPutContext(ctx)) {
struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
hgl_destroy_context(hgl_ctx->ctx);
free(ctx);
ctx = NULL;
}
return EGL_TRUE;
}
static EGLBoolean
haiku_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, _EGLSurface *rsurf,
_EGLContext *ctx)
{
CALLED();
struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
struct haiku_egl_surface *hgl_dsurf = haiku_egl_surface(dsurf);
struct haiku_egl_surface *hgl_rsurf = haiku_egl_surface(rsurf);
_EGLContext *old_ctx;
_EGLSurface *old_dsurf, *old_rsurf;
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
return EGL_FALSE;
if (old_ctx == ctx && old_dsurf == dsurf && old_rsurf == rsurf) {
_eglPutSurface(old_dsurf);
_eglPutSurface(old_rsurf);
_eglPutContext(old_ctx);
return EGL_TRUE;
}
if (ctx == NULL) {
st_api_make_current(NULL, NULL, NULL);
} else {
if (dsurf != NULL && dsurf != old_dsurf)
update_size(hgl_dsurf->fb);
st_api_make_current(hgl_ctx->ctx->st,
hgl_dsurf == NULL ? NULL : &hgl_dsurf->fb->base,
hgl_rsurf == NULL ? NULL : &hgl_rsurf->fb->base);
}
if (old_dsurf != NULL)
haiku_destroy_surface(disp, old_dsurf);
if (old_rsurf != NULL)
haiku_destroy_surface(disp, old_rsurf);
if (old_ctx != NULL)
haiku_destroy_context(disp, old_ctx);
return EGL_TRUE;
}
extern "C" const _EGLDriver _eglDriver = {
.Initialize = haiku_initialize,
.Terminate = haiku_terminate,
.CreateContext = haiku_create_context,
.DestroyContext = haiku_destroy_context,
.MakeCurrent = haiku_make_current,
.CreateWindowSurface = haiku_create_window_surface,
.CreatePixmapSurface = haiku_create_pixmap_surface,
.CreatePbufferSurface = haiku_create_pbuffer_surface,
.DestroySurface = haiku_destroy_surface,
.SwapBuffers = haiku_swap_buffers,
};
File diff suppressed because it is too large. Load diff
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <eglconfig.h>
#include <egldisplay.h>
#include <egldriver.h>
#include <eglimage.h>
#include <eglsync.h>
#include <windows.h>
#include <stw_pixelformat.h>
struct wgl_egl_display {
struct pipe_frontend_screen base;
_EGLDisplay *parent;
int ref_count;
struct pipe_screen *screen;
};
struct wgl_egl_config {
_EGLConfig base;
const struct stw_pixelformat_info *stw_config[2];
};
struct wgl_egl_context {
_EGLContext base;
struct stw_context *ctx;
};
struct wgl_egl_surface {
_EGLSurface base;
struct stw_framebuffer *fb;
};
struct wgl_egl_image {
_EGLImage base;
struct stw_image *img;
};
struct wgl_egl_sync {
_EGLSync base;
int refcount;
struct pipe_fence_handle *fence;
HANDLE event;
};
_EGL_DRIVER_STANDARD_TYPECASTS(wgl_egl)
_EGL_DRIVER_TYPECAST(wgl_egl_image, _EGLImage, obj)
_EGL_DRIVER_TYPECAST(wgl_egl_sync, _EGLSync, obj)
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
import argparse
from generate.eglFunctionList import EGL_FUNCTIONS as GLVND_ENTRYPOINTS
PREFIX1 = 'EGL_ENTRYPOINT('
PREFIX2 = 'EGL_ENTRYPOINT2('
SUFFIX = ')'
# These entrypoints should *not* be in the GLVND entrypoints
GLVND_EXCLUDED_ENTRYPOINTS = [
# EGL_KHR_debug
'eglDebugMessageControlKHR',
'eglQueryDebugKHR',
'eglLabelObjectKHR',
]
def check_entrypoint_sorted(entrypoints):
print('Checking that EGL API entrypoints are sorted...')
for i, _ in enumerate(entrypoints):
# Can't compare the first one with the previous
if i == 0:
continue
if entrypoints[i - 1] > entrypoints[i]:
print('ERROR: ' + entrypoints[i] +
' should come before ' + entrypoints[i - 1])
exit(1)
print('All good :)')
def check_glvnd_entrypoints(egl_entrypoints, glvnd_entrypoints):
print('Checking the GLVND entrypoints against the plain EGL ones...')
success = True
for egl_entrypoint in egl_entrypoints:
if egl_entrypoint in GLVND_EXCLUDED_ENTRYPOINTS:
continue
if egl_entrypoint not in glvnd_entrypoints:
print('ERROR: ' + egl_entrypoint +
' is missing from the GLVND entrypoints (src/egl/generate/eglFunctionList.py)')
success = False
for glvnd_entrypoint in glvnd_entrypoints:
if glvnd_entrypoint not in egl_entrypoints:
print('ERROR: ' + glvnd_entrypoint +
' is missing from the plain EGL entrypoints (src/egl/main/eglentrypoint.h)')
success = False
for glvnd_entrypoint in GLVND_EXCLUDED_ENTRYPOINTS:
if glvnd_entrypoint in glvnd_entrypoints:
print('ERROR: ' + glvnd_entrypoint +
' is should *not* be in the GLVND entrypoints (src/egl/generate/eglFunctionList.py)')
success = False
if success:
print('All good :)')
else:
exit(1)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('header')
args = parser.parse_args()
with open(args.header) as header:
lines = header.readlines()
entrypoints = []
for line in lines:
line = line.strip()
if line.startswith(PREFIX1):
assert line.endswith(SUFFIX)
entrypoints.append(line[len(PREFIX1):-len(SUFFIX)])
if line.startswith(PREFIX2):
assert line.endswith(SUFFIX)
entrypoint = line[len(PREFIX2):-len(SUFFIX)]
entrypoint = entrypoint.split(',')[0].strip()
entrypoints.append(entrypoint)
check_entrypoint_sorted(entrypoints)
glvnd_entrypoints = [x[0] for x in GLVND_ENTRYPOINTS]
check_glvnd_entrypoints(entrypoints, glvnd_entrypoints)
if __name__ == '__main__':
main()
+4
View File
@@ -0,0 +1,4 @@
__egl_Main
MesaGLInteropEGLQueryDeviceInfo
MesaGLInteropEGLExportObject
MesaGLInteropEGLFlushObjects
+9
View File
@@ -0,0 +1,9 @@
{
global:
__egl_Main;
MesaGLInteropEGLQueryDeviceInfo;
MesaGLInteropEGLExportObject;
MesaGLInteropEGLFlushObjects;
local:
*;
};
+47
View File
@@ -0,0 +1,47 @@
eglBindAPI
eglBindTexImage
eglChooseConfig
eglClientWaitSync
eglCopyBuffers
eglCreateContext
eglCreateImage
eglCreatePbufferFromClientBuffer
eglCreatePbufferSurface
eglCreatePixmapSurface
eglCreatePlatformPixmapSurface
eglCreatePlatformWindowSurface
eglCreateSync
eglCreateWindowSurface
eglDestroyContext
eglDestroyImage
eglDestroySurface
eglDestroySync
eglGetConfigAttrib
eglGetConfigs
eglGetCurrentContext
eglGetCurrentDisplay
eglGetCurrentSurface
eglGetDisplay
eglGetError
eglGetPlatformDisplay
eglGetProcAddress
eglGetSyncAttrib
eglInitialize
eglMakeCurrent
eglQueryAPI
eglQueryContext
eglQueryString
eglQuerySurface
eglReleaseTexImage
eglReleaseThread
eglSurfaceAttrib
eglSwapBuffers
eglSwapInterval
eglTerminate
eglWaitClient
eglWaitGL
eglWaitNative
eglWaitSync
MesaGLInteropEGLQueryDeviceInfo
MesaGLInteropEGLExportObject
MesaGLInteropEGLFlushObjects
+7
View File
@@ -0,0 +1,7 @@
{
global:
egl*;
MesaGLInteropEGL*;
local:
*;
};
File diff suppressed because it is too large. Load diff
+247
View File
@@ -0,0 +1,247 @@
# (C) Copyright 2016, NVIDIA CORPORATION.
# All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Authors:
# Kyle Brenneman <[email protected]>
"""
Contains a list of EGL functions to generate dispatch functions for.
This is used from gen_egl_dispatch.py.
EGL_FUNCTIONS is a sequence of (name, eglData) pairs, where name is the name
of the function, and eglData is a dictionary containing data about that
function.
The values in the eglData dictionary are:
- method (string):
How to select a vendor library. See "Method values" below.
- prefix (string):
This string is prepended to the name of the dispatch function. If
unspecified, the default is "" (an empty string).
- static (boolean)
If True, this function should be declared static.
- "public" (boolean)
If True, the function should be exported from the library. Vendor libraries
generally should not use this.
- extension (string):
If specified, this is the name of a macro to check for before defining a
function. Used for checking for extension macros and such.
- retval (string):
If specified, this is a C expression with the default value to return if we
can't find a function to call. By default, it will try to guess from the
return type: EGL_NO_whatever for the various handle types, NULL for
pointers, and zero for everything else.
method values:
- "custom"
The dispatch stub will be hand-written instead of generated.
- "none"
No dispatch function exists at all, but the function should still have an
entry in the index array. This is for other functions that a stub may need
to call that are implemented in libEGL itself.
- "display"
Select a vendor from an EGLDisplay argument.
- "device"
Select a vendor from an EGLDeviceEXT argument.
- "current"
Select the vendor that owns the current context.
"""
def _eglFunc(name, method, static=None, public=False, inheader=None, prefix="dispatch_", extension=None, retval=None):
"""
A convenience function to define an entry in the EGL function list.
"""
if static is None:
static = (not public and method != "custom")
if inheader is None:
inheader = (not static)
values = {
"method": method,
"prefix": prefix,
"extension": extension,
"retval": retval,
"static": static,
"public": public,
"inheader": inheader,
}
return (name, values)
EGL_FUNCTIONS = (
# EGL_VERSION_1_0
_eglFunc("eglChooseConfig", "none"),
_eglFunc("eglCopyBuffers", "none"),
_eglFunc("eglCreateContext", "none"),
_eglFunc("eglCreatePbufferSurface", "none"),
_eglFunc("eglCreatePixmapSurface", "none"),
_eglFunc("eglCreateWindowSurface", "none"),
_eglFunc("eglDestroyContext", "none"),
_eglFunc("eglDestroySurface", "none"),
_eglFunc("eglGetConfigAttrib", "none"),
_eglFunc("eglGetConfigs", "none"),
_eglFunc("eglQueryContext", "none"),
_eglFunc("eglQuerySurface", "none"),
_eglFunc("eglSwapBuffers", "none"),
_eglFunc("eglWaitGL", "none"),
_eglFunc("eglWaitNative", "none"),
_eglFunc("eglTerminate", "none"),
_eglFunc("eglInitialize", "none"),
_eglFunc("eglGetCurrentDisplay", "none"),
_eglFunc("eglGetCurrentSurface", "none"),
_eglFunc("eglGetDisplay", "none"),
_eglFunc("eglGetError", "none"),
_eglFunc("eglGetProcAddress", "none"),
_eglFunc("eglMakeCurrent", "none"),
_eglFunc("eglQueryString", "none"),
# EGL_VERSION_1_1
_eglFunc("eglBindTexImage", "none"),
_eglFunc("eglReleaseTexImage", "none"),
_eglFunc("eglSurfaceAttrib", "none"),
_eglFunc("eglSwapInterval", "none"),
# EGL_VERSION_1_2
_eglFunc("eglCreatePbufferFromClientBuffer", "none"),
_eglFunc("eglWaitClient", "none"),
_eglFunc("eglBindAPI", "none"),
_eglFunc("eglQueryAPI", "none"),
_eglFunc("eglReleaseThread", "none"),
# EGL_VERSION_1_4
_eglFunc("eglGetCurrentContext", "none"),
# EGL_VERSION_1_5
_eglFunc("eglCreateSync", "none"),
_eglFunc("eglDestroySync", "none"),
_eglFunc("eglClientWaitSync", "none"),
_eglFunc("eglGetSyncAttrib", "none"),
_eglFunc("eglCreateImage", "none"),
_eglFunc("eglDestroyImage", "none"),
_eglFunc("eglCreatePlatformWindowSurface", "none"),
_eglFunc("eglCreatePlatformPixmapSurface", "none"),
_eglFunc("eglWaitSync", "none"),
_eglFunc("eglGetPlatformDisplay", "none"),
# EGL_EXT_platform_base
_eglFunc("eglCreatePlatformWindowSurfaceEXT", "display"),
_eglFunc("eglCreatePlatformPixmapSurfaceEXT", "display"),
_eglFunc("eglGetPlatformDisplayEXT", "none"),
# TODO: Most of these extensions should be provided by the vendor
# libraries, not by libEGL. They're here now to make testing everything
# else easier.
# EGL_EXT_swap_buffers_with_damage
_eglFunc("eglSwapBuffersWithDamageEXT", "display"),
# KHR_EXT_swap_buffers_with_damage
_eglFunc("eglSwapBuffersWithDamageKHR", "display"),
# EGL_KHR_cl_event2
_eglFunc("eglCreateSync64KHR", "display"),
# EGL_KHR_fence_sync
_eglFunc("eglCreateSyncKHR", "display"),
_eglFunc("eglDestroySyncKHR", "display"),
_eglFunc("eglClientWaitSyncKHR", "display"),
_eglFunc("eglGetSyncAttribKHR", "display"),
# EGL_KHR_image
_eglFunc("eglCreateImageKHR", "display"),
_eglFunc("eglDestroyImageKHR", "display"),
# EGL_KHR_image_base
# eglCreateImageKHR already defined in EGL_KHR_image
# eglDestroyImageKHR already defined in EGL_KHR_image
# EGL_KHR_reusable_sync
_eglFunc("eglSignalSyncKHR", "display"),
# eglCreateSyncKHR already defined in EGL_KHR_fence_sync
# eglDestroySyncKHR already defined in EGL_KHR_fence_sync
# eglClientWaitSyncKHR already defined in EGL_KHR_fence_sync
# eglGetSyncAttribKHR already defined in EGL_KHR_fence_sync
# EGL_KHR_wait_sync
_eglFunc("eglWaitSyncKHR", "display"),
# EGL_MESA_image_dma_buf_export
_eglFunc("eglExportDMABUFImageQueryMESA", "display"),
_eglFunc("eglExportDMABUFImageMESA", "display"),
# EGL_WL_bind_wayland_display
_eglFunc("eglCreateWaylandBufferFromImageWL", "display"),
_eglFunc("eglUnbindWaylandDisplayWL", "display"),
_eglFunc("eglQueryWaylandBufferWL", "display"),
_eglFunc("eglBindWaylandDisplayWL", "display"),
# EGL_CHROMIUM_get_sync_values
_eglFunc("eglGetSyncValuesCHROMIUM", "display"),
# EGL_ANGLE_sync_control_rate
_eglFunc("eglGetMscRateANGLE", "display"),
# EGL_ANDROID_native_fence_sync
_eglFunc("eglDupNativeFenceFDANDROID", "display"),
# EGL_ANDROID_blob_cache
_eglFunc("eglSetBlobCacheFuncsANDROID", "display"),
# EGL_EXT_image_dma_buf_import_modifiers
_eglFunc("eglQueryDmaBufFormatsEXT", "display"),
_eglFunc("eglQueryDmaBufModifiersEXT", "display"),
# EGL_EXT_device_base
_eglFunc("eglQueryDeviceAttribEXT", "device"),
_eglFunc("eglQueryDeviceStringEXT", "device"),
_eglFunc("eglQueryDevicesEXT", "none"),
_eglFunc("eglQueryDisplayAttribEXT", "display"),
# EGL_MESA_query_driver
_eglFunc("eglGetDisplayDriverName", "display"),
_eglFunc("eglGetDisplayDriverConfig", "display"),
# EGL_KHR_partial_update
_eglFunc("eglSetDamageRegionKHR", "display"),
# EGL_MESA_gl_interop
_eglFunc("eglGLInteropQueryDeviceInfoMESA", "display"),
_eglFunc("eglGLInteropExportObjectMESA", "display"),
_eglFunc("eglGLInteropFlushObjectsMESA", "display"),
# EGL_EXT_surface_compression
_eglFunc("eglQuerySupportedCompressionRatesEXT", "display"),
# EGL_EXT_device_persistent_id
_eglFunc("eglQueryDeviceBinaryEXT", "device"),
)
+112
View File
@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<registry>
<!--
(C) Copyright 2016, NVIDIA CORPORATION.
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
Authors:
Kyle Brenneman <[email protected]>
-->
<comment>
This file contains any EGL extension functions that are missing from
the normal egl.xml list.
</comment>
<types>
<type>struct <name>mesa_glinterop_device_info</name>;</type>
<type>struct <name>mesa_glinterop_export_in</name>;</type>
<type>struct <name>mesa_glinterop_export_out</name>;</type>
<type>struct <name>mesa_glinterop_flush_out</name>;</type>
</types>
<commands namespace="EGL">
<!-- EGL_WL_bind_wayland_display -->
<command>
<proto>struct wl_buffer * <name>eglCreateWaylandBufferFromImageWL</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLImage</ptype> <name>image</name></param>
</command>
<command>
<proto>EGLBoolean <name>eglUnbindWaylandDisplayWL</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>struct wl_display *</ptype> <name>display</name></param>
</command>
<command>
<proto>EGLBoolean <name>eglQueryWaylandBufferWL</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>struct wl_resource *</ptype> <name>buffer</name></param>
<param><ptype>EGLint</ptype> <name>attribute</name></param>
<param><ptype>EGLint *</ptype> <name>value</name></param>
</command>
<command>
<proto>EGLBoolean <name>eglBindWaylandDisplayWL</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>struct wl_display *</ptype> <name>display</name></param>
</command>
<!-- EGL_CHROMIUM_get_sync_values -->
<command>
<proto>EGLBoolean <name>eglGetSyncValuesCHROMIUM</name></proto>
<param><ptype>EGLDisplay</ptype> <name>display</name></param>
<param><ptype>EGLSurface</ptype> <name>surface</name></param>
<param><ptype>EGLuint64KHR *</ptype> <name>ust</name></param>
<param><ptype>EGLuint64KHR *</ptype> <name>msc</name></param>
<param><ptype>EGLuint64KHR *</ptype> <name>sbc</name></param>
</command>
<!-- EGL_ANGLE_sync_control_rate -->
<command>
<proto>EGLBoolean <name>eglGetMscRateANGLE</name></proto>
<param><ptype>EGLDisplay</ptype> <name>display</name></param>
<param><ptype>EGLSurface</ptype> <name>surface</name></param>
<param><ptype>EGLint *</ptype> <name>numerator</name></param>
<param><ptype>EGLint *</ptype> <name>denominator</name></param>
</command>
<!-- EGL_MESA_gl_interop -->
<command>
<proto><ptype>EGLint</ptype> <name>eglGLInteropQueryDeviceInfoMESA</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLContext</ptype> <name>ctx</name></param>
<param>struct <ptype>mesa_glinterop_device_info</ptype> *<name>out</name></param>
</command>
<command>
<proto><ptype>EGLint</ptype> <name>eglGLInteropExportObjectMESA</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLContext</ptype> <name>ctx</name></param>
<param>struct <ptype>mesa_glinterop_export_in</ptype> *<name>in</name></param>
<param>struct <ptype>mesa_glinterop_export_out</ptype> *<name>out</name></param>
</command>
<command>
<proto><ptype>EGLint</ptype> <name>eglGLInteropFlushObjectsMESA</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLContext</ptype> <name>ctx</name></param>
<param>unsigned <name>count</name></param>
<param>struct <ptype>mesa_glinterop_export_in</ptype> *<name>objects</name></param>
<param>struct <ptype>mesa_glinterop_flush_out</ptype> *<name>out</name></param>
</command>
</commands>
</registry>
+269
View File
@@ -0,0 +1,269 @@
#!/usr/bin/env python3
# (C) Copyright 2016, NVIDIA CORPORATION.
# All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Authors:
# Kyle Brenneman <[email protected]>
"""
Generates dispatch functions for EGL.
The list of functions and arguments is read from the Khronos's XML files, with
additional information defined in the module eglFunctionList.
"""
import argparse
import collections
import eglFunctionList
import sys
import textwrap
import os
NEWAPI = os.path.join(os.path.dirname(__file__), "..", "..", "mesa", "glapi", "new")
sys.path.insert(0, NEWAPI)
import genCommon
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--bind-wl-display", action="store_true",
help="Include EGL_WL_bind_wayland_display")
parser.add_argument("target", choices=("header", "source"),
help="Whether to build the source or header file.")
parser.add_argument("xml_files", nargs="+",
help="The XML files with the EGL function lists.")
args = parser.parse_args()
xmlFunctions = genCommon.getFunctions(args.xml_files)
xmlByName = dict((f.name, f) for f in xmlFunctions)
functions = []
for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS:
if not args.bind_wl_display and "Wayland" in name:
continue
func = xmlByName[name]
eglFunc = fixupEglFunc(func, eglFunc)
functions.append((func, eglFunc))
# Sort the function list by name.
functions = sorted(functions, key=lambda f: f[0].name)
if args.target == "header":
text = generateHeader(functions)
elif args.target == "source":
text = generateSource(functions)
sys.stdout.write(text)
def fixupEglFunc(func, eglFunc):
result = dict(eglFunc)
if result.get("prefix") is None:
result["prefix"] = ""
if result.get("extension") is not None:
text = "defined(" + result["extension"] + ")"
result["extension"] = text
if result["method"] in ("none", "custom"):
return result
if result["method"] not in ("display", "device", "current"):
raise ValueError("Invalid dispatch method %r for function %r" %
(result["method"], func.name))
if func.hasReturn():
if result.get("retval") is None:
result["retval"] = getDefaultReturnValue(func.rt)
return result
def generateHeader(functions):
text = textwrap.dedent(r"""
#ifndef G_EGLDISPATCH_STUBS_H
#define G_EGLDISPATCH_STUBS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglmesaext.h>
#include <EGL/eglext_angle.h>
#include <GL/mesa_glinterop.h>
#include "glvnd/libeglabi.h"
""".lstrip("\n"))
text += "enum {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
text += " __EGL_DISPATCH_" + func.name + ",\n"
text += generateGuardEnd(func, eglFunc)
text += " __EGL_DISPATCH_COUNT\n"
text += "};\n"
for (func, eglFunc) in functions:
if eglFunc["inheader"]:
text += generateGuardBegin(func, eglFunc)
text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(
f=func, ex=eglFunc)
text += generateGuardEnd(func, eglFunc)
text += textwrap.dedent(r"""
#ifdef __cplusplus
}
#endif
#endif // G_EGLDISPATCH_STUBS_H
""")
return text
def generateSource(functions):
# First, sort the function list by name.
text = ""
text += '#include "egldispatchstubs.h"\n'
text += '#include "g_egldispatchstubs.h"\n'
text += '#include <stddef.h>\n'
text += "\n"
for (func, eglFunc) in functions:
if eglFunc["method"] not in ("custom", "none"):
text += generateGuardBegin(func, eglFunc)
text += generateDispatchFunc(func, eglFunc)
text += generateGuardEnd(func, eglFunc)
text += "\n"
text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
text += ' "' + func.name + '",\n'
text += generateGuardEnd(func, eglFunc)
text += " NULL\n"
text += "};\n"
text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
if eglFunc["method"] != "none":
text += " (__eglMustCastToProperFunctionPointerType) " + \
eglFunc.get("prefix", "") + func.name + ",\n"
else:
text += " NULL, // " + func.name + "\n"
text += generateGuardEnd(func, eglFunc)
text += " NULL\n"
text += "};\n"
return text
def generateGuardBegin(func, eglFunc):
ext = eglFunc.get("extension")
if ext is not None:
return "#if " + ext + "\n"
else:
return ""
def generateGuardEnd(func, eglFunc):
if eglFunc.get("extension") is not None:
return "#endif\n"
else:
return ""
def generateDispatchFunc(func, eglFunc):
text = ""
if eglFunc.get("static"):
text += "static "
elif eglFunc.get("public"):
text += "PUBLIC "
text += textwrap.dedent(
r"""
{f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
{{
typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
""").lstrip("\n").format(f=func, ef=eglFunc)
if func.hasReturn():
text += " {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
text += " _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
if eglFunc["method"] == "current":
text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(
f=func)
elif eglFunc["method"] in ("display", "device"):
if eglFunc["method"] == "display":
lookupFunc = "__eglDispatchFetchByDisplay"
lookupType = "EGLDisplay"
else:
assert eglFunc["method"] == "device"
lookupFunc = "__eglDispatchFetchByDevice"
lookupType = "EGLDeviceEXT"
lookupArg = None
for arg in func.args:
if arg.type == lookupType:
lookupArg = arg.name
break
if lookupArg is None:
raise ValueError("Can't find %s argument for function %s" %
(lookupType, func.name,))
text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
else:
raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
text += " if(_ptr_{f.name} != NULL) {{\n".format(f=func)
text += " "
if func.hasReturn():
text += "_ret = "
text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
text += " }\n"
if func.hasReturn():
text += " return _ret;\n"
text += "}\n"
return text
def getDefaultReturnValue(typename):
if typename.endswith("*"):
return "NULL"
elif typename == "EGLDisplay":
return "EGL_NO_DISPLAY"
elif typename == "EGLContext":
return "EGL_NO_CONTEXT"
elif typename == "EGLSurface":
return "EGL_NO_SURFACE"
elif typename == "EGLBoolean":
return "EGL_FALSE"
return "0"
if __name__ == "__main__":
main()
+6
View File
@@ -0,0 +1,6 @@
{
"file_format_version" : "1.0.0",
"ICD" : {
"library_path" : "@library_path@"
}
}
+50
View File
@@ -0,0 +1,50 @@
; stdcall calling convention have @number suffix on 32 bits architecture for gcc
eglBindAPI@4
eglBindTexImage@12
eglChooseConfig@20
eglClientWaitSync@20
eglCopyBuffers@12
eglCreateContext@16
eglCreateImage@20
eglCreatePbufferFromClientBuffer@20
eglCreatePbufferSurface@12
eglCreatePixmapSurface@16
eglCreatePlatformPixmapSurface@16
eglCreatePlatformWindowSurface@16
eglCreateSync@12
eglCreateWindowSurface@16
eglDestroyContext@8
eglDestroyImage@8
eglDestroySurface@8
eglDestroySync@8
eglGetConfigAttrib@16
eglGetConfigs@16
eglGetCurrentContext@0
eglGetCurrentDisplay@0
eglGetCurrentSurface@4
eglGetDisplay@4
eglGetError@0
eglGetPlatformDisplay@12
eglGetProcAddress@4
eglGetSyncAttrib@16
eglInitialize@12
eglMakeCurrent@16
eglQueryAPI@0
eglQueryContext@16
eglQueryString@8
eglQuerySurface@16
eglReleaseTexImage@12
eglReleaseThread@0
eglSurfaceAttrib@16
eglSwapBuffers@8
eglSwapInterval@8
eglTerminate@4
eglWaitClient@0
eglWaitGL@0
eglWaitNative@4
eglWaitSync@12
; __cdecl calling convention have no @number suffix
MesaGLInteropEGLQueryDeviceInfo
MesaGLInteropEGLExportObject
MesaGLInteropEGLFlushObjects
File diff suppressed because it is too large. Load diff
+193
View File
@@ -0,0 +1,193 @@
/**************************************************************************
*
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "eglarray.h"
#include "egllog.h"
/**
* Grow the size of the array.
*/
static EGLBoolean
_eglGrowArray(_EGLArray *array)
{
EGLint new_size;
void **elems;
new_size = array->MaxSize;
while (new_size <= array->Size)
new_size *= 2;
elems = realloc(array->Elements, new_size * sizeof(array->Elements[0]));
if (!elems) {
_eglLog(_EGL_DEBUG, "failed to grow %s array to %d", array->Name,
new_size);
return EGL_FALSE;
}
array->Elements = elems;
array->MaxSize = new_size;
return EGL_TRUE;
}
/**
* Create an array.
*/
_EGLArray *
_eglCreateArray(const char *name, EGLint init_size)
{
_EGLArray *array;
array = calloc(1, sizeof(*array));
if (array) {
array->Name = name;
array->MaxSize = (init_size > 0) ? init_size : 1;
if (!_eglGrowArray(array)) {
free(array);
array = NULL;
}
}
return array;
}
/**
* Destroy an array, optionally free the data.
*/
void
_eglDestroyArray(_EGLArray *array, void (*free_cb)(void *))
{
if (free_cb) {
EGLint i;
for (i = 0; i < array->Size; i++)
free_cb(array->Elements[i]);
}
free(array->Elements);
free(array);
}
/**
* Append a element to an array.
*/
void
_eglAppendArray(_EGLArray *array, void *elem)
{
if (array->Size >= array->MaxSize && !_eglGrowArray(array))
return;
array->Elements[array->Size++] = elem;
}
/**
* Erase an element from an array.
*/
void
_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *))
{
if (free_cb)
free_cb(array->Elements[i]);
if (i < array->Size - 1) {
memmove(&array->Elements[i], &array->Elements[i + 1],
(array->Size - i - 1) * sizeof(array->Elements[0]));
}
array->Size--;
}
/**
* Find in an array for the given element.
*/
void *
_eglFindArray(_EGLArray *array, void *elem)
{
EGLint i;
if (!array)
return NULL;
for (i = 0; i < array->Size; i++)
if (array->Elements[i] == elem)
return elem;
return NULL;
}
/**
* Filter an array and return the number of filtered elements.
*/
EGLint
_eglFilterArray(_EGLArray *array, void **data, EGLint size,
_EGLArrayForEach filter, void *filter_data)
{
EGLint count = 0, i;
if (!array)
return 0;
assert(filter);
for (i = 0; i < array->Size; i++) {
if (filter(array->Elements[i], filter_data)) {
if (data && count < size)
data[count] = array->Elements[i];
count++;
}
if (data && count >= size)
break;
}
return count;
}
/**
* Flatten an array by converting array elements into another form and store
* them in a buffer.
*/
EGLint
_eglFlattenArray(_EGLArray *array, void *buffer, EGLint elem_size, EGLint size,
_EGLArrayForEach flatten)
{
EGLint i, count;
if (!array)
return 0;
count = array->Size;
if (buffer) {
/* clamp size to 0 */
if (size < 0)
size = 0;
/* do not exceed buffer size */
if (count > size)
count = size;
for (i = 0; i < count; i++)
flatten(array->Elements[i], (void *)((char *)buffer + elem_size * i));
}
return count;
}
+80
View File
@@ -0,0 +1,80 @@
/**************************************************************************
*
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLARRAY_INCLUDED
#define EGLARRAY_INCLUDED
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef EGLBoolean (*_EGLArrayForEach)(void *elem, void *foreach_data);
struct _egl_array {
const char *Name;
EGLint MaxSize;
void **Elements;
EGLint Size;
};
extern _EGLArray *
_eglCreateArray(const char *name, EGLint init_size);
extern void
_eglDestroyArray(_EGLArray *array, void (*free_cb)(void *));
extern void
_eglAppendArray(_EGLArray *array, void *elem);
extern void
_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *));
void *
_eglFindArray(_EGLArray *array, void *elem);
extern EGLint
_eglFilterArray(_EGLArray *array, void **data, EGLint size,
_EGLArrayForEach filter, void *filter_data);
EGLint
_eglFlattenArray(_EGLArray *array, void *buffer, EGLint elem_size, EGLint size,
_EGLArrayForEach flatten);
static inline EGLint
_eglGetArraySize(_EGLArray *array)
{
return (array) ? array->Size : 0;
}
#ifdef __cplusplus
}
#endif
#endif /* EGLARRAY_INCLUDED */
+835
View File
@@ -0,0 +1,835 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* EGL Configuration (pixel format) functions.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "util/macros.h"
#include "eglconfig.h"
#include "eglconfigdebug.h"
#include "eglcurrent.h"
#include "egldisplay.h"
#include "egllog.h"
/**
* Init the given _EGLconfig to default values.
* \param id the configuration's ID.
*
* Note that id must be positive for the config to be valid.
* It is also recommended that when there are N configs, their
* IDs are from 1 to N respectively.
*/
void
_eglInitConfig(_EGLConfig *conf, _EGLDisplay *disp, EGLint id)
{
memset(conf, 0, sizeof(*conf));
conf->Display = disp;
/* some attributes take non-zero default values */
conf->ConfigID = id;
conf->ConfigCaveat = EGL_NONE;
conf->TransparentType = EGL_NONE;
conf->NativeVisualType = EGL_NONE;
conf->ColorBufferType = EGL_RGB_BUFFER;
conf->ComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
}
/**
* Link a config to its display and return the handle of the link.
* The handle can be passed to client directly.
*
* Note that we just save the ptr to the config (we don't copy the config).
*/
EGLConfig
_eglLinkConfig(_EGLConfig *conf)
{
_EGLDisplay *disp = conf->Display;
/* sanity check */
assert(disp);
assert(conf->ConfigID > 0);
if (!disp->Configs) {
disp->Configs = _eglCreateArray("Config", 16);
if (!disp->Configs)
return (EGLConfig)NULL;
}
_eglAppendArray(disp->Configs, (void *)conf);
return (EGLConfig)conf;
}
/**
* Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/
_EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *disp)
{
_EGLConfig *conf;
if (!disp)
return NULL;
conf = (_EGLConfig *)_eglFindArray(disp->Configs, (void *)config);
if (conf)
assert(conf->Display == disp);
return conf;
}
enum type {
ATTRIB_TYPE_INTEGER,
ATTRIB_TYPE_BOOLEAN,
ATTRIB_TYPE_BITMASK,
ATTRIB_TYPE_ENUM,
ATTRIB_TYPE_PSEUDO, /* non-queryable */
ATTRIB_TYPE_PLATFORM, /* platform-dependent */
};
enum criterion {
ATTRIB_CRITERION_EXACT,
ATTRIB_CRITERION_ATLEAST,
ATTRIB_CRITERION_MASK,
ATTRIB_CRITERION_SPECIAL,
ATTRIB_CRITERION_IGNORE
};
/* EGL spec Table 3.1 and 3.4 */
static const struct {
EGLint attr;
enum type type;
enum criterion criterion;
EGLint default_value;
} _eglValidationTable[] = {
/* clang-format off */
/* core */
{ EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_RED_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_RGB_BUFFER },
{ EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_CONFORMANT, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
0 },
{ EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_LEVEL, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_EXACT,
0 },
{ EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
EGL_OPENGL_ES_BIT },
{ EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_SAMPLES, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
EGL_WINDOW_BIT },
{ EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_NONE },
{ EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
ATTRIB_CRITERION_SPECIAL,
EGL_NONE },
/* extensions */
{ EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_FRAMEBUFFER_TARGET_ANDROID, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_RECORDABLE_ANDROID, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_COLOR_COMPONENT_TYPE_EXT, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_COLOR_COMPONENT_TYPE_FIXED_EXT },
{ EGL_CONFIG_SELECT_GROUP_EXT, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
/* clang-format on */
};
/**
* Return true if a config is valid. When for_matching is true,
* EGL_DONT_CARE is accepted as a valid attribute value, and checks
* for conflicting attribute values are skipped.
*
* Note that some attributes are platform-dependent and are not
* checked.
*/
EGLBoolean
_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
{
_EGLDisplay *disp = conf->Display;
EGLint i, attr, val;
EGLBoolean valid = EGL_TRUE;
/* check attributes by their types */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
EGLint mask;
attr = _eglValidationTable[i].attr;
val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].type) {
case ATTRIB_TYPE_INTEGER:
switch (attr) {
case EGL_CONFIG_ID:
/* config id must be positive */
if (val <= 0)
valid = EGL_FALSE;
break;
case EGL_SAMPLE_BUFFERS:
/* there can be at most 1 sample buffer */
if (val > 1 || val < 0)
valid = EGL_FALSE;
break;
case EGL_CONFIG_SELECT_GROUP_EXT:
break;
default:
if (val < 0)
valid = EGL_FALSE;
break;
}
break;
case ATTRIB_TYPE_BOOLEAN:
if (val != EGL_TRUE && val != EGL_FALSE)
valid = EGL_FALSE;
break;
case ATTRIB_TYPE_ENUM:
switch (attr) {
case EGL_CONFIG_CAVEAT:
if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
val != EGL_NON_CONFORMANT_CONFIG)
valid = EGL_FALSE;
break;
case EGL_TRANSPARENT_TYPE:
if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
valid = EGL_FALSE;
break;
case EGL_COLOR_BUFFER_TYPE:
if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
valid = EGL_FALSE;
break;
case EGL_COLOR_COMPONENT_TYPE_EXT:
if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT &&
val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT)
valid = EGL_FALSE;
break;
default:
UNREACHABLE("check _eglValidationTable[]");
break;
}
break;
case ATTRIB_TYPE_BITMASK:
switch (attr) {
case EGL_SURFACE_TYPE:
mask = EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT |
EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT |
EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
if (disp->Extensions.KHR_mutable_render_buffer)
mask |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR;
break;
case EGL_RENDERABLE_TYPE:
case EGL_CONFORMANT:
mask = EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT |
EGL_OPENGL_ES3_BIT_KHR | EGL_OPENGL_BIT;
break;
default:
UNREACHABLE("check _eglValidationTable[]");
mask = 0;
break;
}
if (val & ~mask)
valid = EGL_FALSE;
break;
case ATTRIB_TYPE_PLATFORM:
/* unable to check platform-dependent attributes here */
break;
case ATTRIB_TYPE_PSEUDO:
/* pseudo attributes should not be set */
if (val != 0)
valid = EGL_FALSE;
break;
}
if (!valid && for_matching) {
/* accept EGL_DONT_CARE as a valid value */
if (val == EGL_DONT_CARE)
valid = EGL_TRUE;
if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
valid = EGL_TRUE;
}
if (!valid) {
_eglLog(_EGL_DEBUG, "attribute 0x%04x has an invalid value 0x%x", attr,
val);
break;
}
}
/* any invalid attribute value should have been caught */
if (!valid || for_matching)
return valid;
/* now check for conflicting attribute values */
switch (conf->ColorBufferType) {
case EGL_RGB_BUFFER:
if (conf->LuminanceSize)
valid = EGL_FALSE;
if (conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize !=
conf->BufferSize)
valid = EGL_FALSE;
break;
case EGL_LUMINANCE_BUFFER:
if (conf->RedSize || conf->GreenSize || conf->BlueSize)
valid = EGL_FALSE;
if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
valid = EGL_FALSE;
break;
}
if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
return EGL_FALSE;
}
if (!conf->SampleBuffers && conf->Samples)
valid = EGL_FALSE;
if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
return EGL_FALSE;
}
if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
valid = EGL_FALSE;
}
if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
valid = EGL_FALSE;
}
if (!valid) {
_eglLog(_EGL_DEBUG,
"conflicting surface type and native visual/texture binding");
return EGL_FALSE;
}
return valid;
}
/**
* Return true if a config matches the criteria. This and
* _eglParseConfigAttribList together implement the algorithm
* described in "Selection of EGLConfigs".
*
* Note that attributes that are special (currently, only
* EGL_MATCH_NATIVE_PIXMAP) are ignored.
*/
EGLBoolean
_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
{
EGLint attr, val, i;
EGLBoolean matched = EGL_TRUE;
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
EGLint cmp;
if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
continue;
attr = _eglValidationTable[i].attr;
cmp = _eglGetConfigKey(criteria, attr);
if (cmp == EGL_DONT_CARE)
continue;
val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].criterion) {
case ATTRIB_CRITERION_EXACT:
if (val != cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_ATLEAST:
if (val < cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_MASK:
if ((val & cmp) != cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_SPECIAL:
/* ignored here */
break;
case ATTRIB_CRITERION_IGNORE:
UNREACHABLE("already handled above");
break;
}
if (!matched) {
#if !MESA_DEBUG
/* only print the common errors when MESA_DEBUG is defined to 0 */
if (attr != EGL_RENDERABLE_TYPE)
break;
#endif
_eglLog(_EGL_DEBUG,
"the value (0x%x) of attribute 0x%04x did not meet the "
"criteria (0x%x)",
val, attr, cmp);
break;
}
}
return matched;
}
static inline EGLBoolean
_eglIsConfigAttribValid(const _EGLConfig *conf, EGLint attr)
{
if (_eglOffsetOfConfig(attr) < 0)
return EGL_FALSE;
switch (attr) {
case EGL_Y_INVERTED_NOK:
return conf->Display->Extensions.NOK_texture_from_pixmap;
case EGL_FRAMEBUFFER_TARGET_ANDROID:
return conf->Display->Extensions.ANDROID_framebuffer_target;
case EGL_RECORDABLE_ANDROID:
return conf->Display->Extensions.ANDROID_recordable;
default:
break;
}
return EGL_TRUE;
}
/**
* Initialize a criteria config from the given attribute list.
* Return EGL_FALSE if any of the attribute is invalid.
*/
EGLBoolean
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp,
const EGLint *attrib_list)
{
EGLint attr, val, i;
_eglInitConfig(conf, disp, EGL_DONT_CARE);
/* reset to default values */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
attr = _eglValidationTable[i].attr;
val = _eglValidationTable[i].default_value;
_eglSetConfigKey(conf, attr, val);
}
/* parse the list */
for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
attr = attrib_list[i];
val = attrib_list[i + 1];
if (!_eglIsConfigAttribValid(conf, attr))
return EGL_FALSE;
_eglSetConfigKey(conf, attr, val);
}
if (!_eglValidateConfig(conf, EGL_TRUE))
return EGL_FALSE;
/* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
if (conf->Level == EGL_DONT_CARE || conf->MatchNativePixmap == EGL_DONT_CARE)
return EGL_FALSE;
/* ignore other attributes when EGL_CONFIG_ID is given */
if (conf->ConfigID != EGL_DONT_CARE) {
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
attr = _eglValidationTable[i].attr;
if (attr != EGL_CONFIG_ID)
_eglSetConfigKey(conf, attr, EGL_DONT_CARE);
}
} else {
if (!(conf->SurfaceType & EGL_WINDOW_BIT))
conf->NativeVisualType = EGL_DONT_CARE;
if (conf->TransparentType == EGL_NONE) {
conf->TransparentRedValue = EGL_DONT_CARE;
conf->TransparentGreenValue = EGL_DONT_CARE;
conf->TransparentBlueValue = EGL_DONT_CARE;
}
}
return EGL_TRUE;
}
/**
* Decide the ordering of conf1 and conf2, under the given criteria.
* When compare_id is true, this implements the algorithm described
* in "Sorting of EGLConfigs". When compare_id is false,
* EGL_CONFIG_ID is not compared.
*
* It returns a negative integer if conf1 is considered to come
* before conf2; a positive integer if conf2 is considered to come
* before conf1; zero if the ordering cannot be decided.
*
* Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
* ignored here.
*/
EGLint
_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
const _EGLConfig *criteria, EGLBoolean compare_id)
{
const EGLint compare_attribs[] = {
EGL_BUFFER_SIZE, EGL_SAMPLE_BUFFERS, EGL_SAMPLES,
EGL_DEPTH_SIZE, EGL_STENCIL_SIZE, EGL_ALPHA_MASK_SIZE,
};
EGLint val1, val2;
EGLint i;
if (conf1 == conf2)
return 0;
val1 = conf1->ConfigSelectGroup - conf2->ConfigSelectGroup;
if (val1)
return val1;
/* the enum values have the desired ordering */
STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG);
STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
if (val1)
return val1;
/* the enum values have the desired ordering */
STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
val1 = conf1->ColorBufferType - conf2->ColorBufferType;
if (val1)
return val1;
if (criteria) {
val1 = val2 = 0;
if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
if (criteria->RedSize > 0) {
val1 += conf1->RedSize;
val2 += conf2->RedSize;
}
if (criteria->GreenSize > 0) {
val1 += conf1->GreenSize;
val2 += conf2->GreenSize;
}
if (criteria->BlueSize > 0) {
val1 += conf1->BlueSize;
val2 += conf2->BlueSize;
}
} else {
if (criteria->LuminanceSize > 0) {
val1 += conf1->LuminanceSize;
val2 += conf2->LuminanceSize;
}
}
if (criteria->AlphaSize > 0) {
val1 += conf1->AlphaSize;
val2 += conf2->AlphaSize;
}
} else {
/* assume the default criteria, which gives no specific ordering */
val1 = val2 = 0;
}
/* for color bits, larger one is preferred */
if (val1 != val2)
return (val2 - val1);
for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
if (val1 != val2)
return (val1 - val2);
}
/* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
}
static inline void
_eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
{
const _EGLConfig *tmp = *conf1;
*conf1 = *conf2;
*conf2 = tmp;
}
/**
* Quick sort an array of configs. This differs from the standard
* qsort() in that the compare function accepts an additional
* argument.
*/
static void
_eglSortConfigs(const _EGLConfig **configs, EGLint count,
EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
void *),
void *priv_data)
{
const EGLint pivot = 0;
EGLint i, j;
if (count <= 1)
return;
_eglSwapConfigs(&configs[pivot], &configs[count / 2]);
i = 1;
j = count - 1;
do {
while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
i++;
while (compare(configs[j], configs[pivot], priv_data) > 0)
j--;
if (i < j) {
_eglSwapConfigs(&configs[i], &configs[j]);
i++;
j--;
} else if (i == j) {
i++;
j--;
break;
}
} while (i <= j);
_eglSwapConfigs(&configs[pivot], &configs[j]);
_eglSortConfigs(configs, j, compare, priv_data);
_eglSortConfigs(configs + i, count - i, compare, priv_data);
}
/**
* A helper function for implementing eglChooseConfig. See _eglFilterArray and
* _eglSortConfigs for the meanings of match and compare.
*/
static EGLBoolean
_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, EGLint config_size,
EGLint *num_configs,
EGLBoolean (*match)(const _EGLConfig *,
const _EGLConfig *),
EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
void *),
void *priv_data)
{
_EGLConfig **configList;
EGLint i, count;
/* get the number of matched configs */
count = _eglFilterArray(array, NULL, 0, (_EGLArrayForEach)match, priv_data);
if (!count) {
*num_configs = count;
return EGL_TRUE;
}
configList = malloc(sizeof(*configList) * count);
if (!configList)
return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
/* get the matched configs */
_eglFilterArray(array, (void **)configList, count, (_EGLArrayForEach)match,
priv_data);
/* perform sorting of configs */
if (configs && count) {
_eglSortConfigs((const _EGLConfig **)configList, count, compare,
priv_data);
count = MIN2(count, config_size);
for (i = 0; i < count; i++)
configs[i] = _eglGetConfigHandle(configList[i]);
}
free(configList);
*num_configs = count;
return EGL_TRUE;
}
static EGLint
_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
void *priv_data)
{
return _eglCompareConfigs(conf1, conf2, (const _EGLConfig *)priv_data,
EGL_TRUE);
}
/**
* Typical fallback routine for eglChooseConfig
*/
EGLBoolean
_eglChooseConfig(_EGLDisplay *disp, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint *num_configs)
{
_EGLConfig criteria;
EGLBoolean result;
if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
result = _eglFilterConfigArray(disp->Configs, configs, config_size,
num_configs, _eglMatchConfig,
_eglFallbackCompare, (void *)&criteria);
if (result && (_eglGetLogLevel() == _EGL_DEBUG))
eglPrintConfigDebug(disp, configs, *num_configs, EGL_TRUE);
return result;
}
/**
* Fallback for eglGetConfigAttrib.
*/
EGLBoolean
_eglGetConfigAttrib(const _EGLDisplay *disp, const _EGLConfig *conf,
EGLint attribute, EGLint *value)
{
if (!_eglIsConfigAttribValid(conf, attribute))
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
/* nonqueryable attributes */
switch (attribute) {
case EGL_MATCH_NATIVE_PIXMAP:
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
break;
default:
break;
}
if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
*value = _eglGetConfigKey(conf, attribute);
return EGL_TRUE;
}
static EGLBoolean
_eglFlattenConfig(void *elem, void *buffer)
{
_EGLConfig *conf = (_EGLConfig *)elem;
EGLConfig *handle = (EGLConfig *)buffer;
*handle = _eglGetConfigHandle(conf);
return EGL_TRUE;
}
/**
* Fallback for eglGetConfigs.
*/
EGLBoolean
_eglGetConfigs(_EGLDisplay *disp, EGLConfig *configs, EGLint config_size,
EGLint *num_config)
{
*num_config =
_eglFlattenArray(disp->Configs, (void *)configs, sizeof(configs[0]),
config_size, _eglFlattenConfig);
if (_eglGetLogLevel() == _EGL_DEBUG)
eglPrintConfigDebug(disp, configs, *num_config, EGL_FALSE);
return EGL_TRUE;
}
+220
View File
@@ -0,0 +1,220 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLCONFIG_INCLUDED
#define EGLCONFIG_INCLUDED
#include <assert.h>
#include <stddef.h>
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
/* update _eglValidationTable and _eglOffsetOfConfig before updating this
* struct */
struct _egl_config {
_EGLDisplay *Display;
/* core */
EGLint BufferSize;
EGLint AlphaSize;
EGLint BlueSize;
EGLint GreenSize;
EGLint RedSize;
EGLint DepthSize;
EGLint StencilSize;
EGLint ConfigCaveat;
EGLint ConfigID;
EGLint Level;
EGLint MaxPbufferHeight;
EGLint MaxPbufferPixels;
EGLint MaxPbufferWidth;
EGLint NativeRenderable;
EGLint NativeVisualID;
EGLint NativeVisualType;
EGLint Samples;
EGLint SampleBuffers;
EGLint SurfaceType;
EGLint TransparentType;
EGLint TransparentBlueValue;
EGLint TransparentGreenValue;
EGLint TransparentRedValue;
EGLint BindToTextureRGB;
EGLint BindToTextureRGBA;
EGLint MinSwapInterval;
EGLint MaxSwapInterval;
EGLint LuminanceSize;
EGLint AlphaMaskSize;
EGLint ColorBufferType;
EGLint RenderableType;
EGLint MatchNativePixmap;
EGLint Conformant;
/* extensions */
EGLint YInvertedNOK;
EGLint FramebufferTargetAndroid;
EGLint RecordableAndroid;
EGLint ComponentType;
EGLint ConfigSelectGroup;
};
/**
* Map an EGL attribute enum to the offset of the member in _EGLConfig.
*/
static inline EGLint
_eglOffsetOfConfig(EGLint attr)
{
switch (attr) {
#define ATTRIB_MAP(attr, memb) \
case attr: \
return offsetof(_EGLConfig, memb)
/* core */
ATTRIB_MAP(EGL_BUFFER_SIZE, BufferSize);
ATTRIB_MAP(EGL_ALPHA_SIZE, AlphaSize);
ATTRIB_MAP(EGL_BLUE_SIZE, BlueSize);
ATTRIB_MAP(EGL_GREEN_SIZE, GreenSize);
ATTRIB_MAP(EGL_RED_SIZE, RedSize);
ATTRIB_MAP(EGL_DEPTH_SIZE, DepthSize);
ATTRIB_MAP(EGL_STENCIL_SIZE, StencilSize);
ATTRIB_MAP(EGL_CONFIG_CAVEAT, ConfigCaveat);
ATTRIB_MAP(EGL_CONFIG_ID, ConfigID);
ATTRIB_MAP(EGL_LEVEL, Level);
ATTRIB_MAP(EGL_MAX_PBUFFER_HEIGHT, MaxPbufferHeight);
ATTRIB_MAP(EGL_MAX_PBUFFER_PIXELS, MaxPbufferPixels);
ATTRIB_MAP(EGL_MAX_PBUFFER_WIDTH, MaxPbufferWidth);
ATTRIB_MAP(EGL_NATIVE_RENDERABLE, NativeRenderable);
ATTRIB_MAP(EGL_NATIVE_VISUAL_ID, NativeVisualID);
ATTRIB_MAP(EGL_NATIVE_VISUAL_TYPE, NativeVisualType);
ATTRIB_MAP(EGL_SAMPLES, Samples);
ATTRIB_MAP(EGL_SAMPLE_BUFFERS, SampleBuffers);
ATTRIB_MAP(EGL_SURFACE_TYPE, SurfaceType);
ATTRIB_MAP(EGL_TRANSPARENT_TYPE, TransparentType);
ATTRIB_MAP(EGL_TRANSPARENT_BLUE_VALUE, TransparentBlueValue);
ATTRIB_MAP(EGL_TRANSPARENT_GREEN_VALUE, TransparentGreenValue);
ATTRIB_MAP(EGL_TRANSPARENT_RED_VALUE, TransparentRedValue);
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGB, BindToTextureRGB);
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGBA, BindToTextureRGBA);
ATTRIB_MAP(EGL_MIN_SWAP_INTERVAL, MinSwapInterval);
ATTRIB_MAP(EGL_MAX_SWAP_INTERVAL, MaxSwapInterval);
ATTRIB_MAP(EGL_LUMINANCE_SIZE, LuminanceSize);
ATTRIB_MAP(EGL_ALPHA_MASK_SIZE, AlphaMaskSize);
ATTRIB_MAP(EGL_COLOR_BUFFER_TYPE, ColorBufferType);
ATTRIB_MAP(EGL_RENDERABLE_TYPE, RenderableType);
ATTRIB_MAP(EGL_MATCH_NATIVE_PIXMAP, MatchNativePixmap);
ATTRIB_MAP(EGL_CONFORMANT, Conformant);
/* extensions */
ATTRIB_MAP(EGL_Y_INVERTED_NOK, YInvertedNOK);
ATTRIB_MAP(EGL_FRAMEBUFFER_TARGET_ANDROID, FramebufferTargetAndroid);
ATTRIB_MAP(EGL_RECORDABLE_ANDROID, RecordableAndroid);
ATTRIB_MAP(EGL_COLOR_COMPONENT_TYPE_EXT, ComponentType);
ATTRIB_MAP(EGL_CONFIG_SELECT_GROUP_EXT, ConfigSelectGroup);
#undef ATTRIB_MAP
default:
return -1;
}
}
/**
* Update a config for a given key.
*
* Note that a valid key is not necessarily a valid attribute. There are gaps
* in the attribute enums. The separation is to catch application errors.
* Drivers should never set a key that is an invalid attribute.
*/
static inline void
_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
{
EGLint offset = _eglOffsetOfConfig(key);
assert(offset >= 0);
*((EGLint *)((char *)conf + offset)) = val;
}
/**
* Return the value for a given key.
*/
static inline EGLint
_eglGetConfigKey(const _EGLConfig *conf, EGLint key)
{
EGLint offset = _eglOffsetOfConfig(key);
assert(offset >= 0);
return *((EGLint *)((char *)conf + offset));
}
extern void
_eglInitConfig(_EGLConfig *config, _EGLDisplay *disp, EGLint id);
extern EGLConfig
_eglLinkConfig(_EGLConfig *conf);
extern _EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *disp);
/**
* Return the handle of a linked config.
*/
static inline EGLConfig
_eglGetConfigHandle(_EGLConfig *conf)
{
return (EGLConfig)conf;
}
extern EGLBoolean
_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching);
extern EGLBoolean
_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria);
extern EGLBoolean
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp,
const EGLint *attrib_list);
extern EGLint
_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
const _EGLConfig *criteria, EGLBoolean compare_id);
extern EGLBoolean
_eglChooseConfig(_EGLDisplay *disp, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint *num_config);
extern EGLBoolean
_eglGetConfigAttrib(const _EGLDisplay *disp, const _EGLConfig *conf,
EGLint attribute, EGLint *value);
extern EGLBoolean
_eglGetConfigs(_EGLDisplay *disp, EGLConfig *configs, EGLint config_size,
EGLint *num_config);
#ifdef __cplusplus
}
#endif
#endif /* EGLCONFIG_INCLUDED */
+205
View File
@@ -0,0 +1,205 @@
/*
* Copyright 2019 Imagination Technologies.
* All Rights Reserved.
*
* Based on eglinfo, which has copyright:
* Copyright (C) 2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util/macros.h"
#include "eglarray.h"
#include "eglconfig.h"
#include "eglconfigdebug.h"
#include "egldisplay.h"
#include "egllog.h"
#include "egltypedefs.h"
/* Max debug message length */
#define CONFIG_DEBUG_MSG_MAX 1000
/*
* These are X visual types, so if you're running eglinfo under
* something not X, they probably don't make sense.
*/
static const char *const vnames[] = {"SG", "GS", "SC", "PC", "TC", "DC"};
static void
_printHeaderFormat(void)
{
/*
* EGL configuration output legend:
*
* chosen --------------- eglChooseConfig returned config priority,
* only relevant when eglChooseConfig is called.
* id ------------------- EGL_CONFIG_ID
* bfsz ----------------- EGL_BUFFER_SIZE
* lvl ------------------ EGL_LEVEL
*
* colourbuffer
* r -------------------- EGL_RED_SIZE
* g -------------------- EGL_GREEN_SIZE
* b -------------------- EGL_BLUE_SIZE
* a -------------------- EGL_ALPHA_SIZE
* dpth ----------------- EGL_DEPTH_SIZE
* stcl ----------------- EGL_STENCIL_SIZE
*
* multisample
* ns ------------------- EGL_SAMPLES
* b -------------------- EGL_SAMPLE_BUFFERS
* visid ---------------- EGL_NATIVE_VISUAL_ID/EGL_NATIVE_VISUAL_TYPE
* caveat --------------- EGL_CONFIG_CAVEAT
* bind ----------------- EGL_BIND_TO_TEXTURE_RGB/EGL_BIND_TO_TEXTURE_RGBA
*
* renderable
* gl, es, es2, es3, vg - EGL_RENDERABLE_TYPE
*
* supported
* surfaces ------------- EGL_SURFACE_TYPE
*/
/* clang-format off */
_eglLog(_EGL_DEBUG, "---------------");
_eglLog(_EGL_DEBUG, "Configurations:");
_eglLog(_EGL_DEBUG, "cho bf lv colourbuffer dp st ms vis cav bi renderable supported");
_eglLog(_EGL_DEBUG, "sen id sz l r g b a th cl ns b id eat nd gl es es2 es3 vg surfaces");
_eglLog(_EGL_DEBUG, "---------------");
/* clang-format on */
}
/* Append a formatted string to the buffer, up to the buffer size */
static inline void
_strnAppend(char *const buf, const int bufSize, const char *fmt, ...)
{
int maxAllowed;
va_list args;
size_t bufLen = strlen(buf);
maxAllowed = bufSize - bufLen;
assert(maxAllowed >= 0);
va_start(args, fmt);
(void)vsnprintf(&buf[bufLen], maxAllowed, fmt, args);
va_end(args);
}
static void
_eglPrintConfig(_EGLConfig *const conf, const int chosenIndex)
{
const char padding[] = " ";
char printMsg[CONFIG_DEBUG_MSG_MAX] = "";
char surfString[32] = "";
EGLint renderable, surfaces, vtype, bindRgb, bindRgba;
vtype = conf->NativeVisualType;
surfaces = conf->SurfaceType;
STATIC_ASSERT(sizeof(surfString) >= sizeof("win,pb,pix,str,prsv"));
if (surfaces & EGL_WINDOW_BIT)
strcat(surfString, "win,");
if (surfaces & EGL_PBUFFER_BIT)
strcat(surfString, "pb,");
if (surfaces & EGL_PIXMAP_BIT)
strcat(surfString, "pix,");
if (surfaces & EGL_STREAM_BIT_KHR)
strcat(surfString, "str,");
if (surfaces & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
strcat(surfString, "prsv");
/* If one of chosen configs, print its index in the returned config array */
if (chosenIndex >= 0)
_strnAppend(printMsg, sizeof(printMsg), "%*d ", (int)strlen(padding),
chosenIndex);
else
_strnAppend(printMsg, sizeof(printMsg), "%s ", &padding[0]);
_strnAppend(printMsg, sizeof(printMsg),
"0x%03x %2d %2d %2d %2d %2d %2d %2d %2d %2d%2d 0x%08x%2s ",
conf->ConfigID, conf->BufferSize, conf->Level, conf->RedSize,
conf->GreenSize, conf->BlueSize, conf->AlphaSize,
conf->DepthSize, conf->StencilSize, conf->Samples,
conf->SampleBuffers, conf->NativeVisualID,
vtype < 6 ? vnames[vtype] : "--");
bindRgb = conf->BindToTextureRGB;
bindRgba = conf->BindToTextureRGBA;
renderable = conf->RenderableType;
_strnAppend(printMsg, sizeof(printMsg),
"%c %c %c %c %c %c %c %15s",
(conf->ConfigCaveat != EGL_NONE) ? 'y' : ' ',
(bindRgba) ? 'a'
: (bindRgb) ? 'y'
: ' ',
(renderable & EGL_OPENGL_BIT) ? 'y' : ' ',
(renderable & EGL_OPENGL_ES_BIT) ? 'y' : ' ',
(renderable & EGL_OPENGL_ES2_BIT) ? 'y' : ' ',
(renderable & EGL_OPENGL_ES3_BIT) ? 'y' : ' ',
(renderable & EGL_OPENVG_BIT) ? 'y' : ' ', surfString);
_eglLog(_EGL_DEBUG, printMsg);
}
void
eglPrintConfigDebug(const _EGLDisplay *const disp,
const EGLConfig *const configs, const EGLint numConfigs,
const EGLBoolean printChosen)
{
EGLint numConfigsToPrint;
_EGLConfig **configsToPrint;
_EGLConfig **chosenConfigs;
if (!numConfigs || !configs) {
_eglLog(_EGL_DEBUG, "%s: nothing to print", __func__);
return;
}
/*
* If the printout request came from the 'eglChooseConfig', all
* configs are printed, and the "chosen" configs are marked.
*/
if (printChosen) {
configsToPrint = (_EGLConfig **)disp->Configs->Elements;
numConfigsToPrint = disp->Configs->Size;
chosenConfigs = (_EGLConfig **)configs;
} else {
configsToPrint = (_EGLConfig **)configs;
numConfigsToPrint = numConfigs;
chosenConfigs = NULL;
}
_printHeaderFormat();
for (EGLint i = 0; i < numConfigsToPrint; i++) {
_EGLConfig *configToPrint = configsToPrint[i];
EGLint chosenIndex = -1;
/* See if the current config to print is one of the chosen configs */
if (chosenConfigs)
for (EGLint j = 0; j < numConfigs; j++)
if (configToPrint == chosenConfigs[j])
chosenIndex = j;
_eglPrintConfig(configToPrint, chosenIndex);
}
}
+48
View File
@@ -0,0 +1,48 @@
/**************************************************************************
* Copyright 2017 Imagination Technologies.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLCONFIGDEBUG_INCLUDED
#define EGLCONFIGDEBUG_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "egltypedefs.h"
/**
* Print the list of configs and the associated attributes.
*/
void
eglPrintConfigDebug(const _EGLDisplay *const disp,
const EGLConfig *const configs, EGLint numConfigs,
EGLBoolean printChosen);
#ifdef __cplusplus
}
#endif
#endif /* EGLCONFIGDEBUG_INCLUDED */
+964
View File
@@ -0,0 +1,964 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include "eglcontext.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "util/macros.h"
#include "eglconfig.h"
#include "eglcurrent.h"
#include "egldisplay.h"
#include "egllog.h"
#include "eglsurface.h"
/**
* Return the API bit (one of EGL_xxx_BIT) of the context.
*/
static EGLint
_eglGetContextAPIBit(_EGLContext *ctx)
{
EGLint bit = 0;
switch (ctx->ClientAPI) {
case EGL_OPENGL_ES_API:
switch (ctx->ClientMajorVersion) {
case 1:
bit = EGL_OPENGL_ES_BIT;
break;
case 2:
bit = EGL_OPENGL_ES2_BIT;
break;
case 3:
bit = EGL_OPENGL_ES3_BIT_KHR;
break;
default:
break;
}
break;
case EGL_OPENVG_API:
bit = EGL_OPENVG_BIT;
break;
case EGL_OPENGL_API:
bit = EGL_OPENGL_BIT;
break;
default:
break;
}
return bit;
}
/**
* Parse the list of context attributes and return the proper error code.
*/
static EGLint
_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *disp,
const EGLint *attrib_list)
{
EGLenum api = ctx->ClientAPI;
EGLint i, err = EGL_SUCCESS;
if (!attrib_list)
return EGL_SUCCESS;
if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]);
return EGL_BAD_ATTRIBUTE;
}
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
case EGL_CONTEXT_CLIENT_VERSION:
/* The EGL 1.4 spec says:
*
* "attribute EGL_CONTEXT_CLIENT_VERSION is only valid when the
* current rendering API is EGL_OPENGL_ES_API"
*
* The EGL_KHR_create_context spec says:
*
* "EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
* (this token is an alias for EGL_CONTEXT_CLIENT_VERSION)"
*
* "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
* version. They are only meaningful for OpenGL and OpenGL ES
* contexts, and specifying them for other types of contexts will
* generate an error."
*/
if ((api != EGL_OPENGL_ES_API &&
(!disp->Extensions.KHR_create_context ||
api != EGL_OPENGL_API))) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ClientMajorVersion = val;
break;
case EGL_CONTEXT_MINOR_VERSION_KHR:
/* The EGL_KHR_create_context spec says:
*
* "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
* version. They are only meaningful for OpenGL and OpenGL ES
* contexts, and specifying them for other types of contexts will
* generate an error."
*/
if (!disp->Extensions.KHR_create_context ||
(api != EGL_OPENGL_ES_API && api != EGL_OPENGL_API)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ClientMinorVersion = val;
break;
case EGL_CONTEXT_FLAGS_KHR:
if (!disp->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "If the EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR flag bit is set in
* EGL_CONTEXT_FLAGS_KHR, then a <debug context> will be created.
* [...]
* In some cases a debug context may be identical to a non-debug
* context. This bit is supported for OpenGL and OpenGL ES
* contexts."
*/
if ((val & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) &&
(api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "If the EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR flag bit
* is set in EGL_CONTEXT_FLAGS_KHR, then a <forward-compatible>
* context will be created. Forward-compatible contexts are
* defined only for OpenGL versions 3.0 and later. They must not
* support functionality marked as <deprecated> by that version of
* the API, while a non-forward-compatible context must support
* all functionality in that version, deprecated or not. This bit
* is supported for OpenGL contexts, and requesting a
* forward-compatible context for OpenGL versions less than 3.0
* will generate an error."
*
* Note: since the forward-compatible flag can be set more than one
* way, the OpenGL version check is performed once, below.
*/
if ((val & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) &&
api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if ((val & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) &&
api != EGL_OPENGL_API) {
/* The EGL_KHR_create_context spec says:
*
* 10) Which error should be generated if robust buffer access
* or reset notifications are requested under OpenGL ES?
*
* As per Issue 6, this extension does not support creating
* robust contexts for OpenGL ES. This is only supported via
* the EGL_EXT_create_context_robustness extension.
*
* Attempting to use this extension to create robust OpenGL
* ES context will generate an EGL_BAD_ATTRIBUTE error. This
* specific error is generated because this extension does
* not define the EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
* and EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
* bits for OpenGL ES contexts. Thus, use of these bits fall
* under condition described by: "If an attribute is
* specified that is not meaningful for the client API
* type.." in the above specification.
*
* The spec requires that we emit the error even if the display
* supports EGL_EXT_create_context_robustness. To create a robust
* GLES context, the *attribute*
* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT must be used, not the
* *flag* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR.
*/
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
* "If <config> does not support a client API context compatible
* with the requested API major and minor version, context flags,
* and context reset notification behavior (for client API types
* where these attributes are supported), then an EGL_BAD_MATCH
* error is generated."
*/
if ((val & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) &&
!disp->RobustBufferAccess) {
err = EGL_BAD_MATCH;
break;
}
ctx->Flags |= val;
break;
case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
if (!disp->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
* OpenGL contexts, and specifying it for other types of
* contexts, including OpenGL ES contexts, will generate an
* error."
*/
if (api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Profile = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
* meaningful for OpenGL contexts, and specifying it for other
* types of contexts, including OpenGL ES contexts, will generate
* an error."
*
* EGL 1.5 defines EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
* (without a suffix) which has the same value as the KHR token,
* and specifies that it now works with both GL and ES contexts:
*
* "This attribute is supported only for OpenGL and OpenGL ES
* contexts."
*/
if (!(disp->Extensions.KHR_create_context && api == EGL_OPENGL_API) &&
disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL 1.5 spec says:
* "An EGL_BAD_MATCH error is generated if an OpenGL or OpenGL ES
* context is requested with robust buffer access and with a
* specified reset notification behavior, and the implementation
* does not support that behavior."
*
* and the EGL_KHR_create_context spec says:
* "If <config> does not support a client API context compatible
* with the requested API major and minor version, context flags,
* and context reset notification behavior (for client API types
* where these attributes are supported), then an EGL_BAD_MATCH
* error is generated."
*/
if (val != EGL_NO_RESET_NOTIFICATION_KHR &&
!disp->Extensions.EXT_create_context_robustness) {
err = EGL_BAD_MATCH;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
/* The EGL_EXT_create_context_robustness spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
* meaningful for OpenGL ES contexts, and specifying it for other
* types of contexts will generate an EGL_BAD_ATTRIBUTE error."
*/
if (!disp->Extensions.EXT_create_context_robustness ||
api != EGL_OPENGL_ES_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
if (!disp->Extensions.EXT_create_context_robustness) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_EXT_create_context_robustness spec says:
*
* "EGL_BAD_CONFIG is generated if
* [EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT] is set to EGL_TRUE and
* no GL context supporting the GL_EXT_robustness extension and
* robust access as described therein can be created."
*/
if (val == EGL_TRUE && !disp->RobustBufferAccess) {
err = EGL_BAD_CONFIG;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL 1.5 spec says:
* "An EGL_BAD_MATCH error is generated if an OpenGL or OpenGL ES
* context is requested with robust buffer access, and the
* implementation does not support the corresponding OpenGL or
* OpenGL ES extension".
*/
if (val == EGL_TRUE && !disp->RobustBufferAccess) {
err = EGL_BAD_MATCH;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_DEBUG:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
if (disp->Version < 14 ||
!disp->Extensions.KHR_create_context_no_error) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The KHR_no_error spec only applies against OpenGL 2.0+ and
* OpenGL ES 2.0+
*/
if (((api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API) ||
ctx->ClientMajorVersion < 2) &&
val == EGL_TRUE) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* Canonicalize value to EGL_TRUE/EGL_FALSE definitions */
ctx->NoError = !!val;
break;
case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
/* The EGL_IMG_context_priority spec says:
*
* "EGL_CONTEXT_PRIORITY_LEVEL_IMG determines the priority level of
* the context to be created. This attribute is a hint, as an
* implementation may not support multiple contexts at some
* priority levels and system policy may limit access to high
* priority contexts to appropriate system privilege level. The
* default value for EGL_CONTEXT_PRIORITY_LEVEL_IMG is
* EGL_CONTEXT_PRIORITY_MEDIUM_IMG."
*/
{
int bit;
switch (val) {
case EGL_CONTEXT_PRIORITY_REALTIME_NV:
if (disp->Extensions.NV_context_priority_realtime)
bit = __EGL_CONTEXT_PRIORITY_REALTIME_BIT;
else
bit = -1;
break;
case EGL_CONTEXT_PRIORITY_HIGH_IMG:
bit = __EGL_CONTEXT_PRIORITY_HIGH_BIT;
break;
case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
bit = __EGL_CONTEXT_PRIORITY_MEDIUM_BIT;
break;
case EGL_CONTEXT_PRIORITY_LOW_IMG:
bit = __EGL_CONTEXT_PRIORITY_LOW_BIT;
break;
default:
bit = -1;
break;
}
if (bit < 0) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* "This extension allows an EGLContext to be created with a
* priority hint. It is possible that an implementation will not
* honour the hint, especially if there are constraints on the
* number of high priority contexts available in the system, or
* system policy limits access to high priority contexts to
* appropriate system privilege level. A query is provided to find
* the real priority level assigned to the context after creation."
*
* We currently assume that the driver applies the priority hint
* and filters out any it cannot handle during the screen setup,
* e.g. dri2_setup_screen(). As such we can mask any change that
* the driver would fail, and ctx->ContextPriority matches the
* hint applied to the driver/hardware backend.
*/
if (disp->Extensions.IMG_context_priority & (1 << bit))
ctx->ContextPriority = val;
break;
}
case EGL_CONTEXT_RELEASE_BEHAVIOR_KHR:
if (val == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR ||
val == EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR) {
ctx->ReleaseBehavior = val;
} else {
err = EGL_BAD_ATTRIBUTE;
}
break;
case EGL_PROTECTED_CONTENT_EXT:
if (!disp->Extensions.EXT_protected_content) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Protected = val == EGL_TRUE;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
break;
}
}
if (api == EGL_OPENGL_API) {
/* The EGL_KHR_create_context spec says:
*
* "If the requested OpenGL version is less than 3.2,
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
* functionality of the context is determined solely by the
* requested version."
*
* Since the value is ignored, only validate the setting if the version
* is >= 3.2.
*/
if (ctx->ClientMajorVersion >= 4 ||
(ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
switch (ctx->Profile) {
case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
break;
default:
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested, the requested version
* is greater than 3.2, and the value for attribute
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
* any bits set other than
* EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR and
* EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has more than
* one of these bits set; or if the implementation does not support
* the requested profile, then an EGL_BAD_MATCH error is generated."
*/
err = EGL_BAD_MATCH;
break;
}
}
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
* the value for attribute
* EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
* version and feature set that are not defined, than an
* EGL_BAD_MATCH error is generated.
*
* ... Thus, examples of invalid combinations of attributes
* include:
*
* - Major version < 1 or > 4
* - Major version == 1 and minor version < 0 or > 5
* - Major version == 2 and minor version < 0 or > 1
* - Major version == 3 and minor version < 0 or > 2
* - Major version == 4 and minor version < 0 or > 2
* - Forward-compatible flag set and major version < 3"
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 5 ||
(ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 1 ||
(ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 3:
/* Note: The text above is incorrect. There *is* an OpenGL 3.3!
*/
if (ctx->ClientMinorVersion > 3)
err = EGL_BAD_MATCH;
break;
case 4:
default:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 4.2.
*/
break;
}
} else if (api == EGL_OPENGL_ES_API) {
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL ES context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
* is not defined, than an EGL_BAD_MATCH error is generated.
*
* ... Examples of invalid combinations of attributes include:
*
* - Major version < 1 or > 2
* - Major version == 1 and minor version < 0 or > 1
* - Major version == 2 and minor version != 0
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 1)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 0)
err = EGL_BAD_MATCH;
break;
case 3:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 3.0.
*/
break;
default:
err = EGL_BAD_MATCH;
break;
}
}
switch (ctx->ResetNotificationStrategy) {
case EGL_NO_RESET_NOTIFICATION_KHR:
case EGL_LOSE_CONTEXT_ON_RESET_KHR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context_no_error spec says:
*
* "BAD_MATCH is generated if the EGL_CONTEXT_OPENGL_NO_ERROR_KHR is TRUE
* at the same time as a debug or robustness context is specified."
*/
if (ctx->NoError &&
(ctx->Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR ||
ctx->Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) {
err = EGL_BAD_MATCH;
}
if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR |
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR |
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
err = EGL_BAD_ATTRIBUTE;
}
return err;
}
/**
* Initialize the given _EGLContext object to defaults and/or the values
* in the attrib_list.
*
* According to EGL 1.5 Section 3.7:
*
* "EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all
* purposes except eglCreateContext."
*
* And since we only support GL and GLES, this is the only place where the
* bound API matters at all. We look up the current API from the current
* thread, and stash that in the context we're initializing. Our caller is
* responsible for determining whether that's an API it supports.
*/
EGLBoolean
_eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, _EGLConfig *conf,
_EGLContext *share_list, const EGLint *attrib_list)
{
const EGLenum api = eglQueryAPI();
EGLint err;
if (api == EGL_NONE)
return _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
_eglInitResource(&ctx->Resource, sizeof(*ctx), disp);
ctx->ClientAPI = api;
ctx->Config = conf;
ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
ctx->ClientMinorVersion = 0;
ctx->Flags = 0;
ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
ctx->ContextPriority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
ctx->ReleaseBehavior = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR;
err = _eglParseContextAttribList(ctx, disp, attrib_list);
if (err == EGL_SUCCESS && ctx->Config) {
EGLint api_bit;
api_bit = _eglGetContextAPIBit(ctx);
if (!(ctx->Config->RenderableType & api_bit)) {
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
api_bit, ctx->Config->RenderableType);
err = EGL_BAD_CONFIG;
}
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglCreateContext");
/* The EGL_EXT_create_context_robustness spec says:
*
* "Add to the eglCreateContext context creation errors: [...]
*
* * If the reset notification behavior of <share_context> and the
* newly created context are different then an EGL_BAD_MATCH error is
* generated."
*/
if (share_list && share_list->ResetNotificationStrategy !=
ctx->ResetNotificationStrategy) {
return _eglError(
EGL_BAD_MATCH,
"eglCreateContext() share list notification strategy mismatch");
}
/* The EGL_KHR_create_context_no_error spec says:
*
* "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
* used to create <share_context> does not match the value of
* EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
*/
if (share_list && share_list->NoError != ctx->NoError) {
return _eglError(EGL_BAD_MATCH,
"eglCreateContext() share list no-error mismatch");
}
return EGL_TRUE;
}
static EGLint
_eglQueryContextRenderBuffer(_EGLContext *ctx)
{
_EGLSurface *surf = ctx->DrawSurface;
/* From the EGL 1.5 spec:
*
* - If the context is not bound to a surface, then EGL_NONE will be
* returned.
*/
if (!surf)
return EGL_NONE;
switch (surf->Type) {
default:
UNREACHABLE("bad EGLSurface type");
case EGL_PIXMAP_BIT:
/* - If the context is bound to a pixmap surface, then EGL_SINGLE_BUFFER
* will be returned.
*/
return EGL_SINGLE_BUFFER;
case EGL_PBUFFER_BIT:
/* - If the context is bound to a pbuffer surface, then EGL_BACK_BUFFER
* will be returned.
*/
return EGL_BACK_BUFFER;
case EGL_WINDOW_BIT:
/* - If the context is bound to a window surface, then either
* EGL_BACK_BUFFER or EGL_SINGLE_BUFFER may be returned. The value
* returned depends on both the buffer requested by the setting of the
* EGL_RENDER_BUFFER property of the surface [...], and on the client
* API (not all client APIs support single-buffer Rendering to window
* surfaces). Some client APIs allow control of whether rendering goes
* to the front or back buffer. This client API-specific choice is not
* reflected in the returned value, which only describes the buffer
* that will be rendered to by default if not overridden by the client
* API.
*/
return surf->ActiveRenderBuffer;
}
}
EGLBoolean
_eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
{
_EGLDisplay *disp = c->Resource.Display;
EGLenum api = c->ClientAPI;
if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
switch (attribute) {
case EGL_CONFIG_ID:
/*
* From EGL_KHR_no_config_context:
*
* "Querying EGL_CONFIG_ID returns the ID of the EGLConfig with
* respect to which the context was created, or zero if created
* without respect to an EGLConfig."
*/
*value = c->Config ? c->Config->ConfigID : 0;
break;
case EGL_CONTEXT_CLIENT_VERSION:
*value = c->ClientMajorVersion;
break;
case EGL_CONTEXT_CLIENT_TYPE:
*value = c->ClientAPI;
break;
case EGL_RENDER_BUFFER:
*value = _eglQueryContextRenderBuffer(c);
break;
case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
*value = c->ContextPriority;
break;
case EGL_PROTECTED_CONTENT_EXT:
if (!disp->Extensions.EXT_protected_content)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
*value = c->Protected;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
if (!disp->Extensions.EXT_create_context_robustness ||
api != EGL_OPENGL_ES_API)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
*value = c->ResetNotificationStrategy;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
if (!(disp->Extensions.KHR_create_context && api == EGL_OPENGL_API) &&
disp->Version < 15)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
*value = c->ResetNotificationStrategy;
break;
default:
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
}
return EGL_TRUE;
}
/**
* Bind the context to the thread and return the previous context.
*
* Note that the context may be NULL.
*/
_EGLContext *
_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
{
_EGLContext *oldCtx;
oldCtx = t->CurrentContext;
if (ctx != oldCtx) {
if (oldCtx)
oldCtx->Binding = NULL;
if (ctx)
ctx->Binding = t;
t->CurrentContext = ctx;
}
return oldCtx;
}
/**
* Return true if the given context and surfaces can be made current.
*/
static EGLBoolean
_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLDisplay *disp;
/* this is easy */
if (!ctx) {
if (draw || read)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_TRUE;
}
disp = ctx->Resource.Display;
if (!disp->Extensions.KHR_surfaceless_context &&
(draw == NULL || read == NULL))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
/*
* The spec says
*
* "If ctx is current to some other thread, or if either draw or read are
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
* generated."
*
* and
*
* "at most one context may be bound to a particular surface at a given
* time"
*/
if (ctx->Binding && ctx->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
if (draw->CurrentContext->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
if (read && read->CurrentContext && read->CurrentContext != ctx) {
if (read->CurrentContext->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
/* If the context has a config then it must match that of the two
* surfaces */
if (ctx->Config) {
if ((draw && draw->Config != ctx->Config) ||
(read && read->Config != ctx->Config))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
} else {
/* Otherwise we must be using the EGL_KHR_no_config_context
* extension */
assert(disp->Extensions.KHR_no_config_context);
}
return EGL_TRUE;
}
/**
* Bind the context to the current thread and given surfaces. Return the
* previous bound context and surfaces. The caller should unreference the
* returned context and surfaces.
*
* Making a second call with the resources returned by the first call
* unsurprisingly undoes the first call, except for the resource reference
* counts.
*/
EGLBoolean
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx, _EGLSurface **old_draw,
_EGLSurface **old_read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLContext *prev_ctx;
_EGLSurface *prev_draw, *prev_read;
if (!_eglCheckMakeCurrent(ctx, draw, read))
return EGL_FALSE;
/* increment refcounts before binding */
_eglGetContext(ctx);
_eglGetSurface(draw);
_eglGetSurface(read);
/* bind the new context */
prev_ctx = _eglBindContextToThread(ctx, t);
/* break previous bindings */
if (prev_ctx) {
prev_draw = prev_ctx->DrawSurface;
prev_read = prev_ctx->ReadSurface;
if (prev_draw)
prev_draw->CurrentContext = NULL;
if (prev_read)
prev_read->CurrentContext = NULL;
prev_ctx->DrawSurface = NULL;
prev_ctx->ReadSurface = NULL;
} else {
prev_draw = prev_read = NULL;
}
/* establish new bindings */
if (ctx) {
if (draw)
draw->CurrentContext = ctx;
if (read)
read->CurrentContext = ctx;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
}
assert(old_ctx && old_draw && old_read);
*old_ctx = prev_ctx;
*old_draw = prev_draw;
*old_read = prev_read;
return EGL_TRUE;
}
+149
View File
@@ -0,0 +1,149 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLCONTEXT_INCLUDED
#define EGLCONTEXT_INCLUDED
#include "egldisplay.h"
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* "Base" class for device driver contexts.
*/
struct _egl_context {
/* A context is a display resource */
_EGLResource Resource;
/* The bound status of the context */
_EGLThreadInfo *Binding;
_EGLSurface *DrawSurface;
_EGLSurface *ReadSurface;
_EGLConfig *Config;
EGLint ClientAPI; /**< EGL_OPENGL_ES_API, EGL_OPENGL_API, EGL_OPENVG_API */
EGLint ClientMajorVersion;
EGLint ClientMinorVersion;
EGLint Flags;
EGLint Profile;
EGLint ResetNotificationStrategy;
EGLint ContextPriority;
EGLBoolean NoError;
EGLint ReleaseBehavior;
EGLBoolean Protected; /* EGL_EXT_protected_content */
};
extern EGLBoolean
_eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, _EGLConfig *config,
_EGLContext *share_list, const EGLint *attrib_list);
extern EGLBoolean
_eglQueryContext(_EGLContext *ctx, EGLint attribute, EGLint *value);
extern EGLBoolean
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx, _EGLSurface **old_draw,
_EGLSurface **old_read);
extern _EGLContext *
_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t);
/**
* Increment reference count for the context.
*/
static inline _EGLContext *
_eglGetContext(_EGLContext *ctx)
{
if (ctx)
_eglGetResource(&ctx->Resource);
return ctx;
}
/**
* Decrement reference count for the context.
*/
static inline EGLBoolean
_eglPutContext(_EGLContext *ctx)
{
return (ctx) ? _eglPutResource(&ctx->Resource) : EGL_FALSE;
}
/**
* Link a context to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
static inline EGLContext
_eglLinkContext(_EGLContext *ctx)
{
_eglLinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT);
return (EGLContext)ctx;
}
/**
* Unlink a linked context from its display.
* Accessing an unlinked context should generate EGL_BAD_CONTEXT error.
*/
static inline void
_eglUnlinkContext(_EGLContext *ctx)
{
_eglUnlinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT);
}
/**
* Lookup a handle to find the linked context.
* Return NULL if the handle has no corresponding linked context.
*/
static inline _EGLContext *
_eglLookupContext(EGLContext context, _EGLDisplay *disp)
{
_EGLContext *ctx = (_EGLContext *)context;
if (!disp || !_eglCheckResource((void *)ctx, _EGL_RESOURCE_CONTEXT, disp))
ctx = NULL;
return ctx;
}
/**
* Return the handle of a linked context, or EGL_NO_CONTEXT.
*/
static inline EGLContext
_eglGetContextHandle(_EGLContext *ctx)
{
_EGLResource *res = (_EGLResource *)ctx;
return (res && _eglIsResourceLinked(res)) ? (EGLContext)ctx : EGL_NO_CONTEXT;
}
#ifdef __cplusplus
}
#endif
#endif /* EGLCONTEXT_INCLUDED */
+210
View File
@@ -0,0 +1,210 @@
/**************************************************************************
*
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "c11/threads.h"
#include "util/u_string.h"
#include "util/u_thread.h"
#include "eglcurrent.h"
#include "eglglobals.h"
#include "egllog.h"
static __THREAD_INITIAL_EXEC _EGLThreadInfo _egl_TLS = {
.inited = false,
};
static void
_eglInitThreadInfo(_EGLThreadInfo *t)
{
t->LastError = EGL_SUCCESS;
/* default, per EGL spec */
t->CurrentAPI = EGL_OPENGL_ES_API;
}
/**
* Return the calling thread's thread info.
* If the calling thread never calls this function before, or if its thread
* info was destroyed, reinitialize it. This function never returns NULL.
*/
_EGLThreadInfo *
_eglGetCurrentThread(void)
{
_EGLThreadInfo *current = &_egl_TLS;
if (unlikely(!current->inited)) {
memset(current, 0, sizeof(current[0]));
_eglInitThreadInfo(current);
current->inited = true;
}
return current;
}
/**
* Destroy the calling thread's thread info.
*/
void
_eglDestroyCurrentThread(void)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
t->inited = false;
}
/**
* Return the currently bound context of the current API, or NULL.
*/
_EGLContext *
_eglGetCurrentContext(void)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
return t->CurrentContext;
}
/**
* Record EGL error code and return EGL_FALSE.
*/
static EGLBoolean
_eglInternalError(EGLint errCode, const char *msg)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
t->LastError = errCode;
if (errCode != EGL_SUCCESS) {
const char *s;
switch (errCode) {
case EGL_BAD_ACCESS:
s = "EGL_BAD_ACCESS";
break;
case EGL_BAD_ALLOC:
s = "EGL_BAD_ALLOC";
break;
case EGL_BAD_ATTRIBUTE:
s = "EGL_BAD_ATTRIBUTE";
break;
case EGL_BAD_CONFIG:
s = "EGL_BAD_CONFIG";
break;
case EGL_BAD_CONTEXT:
s = "EGL_BAD_CONTEXT";
break;
case EGL_BAD_CURRENT_SURFACE:
s = "EGL_BAD_CURRENT_SURFACE";
break;
case EGL_BAD_DISPLAY:
s = "EGL_BAD_DISPLAY";
break;
case EGL_BAD_MATCH:
s = "EGL_BAD_MATCH";
break;
case EGL_BAD_NATIVE_PIXMAP:
s = "EGL_BAD_NATIVE_PIXMAP";
break;
case EGL_BAD_NATIVE_WINDOW:
s = "EGL_BAD_NATIVE_WINDOW";
break;
case EGL_BAD_PARAMETER:
s = "EGL_BAD_PARAMETER";
break;
case EGL_BAD_SURFACE:
s = "EGL_BAD_SURFACE";
break;
case EGL_NOT_INITIALIZED:
s = "EGL_NOT_INITIALIZED";
break;
default:
s = "other EGL error";
}
_eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
}
return EGL_FALSE;
}
EGLBoolean
_eglError(EGLint errCode, const char *msg)
{
if (errCode != EGL_SUCCESS) {
EGLint type;
if (errCode == EGL_BAD_ALLOC)
type = EGL_DEBUG_MSG_CRITICAL_KHR;
else
type = EGL_DEBUG_MSG_ERROR_KHR;
_eglDebugReport(errCode, NULL, type, msg);
} else
_eglInternalError(errCode, msg);
return EGL_FALSE;
}
void
_eglDebugReport(EGLenum error, const char *funcName, EGLint type,
const char *message, ...)
{
_EGLThreadInfo *thr = _eglGetCurrentThread();
EGLDEBUGPROCKHR callback = NULL;
va_list args;
if (funcName == NULL)
funcName = thr->CurrentFuncName;
simple_mtx_lock(_eglGlobal.Mutex);
if (_eglGlobal.debugTypesEnabled & DebugBitFromType(type))
callback = _eglGlobal.debugCallback;
simple_mtx_unlock(_eglGlobal.Mutex);
char *message_buf = NULL;
if (message != NULL) {
va_start(args, message);
if (vasprintf(&message_buf, message, args) < 0)
message_buf = NULL;
va_end(args);
}
if (callback != NULL) {
callback(error, funcName, type, thr->Label, thr->CurrentObjectLabel,
message_buf);
}
if (type == EGL_DEBUG_MSG_CRITICAL_KHR || type == EGL_DEBUG_MSG_ERROR_KHR) {
char *func_message_buf = NULL;
/* Note: _eglError() is often called with msg == thr->currentFuncName */
if (message_buf && funcName && strcmp(message_buf, funcName) != 0) {
if (asprintf(&func_message_buf, "%s: %s", funcName, message_buf) < 0)
func_message_buf = NULL;
}
_eglInternalError(error, func_message_buf ? func_message_buf : funcName);
free(func_message_buf);
}
free(message_buf);
}
+101
View File
@@ -0,0 +1,101 @@
/**************************************************************************
*
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLCURRENT_INCLUDED
#define EGLCURRENT_INCLUDED
#include <stdbool.h>
#include "util/detect_os.h"
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define _EGL_API_ALL_BITS \
(EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT | \
EGL_OPENGL_ES3_BIT_KHR | EGL_OPENGL_BIT)
/**
* Per-thread info
*/
struct _egl_thread_info {
bool inited;
EGLint LastError;
_EGLContext *CurrentContext;
EGLenum CurrentAPI;
EGLLabelKHR Label;
/**
* The name of the EGL function that's being called at the moment. This is
* used to report the function name to the EGL_KHR_debug callback.
*/
const char *CurrentFuncName;
EGLLabelKHR CurrentObjectLabel;
};
/**
* Return true if a client API enum is recognized.
*/
static inline EGLBoolean
_eglIsApiValid(EGLenum api)
{
#if HAVE_OPENGL && !DETECT_OS_ANDROID
/* OpenGL is not a valid/supported API on Android */
if (api == EGL_OPENGL_API)
return true;
#endif
#if HAVE_OPENGL_ES_1 || HAVE_OPENGL_ES_2
if (api == EGL_OPENGL_ES_API)
return true;
#endif
return false;
}
extern _EGLThreadInfo *
_eglGetCurrentThread(void);
extern void
_eglDestroyCurrentThread(void);
extern _EGLContext *
_eglGetCurrentContext(void);
extern EGLBoolean
_eglError(EGLint errCode, const char *msg);
extern void
_eglDebugReport(EGLenum error, const char *funcName, EGLint type,
const char *message, ...);
#ifdef __cplusplus
}
#endif
#endif /* EGLCURRENT_INCLUDED */
+53
View File
@@ -0,0 +1,53 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* Internal EGL defines
*/
#ifndef EGLDEFINES_INCLUDED
#define EGLDEFINES_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#define _EGL_MAX_EXTENSIONS_LEN 2048
/* Hardcoded, conservative default for EGL_LARGEST_PBUFFER,
* this is used to implement EGL_LARGEST_PBUFFER.
*/
#define _EGL_MAX_PBUFFER_WIDTH 4096
#define _EGL_MAX_PBUFFER_HEIGHT 4096
#define _EGL_VENDOR_STRING "Mesa Project"
#ifdef __cplusplus
}
#endif
#endif /* EGLDEFINES_INCLUDED */
+523
View File
@@ -0,0 +1,523 @@
/**************************************************************************
*
* Copyright 2015, 2018 Collabora
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#endif
#include "util/compiler.h"
#include "util/macros.h"
#include "util/u_debug.h"
#include "eglcurrent.h"
#include "egldevice.h"
#include "eglglobals.h"
#include "egllog.h"
#include "egltypedefs.h"
#include "egldriver.h"
struct _egl_device {
_EGLDevice *Next;
const char *extensions;
EGLBoolean MESA_device_software;
EGLBoolean EXT_device_drm;
EGLBoolean EXT_device_drm_render_node;
EGLBoolean EXT_device_query_name;
EGLBoolean EXT_device_persistent_id;
#ifdef HAVE_LIBDRM
drmDevicePtr device;
#endif
/* Cache for EGL_EXT_device_query_name and EXT_device_persistent_id. */
struct egl_device_info device_info;
};
void
_eglFiniDevice(void)
{
_EGLDevice *dev_list, *dev;
/* atexit function is called with global mutex locked */
dev_list = _eglGlobal.DeviceList;
/* The first device is static allocated SW device */
assert(dev_list);
assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE));
dev_list = dev_list->Next;
while (dev_list) {
/* pop list head */
dev = dev_list;
dev_list = dev_list->Next;
#ifdef HAVE_LIBDRM
assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
drmFreeDevice(&dev->device);
#endif
free(dev->device_info.vendor_name);
free(dev->device_info.renderer_name);
free(dev->device_info.driver_name);
free(dev);
}
_eglGlobal.DeviceList = NULL;
}
EGLBoolean
_eglCheckDeviceHandle(EGLDeviceEXT device)
{
_EGLDevice *cur;
simple_mtx_lock(_eglGlobal.Mutex);
cur = _eglGlobal.DeviceList;
while (cur) {
if (cur == (_EGLDevice *)device)
break;
cur = cur->Next;
}
simple_mtx_unlock(_eglGlobal.Mutex);
return (cur != NULL);
}
_EGLDevice _eglSoftwareDevice = {
/* TODO: EGL_EXT_device_drm support for KMS + llvmpipe */
.extensions = "EGL_MESA_device_software EGL_EXT_device_drm_render_node",
.MESA_device_software = EGL_TRUE,
.EXT_device_drm_render_node = EGL_TRUE,
};
#ifdef HAVE_LIBDRM
extern const _EGLDriver _eglDriver;
/*
* Negative value on error, zero if newly added, one if already in list.
*/
static int
_eglAddDRMDevice(drmDevicePtr device)
{
_EGLDevice *dev;
assert(device->available_nodes & ((1 << DRM_NODE_RENDER)));
/* TODO: uncomment this assert, which is a sanity check.
*
* assert(device->available_nodes & ((1 << DRM_NODE_PRIMARY)));
*
* DRM shim does not expose a primary node, so the CI would fail if we had
* this assert. DRM shim is being used to run shader-db. We need to
* investigate what should be done (probably fixing DRM shim).
*/
dev = _eglGlobal.DeviceList;
/* The first device is always software */
assert(dev);
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
while (dev->Next) {
dev = dev->Next;
assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
if (drmDevicesEqual(device, dev->device) != 0)
return 1;
}
dev->Next = calloc(1, sizeof(_EGLDevice));
if (!dev->Next)
return -1;
dev = dev->Next;
/* Need to have render node for query to work. */
bool supports_info_query =
device->available_nodes & (1 << DRM_NODE_RENDER) &&
_eglDriver.QueryDeviceInfo;
if (supports_info_query)
dev->extensions =
"EGL_EXT_device_drm EGL_EXT_device_drm_render_node "
"EGL_EXT_device_query_name EGL_EXT_device_persistent_id";
else
dev->extensions = "EGL_EXT_device_drm EGL_EXT_device_drm_render_node";
dev->EXT_device_drm = EGL_TRUE;
dev->EXT_device_drm_render_node = EGL_TRUE;
if (supports_info_query) {
dev->EXT_device_query_name = EGL_TRUE;
dev->EXT_device_persistent_id = EGL_TRUE;
}
dev->device = device;
return 0;
}
#endif
/* Finds a device in DeviceList, for the given fd.
*
* The fd must be of a render-capable device, as there are only render-capable
* devices in DeviceList.
*
* If a software device, the fd is ignored.
*/
_EGLDevice *
_eglFindDevice(int fd, bool software)
{
_EGLDevice *dev;
simple_mtx_lock(_eglGlobal.Mutex);
dev = _eglGlobal.DeviceList;
/* The first device is always software */
assert(dev);
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
if (software)
goto out;
#ifdef HAVE_LIBDRM
drmDevicePtr device;
if (drmGetDevice2(fd, 0, &device) != 0) {
dev = NULL;
goto out;
}
while (dev->Next) {
dev = dev->Next;
if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM) &&
drmDevicesEqual(device, dev->device) != 0) {
goto cleanup_drm;
}
}
/* Couldn't find an EGLDevice for the device. */
dev = NULL;
cleanup_drm:
drmFreeDevice(&device);
#else
_eglLog(_EGL_FATAL,
"Driver bug: Built without libdrm, yet looking for HW device");
dev = NULL;
#endif
out:
simple_mtx_unlock(_eglGlobal.Mutex);
return dev;
}
#ifdef HAVE_LIBDRM
drmDevicePtr
_eglDeviceDrm(_EGLDevice *dev)
{
if (!dev)
return NULL;
return dev->device;
}
#endif
_EGLDevice *
_eglDeviceNext(_EGLDevice *dev)
{
if (!dev)
return NULL;
return dev->Next;
}
EGLBoolean
_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext)
{
switch (ext) {
case _EGL_DEVICE_SOFTWARE:
return dev->MESA_device_software;
case _EGL_DEVICE_DRM:
return dev->EXT_device_drm;
case _EGL_DEVICE_DRM_RENDER_NODE:
return dev->EXT_device_drm_render_node;
case _EGL_DEVICE_QUERY_NAME:
return dev->EXT_device_query_name;
case _EGL_DEVICE_PERSISTENT_ID:
return dev->EXT_device_persistent_id;
default:
assert(0);
return EGL_FALSE;
};
}
EGLBoolean
_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, EGLAttrib *value)
{
switch (attribute) {
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceAttribEXT");
return EGL_FALSE;
}
}
EGLBoolean
_eglQueryDeviceBinaryEXT(_EGLDevice *dev, EGLint name, EGLint max_size,
void *value, EGLint *size)
{
if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
!_eglDeviceSupports(dev, _EGL_DEVICE_PERSISTENT_ID) ||
!(name == EGL_DEVICE_UUID_EXT || name == EGL_DRIVER_UUID_EXT) ||
(value != NULL && max_size < EGL_UUID_SIZE) ||
size == NULL) {
_eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceBinaryEXT");
return EGL_FALSE;
}
#ifdef HAVE_LIBDRM
drmDevicePtr device = _eglDeviceDrm(dev);
/* Software device does not have render node. */
const char *render_node =
_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE) ?
"" : device->nodes[DRM_NODE_RENDER];
if (!_eglDriver.QueryDeviceInfo(render_node, &dev->device_info)) {
_eglError(EGL_BAD_DEVICE_EXT, "eglQueryDeviceBinaryEXT");
return EGL_FALSE;
}
if (value && name == EGL_DEVICE_UUID_EXT) {
memcpy(value, dev->device_info.device_uuid, EGL_UUID_SIZE);
}
if (value && name == EGL_DRIVER_UUID_EXT) {
memcpy(value, dev->device_info.driver_uuid, EGL_UUID_SIZE);
}
*size = EGL_UUID_SIZE;
return EGL_TRUE;
#else
/* This should never happen: we don't yet support EGL_DEVICE_DRM nor
* EGL_DEVICE_PERSISTENT_ID for the software device, and physical devices are
* only exposed when libdrm is available. */
assert(0);
_eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceBinaryEXT");
return EGL_FALSE;
#endif
}
const char *
_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name)
{
#ifdef HAVE_LIBDRM
drmDevicePtr device = _eglDeviceDrm(dev);
/* Software device does not have render node. */
const char *render_node =
_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE) ?
"" : device->nodes[DRM_NODE_RENDER];
#endif
switch (name) {
case EGL_EXTENSIONS:
return dev->extensions;
case EGL_DRM_DEVICE_FILE_EXT:
if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM))
break;
#ifdef HAVE_LIBDRM
return dev->device->nodes[DRM_NODE_PRIMARY];
#else
/* This should never happen: we don't yet support EGL_DEVICE_DRM for the
* software device, and physical devices are only exposed when libdrm is
* available. */
assert(0);
break;
#endif
case EGL_DRM_RENDER_NODE_FILE_EXT:
if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM_RENDER_NODE))
break;
#ifdef HAVE_LIBDRM
/* EGLDevice represents a software device, so no render node
* should be advertised. */
if (_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE))
return NULL;
/* We create EGLDevice's only for render capable devices. */
assert(dev->device->available_nodes & (1 << DRM_NODE_RENDER));
return dev->device->nodes[DRM_NODE_RENDER];
#else
/* Physical devices are only exposed when libdrm is available. */
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
return NULL;
#endif
/* EGL_EXT_device_query_name */
case EGL_VENDOR:
if (!_eglDeviceSupports(dev, _EGL_DEVICE_QUERY_NAME))
break;
#ifdef HAVE_LIBDRM
if (!_eglDriver.QueryDeviceInfo(render_node, &dev->device_info)) {
_eglError(EGL_BAD_DEVICE_EXT, "eglQueryDeviceStringEXT");
return NULL;
}
return dev->device_info.vendor_name;
#else
/* Physical devices are only exposed when libdrm is available. */
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
return NULL;
#endif
case EGL_RENDERER_EXT:
if (!_eglDeviceSupports(dev, _EGL_DEVICE_QUERY_NAME))
break;
#ifdef HAVE_LIBDRM
if (!_eglDriver.QueryDeviceInfo(render_node, &dev->device_info)) {
_eglError(EGL_BAD_DEVICE_EXT, "eglQueryDeviceStringEXT");
return NULL;
}
return dev->device_info.renderer_name;
#else
/* Physical devices are only exposed when libdrm is available. */
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
return NULL;
#endif
/* EGL_EXT_device_persistent_id */
case EGL_DRIVER_NAME_EXT:
if (!_eglDeviceSupports(dev, _EGL_DEVICE_PERSISTENT_ID))
break;
#ifdef HAVE_LIBDRM
if (!_eglDriver.QueryDeviceInfo(render_node, &dev->device_info)) {
_eglError(EGL_BAD_DEVICE_EXT, "eglQueryDeviceStringEXT");
return NULL;
}
return dev->device_info.driver_name;
#else
/* Physical devices are only exposed when libdrm is available. */
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
return NULL;
#endif
}
_eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT");
return NULL;
}
/* Do a fresh lookup for devices.
*
* Walks through the DeviceList, discarding no longer available ones
* and adding new ones as applicable.
*
* Must be called with the global lock held.
*/
int
_eglDeviceRefreshList(void)
{
ASSERTED _EGLDevice *dev;
int count = 0;
dev = _eglGlobal.DeviceList;
/* The first device is always software */
assert(dev);
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
count++;
#ifdef HAVE_LIBDRM
drmDevicePtr devices[64];
int num_devs, ret;
num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
for (int i = 0; i < num_devs; i++) {
if (!(devices[i]->available_nodes & (1 << DRM_NODE_RENDER))) {
drmFreeDevice(&devices[i]);
continue;
}
ret = _eglAddDRMDevice(devices[i]);
/* Device is not added - error or already present */
if (ret != 0)
drmFreeDevice(&devices[i]);
if (ret >= 0)
count++;
}
#endif
return count;
}
EGLBoolean
_eglQueryDevicesEXT(EGLint max_devices, _EGLDevice **devices,
EGLint *num_devices)
{
_EGLDevice *dev, *devs, *swrast;
int i = 0, num_devs;
bool request_software =
debug_get_bool_option("LIBGL_ALWAYS_SOFTWARE", false);
if ((devices && max_devices <= 0) || !num_devices)
return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT");
simple_mtx_lock(_eglGlobal.Mutex);
num_devs = _eglDeviceRefreshList();
devs = _eglGlobal.DeviceList;
#ifdef HAVE_SWRAST
swrast = devs;
#else
swrast = NULL;
num_devs--;
#endif
/* The first device is swrast. Start with the non-swrast device. */
devs = devs->Next;
/* bail early if we only care about the count */
if (!devices) {
*num_devices = request_software ? !!swrast : num_devs;
goto out;
}
if (request_software) {
*num_devices = !!swrast;
devices[0] = swrast;
goto out;
}
*num_devices = MIN2(num_devs, max_devices);
/* Add non-swrast devices first and add swrast last.
*
* By default, the user is likely to pick the first device so having the
* software (aka least performant) one is not a good idea.
*/
for (i = 0, dev = devs; dev && i < max_devices; i++) {
devices[i] = dev;
dev = dev->Next;
}
/* User requested the full device list, add the software device. */
if (max_devices >= num_devs && swrast) {
assert(_eglDeviceSupports(swrast, _EGL_DEVICE_SOFTWARE));
devices[num_devs - 1] = swrast;
}
out:
simple_mtx_unlock(_eglGlobal.Mutex);
return EGL_TRUE;
}
+110
View File
@@ -0,0 +1,110 @@
/**************************************************************************
*
* Copyright 2015, 2018 Collabora
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLDEVICE_INCLUDED
#define EGLDEVICE_INCLUDED
#include <stdbool.h>
#include <stddef.h>
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#endif
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
extern _EGLDevice _eglSoftwareDevice;
void
_eglFiniDevice(void);
EGLBoolean
_eglCheckDeviceHandle(EGLDeviceEXT device);
static inline _EGLDevice *
_eglLookupDevice(EGLDeviceEXT device)
{
_EGLDevice *dev = (_EGLDevice *)device;
if (!_eglCheckDeviceHandle(device))
dev = NULL;
return dev;
}
_EGLDevice *
_eglFindDevice(int fd, bool software);
enum _egl_device_extension {
_EGL_DEVICE_SOFTWARE,
_EGL_DEVICE_DRM,
_EGL_DEVICE_DRM_RENDER_NODE,
_EGL_DEVICE_QUERY_NAME,
_EGL_DEVICE_PERSISTENT_ID,
};
typedef enum _egl_device_extension _EGLDeviceExtension;
#ifdef HAVE_LIBDRM
drmDevicePtr
_eglDeviceDrm(_EGLDevice *dev);
#else
#define _eglDeviceDrm(dev) NULL
#endif
_EGLDevice *
_eglDeviceNext(_EGLDevice *dev);
EGLBoolean
_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext);
int
_eglDeviceRefreshList(void);
EGLBoolean
_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, EGLAttrib *value);
const char *
_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name);
EGLBoolean
_eglQueryDevicesEXT(EGLint max_devices, _EGLDevice **devices,
EGLint *num_devices);
EGLBoolean
_eglQueryDeviceBinaryEXT(_EGLDevice* dev,
EGLint name,
EGLint max_size,
void *value,
EGLint *size);
#ifdef __cplusplus
}
#endif
#endif /* EGLDEVICE_INCLUDED */
+147
View File
@@ -0,0 +1,147 @@
/*
* (C) Copyright 2016, NVIDIA CORPORATION.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Kyle Brenneman <[email protected]>
*/
#include "egldispatchstubs.h"
#include "g_egldispatchstubs.h"
#include <stdlib.h>
#include <string.h>
#include "eglcurrent.h"
static const __EGLapiExports *exports;
const int __EGL_DISPATCH_FUNC_COUNT = __EGL_DISPATCH_COUNT;
int __EGL_DISPATCH_FUNC_INDICES[__EGL_DISPATCH_COUNT + 1];
static int
Compare(const void *l, const void *r)
{
const char *s = *(const char **)r;
return strcmp(l, s);
}
static int
FindProcIndex(const char *name)
{
const char * const *match =
bsearch(name, __EGL_DISPATCH_FUNC_NAMES, __EGL_DISPATCH_COUNT,
sizeof(const char *), Compare);
if (match == NULL)
return __EGL_DISPATCH_COUNT;
return match - __EGL_DISPATCH_FUNC_NAMES;
}
void
__eglInitDispatchStubs(const __EGLapiExports *exportsTable)
{
int i;
exports = exportsTable;
for (i = 0; i < __EGL_DISPATCH_FUNC_COUNT; i++) {
__EGL_DISPATCH_FUNC_INDICES[i] = -1;
}
}
void
__eglSetDispatchIndex(const char *name, int dispatchIndex)
{
int index = FindProcIndex(name);
__EGL_DISPATCH_FUNC_INDICES[index] = dispatchIndex;
}
void *
__eglDispatchFindDispatchFunction(const char *name)
{
int index = FindProcIndex(name);
return (void *)__EGL_DISPATCH_FUNCS[index];
}
static __eglMustCastToProperFunctionPointerType
FetchVendorFunc(__EGLvendorInfo *vendor, int index, EGLint errorCode)
{
__eglMustCastToProperFunctionPointerType func = NULL;
if (vendor != NULL) {
func = exports->fetchDispatchEntry(vendor,
__EGL_DISPATCH_FUNC_INDICES[index]);
}
if (func == NULL) {
if (errorCode != EGL_SUCCESS) {
// Since we have no vendor, the follow-up eglGetError() call will
// end up using the GLVND error code. Set it here.
if (vendor == NULL) {
exports->setEGLError(errorCode);
}
_eglError(errorCode, __EGL_DISPATCH_FUNC_NAMES[index]);
}
return NULL;
}
if (!exports->setLastVendor(vendor)) {
// Don't bother trying to set an error code in libglvnd. If
// setLastVendor failed, then setEGLError would also fail.
_eglError(errorCode, __EGL_DISPATCH_FUNC_NAMES[index]);
return NULL;
}
return func;
}
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByCurrent(int index)
{
__EGLvendorInfo *vendor;
// Note: This is only used for the eglWait* functions. For those, if
// there's no current context, then they're supposed to do nothing but
// return success.
exports->threadInit();
vendor = exports->getCurrentVendor();
return FetchVendorFunc(vendor, index, EGL_SUCCESS);
}
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByDisplay(EGLDisplay dpy, int index)
{
__EGLvendorInfo *vendor;
exports->threadInit();
vendor = exports->getVendorFromDisplay(dpy);
return FetchVendorFunc(vendor, index, EGL_BAD_DISPLAY);
}
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByDevice(EGLDeviceEXT dev, int index)
{
__EGLvendorInfo *vendor;
exports->threadInit();
vendor = exports->getVendorFromDevice(dev);
return FetchVendorFunc(vendor, index, EGL_BAD_DEVICE_EXT);
}
+59
View File
@@ -0,0 +1,59 @@
/*
* (C) Copyright 2016, NVIDIA CORPORATION.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Kyle Brenneman <[email protected]>
*/
#ifndef EGLDISPATCHSTUBS_H
#define EGLDISPATCHSTUBS_H
#include "glvnd/libeglabi.h"
// These variables are all generated along with the dispatch stubs.
extern const int __EGL_DISPATCH_FUNC_COUNT;
extern const char *const __EGL_DISPATCH_FUNC_NAMES[];
extern int __EGL_DISPATCH_FUNC_INDICES[];
extern const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[];
void
__eglInitDispatchStubs(const __EGLapiExports *exportsTable);
void
__eglSetDispatchIndex(const char *name, int index);
/**
* Returns the dispatch function for the given name, or \c NULL if the function
* isn't supported.
*/
void *
__eglDispatchFindDispatchFunction(const char *name);
// Helper functions used by the generated stubs.
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByDisplay(EGLDisplay dpy, int index);
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByDevice(EGLDeviceEXT dpy, int index);
__eglMustCastToProperFunctionPointerType
__eglDispatchFetchByCurrent(int index);
#endif // EGLDISPATCHSTUBS_H
+753
View File
@@ -0,0 +1,753 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* Functions related to EGLDisplay.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <fcntl.h>
#include "c11/threads.h"
#include "util/macros.h"
#include "util/os_file.h"
#include "util/os_misc.h"
#include "util/u_atomic.h"
#include "eglcontext.h"
#include "eglcurrent.h"
#include "egldevice.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "eglglobals.h"
#include "eglimage.h"
#include "egllog.h"
#include "eglsurface.h"
#include "eglsync.h"
/* Includes for _eglNativePlatformDetectNativeDisplay */
#ifdef HAVE_WAYLAND_PLATFORM
#include <wayland-client.h>
#endif
#ifdef HAVE_DRM_PLATFORM
#include <gbm.h>
#endif
#ifdef HAVE_WINDOWS_PLATFORM
#include <windows.h>
#endif
/**
* Map build-system platform names to platform types.
*/
static const struct {
_EGLPlatformType platform;
const char *name;
} egl_platforms[] = {
{_EGL_PLATFORM_X11, "x11"},
{_EGL_PLATFORM_XCB, "xcb"},
{_EGL_PLATFORM_WAYLAND, "wayland"},
{_EGL_PLATFORM_DRM, "drm"},
{_EGL_PLATFORM_ANDROID, "android"},
{_EGL_PLATFORM_HAIKU, "haiku"},
{_EGL_PLATFORM_SURFACELESS, "surfaceless"},
{_EGL_PLATFORM_DEVICE, "device"},
{_EGL_PLATFORM_WINDOWS, "windows"},
};
/**
* Return the native platform by parsing EGL_PLATFORM.
*/
static _EGLPlatformType
_eglGetNativePlatformFromEnv(void)
{
_EGLPlatformType plat = _EGL_INVALID_PLATFORM;
const char *plat_name;
EGLint i;
static_assert(ARRAY_SIZE(egl_platforms) == _EGL_NUM_PLATFORMS,
"Missing platform");
plat_name = os_get_option("EGL_PLATFORM");
/* try deprecated env variable */
if (!plat_name || !plat_name[0])
plat_name = os_get_option("EGL_DISPLAY");
if (!plat_name || !plat_name[0])
return _EGL_INVALID_PLATFORM;
for (i = 0; i < ARRAY_SIZE(egl_platforms); i++) {
if (strcmp(egl_platforms[i].name, plat_name) == 0) {
plat = egl_platforms[i].platform;
break;
}
}
if (plat == _EGL_INVALID_PLATFORM)
_eglLog(_EGL_WARNING, "invalid EGL_PLATFORM given");
return plat;
}
/**
* Try detecting native platform with the help of native display characteristics.
*/
static _EGLPlatformType
_eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
{
if (nativeDisplay == EGL_DEFAULT_DISPLAY)
return _EGL_INVALID_PLATFORM;
#ifdef HAVE_WINDOWS_PLATFORM
if (GetObjectType(nativeDisplay) == OBJ_DC)
return _EGL_PLATFORM_WINDOWS;
#endif
#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)
if (_eglPointerIsDereferenceable(nativeDisplay)) {
void *first_pointer = *(void **)nativeDisplay;
#ifdef HAVE_WAYLAND_PLATFORM
/* wl_display is a wl_proxy, which is a wl_object.
* wl_object's first element points to the interfacetype. */
if (first_pointer == &wl_display_interface)
return _EGL_PLATFORM_WAYLAND;
#endif
#ifdef HAVE_DRM_PLATFORM
/* gbm has a pointer to its constructor as first element. */
if (first_pointer == gbm_create_device)
return _EGL_PLATFORM_DRM;
#endif
}
#endif
return _EGL_INVALID_PLATFORM;
}
/**
* Return the native platform. It is the platform of the EGL native types.
*/
_EGLPlatformType
_eglGetNativePlatform(void *nativeDisplay)
{
_EGLPlatformType detected_platform = _eglGetNativePlatformFromEnv();
const char *detection_method = "environment";
if (detected_platform == _EGL_INVALID_PLATFORM) {
detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
detection_method = "autodetected";
}
if (detected_platform == _EGL_INVALID_PLATFORM) {
detected_platform = _EGL_NATIVE_PLATFORM;
detection_method = "build-time configuration";
}
_eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
egl_platforms[detected_platform].name, detection_method);
return detected_platform;
}
/**
* Finish display management.
*/
void
_eglFiniDisplay(void)
{
_EGLDisplay *dispList, *disp;
/* atexit function is called with global mutex locked */
dispList = _eglGlobal.DisplayList;
while (dispList) {
EGLint i;
/* pop list head */
disp = dispList;
dispList = dispList->Next;
for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
if (disp->ResourceLists[i]) {
_eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
break;
}
}
/* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
* and invalid one is 0.
*/
if (disp->Options.fd)
close(disp->Options.fd);
free(disp->Options.Attribs);
free(disp);
}
_eglGlobal.DisplayList = NULL;
}
static EGLBoolean
_eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b)
{
size_t na = _eglNumAttribs(a);
size_t nb = _eglNumAttribs(b);
/* different numbers of attributes must be different */
if (na != nb)
return EGL_FALSE;
/* both lists NULL are the same */
if (!a && !b)
return EGL_TRUE;
/* otherwise, compare the lists */
return memcmp(a, b, na * sizeof(a[0])) == 0 ? EGL_TRUE : EGL_FALSE;
}
/**
* Find the display corresponding to the specified native display, or create a
* new one. EGL 1.5 says:
*
* Multiple calls made to eglGetPlatformDisplay with the same parameters
* will return the same EGLDisplay handle.
*
* We read this extremely strictly, and treat a call with NULL attribs as
* different from a call with attribs only equal to { EGL_NONE }. Similarly
* we do not sort the attribute list, so even if all attribute _values_ are
* identical, different attribute orders will be considered different
* parameters.
*/
_EGLDisplay *
_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy,
const EGLAttrib *attrib_list)
{
_EGLDisplay *disp;
size_t num_attribs;
if (plat == _EGL_INVALID_PLATFORM)
return NULL;
simple_mtx_lock(_eglGlobal.Mutex);
/* search the display list first */
for (disp = _eglGlobal.DisplayList; disp; disp = disp->Next) {
if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy &&
_eglSameAttribs(disp->Options.Attribs, attrib_list))
goto out;
}
/* create a new display */
assert(!disp);
disp = calloc(1, sizeof(_EGLDisplay));
if (!disp)
goto out;
simple_mtx_init(&disp->Mutex, mtx_plain);
u_rwlock_init(&disp->TerminateLock);
disp->Platform = plat;
disp->PlatformDisplay = plat_dpy;
num_attribs = _eglNumAttribs(attrib_list);
if (num_attribs) {
disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib));
if (!disp->Options.Attribs) {
free(disp);
disp = NULL;
goto out;
}
memcpy(disp->Options.Attribs, attrib_list,
num_attribs * sizeof(EGLAttrib));
}
/* add to the display list */
disp->Next = _eglGlobal.DisplayList;
_eglGlobal.DisplayList = disp;
out:
simple_mtx_unlock(_eglGlobal.Mutex);
return disp;
}
/**
* Destroy the contexts and surfaces that are linked to the display.
*/
void
_eglReleaseDisplayResources(_EGLDisplay *display)
{
_EGLResource *list;
const _EGLDriver *drv = display->Driver;
simple_mtx_assert_locked(&display->Mutex);
list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
while (list) {
_EGLContext *ctx = (_EGLContext *)list;
list = list->Next;
_eglUnlinkContext(ctx);
drv->DestroyContext(display, ctx);
}
assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
while (list) {
_EGLSurface *surf = (_EGLSurface *)list;
list = list->Next;
_eglUnlinkSurface(surf);
drv->DestroySurface(display, surf);
}
assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
while (list) {
_EGLImage *image = (_EGLImage *)list;
list = list->Next;
_eglUnlinkImage(image);
drv->DestroyImageKHR(display, image);
}
assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
list = display->ResourceLists[_EGL_RESOURCE_SYNC];
while (list) {
_EGLSync *sync = (_EGLSync *)list;
list = list->Next;
_eglUnlinkSync(sync);
drv->DestroySyncKHR(display, sync);
}
assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
}
/**
* Free all the data hanging of an _EGLDisplay object, but not
* the object itself.
*/
void
_eglCleanupDisplay(_EGLDisplay *disp)
{
if (disp->Configs) {
_eglDestroyArray(disp->Configs, free);
disp->Configs = NULL;
}
/* XXX incomplete */
}
/**
* Return EGL_TRUE if the given resource is valid. That is, the display does
* own the resource.
*/
EGLBoolean
_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
{
_EGLResource *list = disp->ResourceLists[type];
simple_mtx_assert_locked(&disp->Mutex);
if (!res)
return EGL_FALSE;
while (list) {
if (res == (void *)list) {
assert(list->Display == disp);
break;
}
list = list->Next;
}
return (list != NULL);
}
/**
* Initialize a display resource. The size of the subclass object is
* specified.
*
* This is supposed to be called from the initializers of subclasses, such as
* _eglInitContext or _eglInitSurface.
*/
void
_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
{
memset(res, 0, size);
res->Display = disp;
res->RefCount = 1;
}
/**
* Increment reference count for the resource.
*/
void
_eglGetResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
p_atomic_inc(&res->RefCount);
}
/**
* Decrement reference count for the resource.
*/
EGLBoolean
_eglPutResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
return p_atomic_dec_zero(&res->RefCount);
}
/**
* Link a resource to its display.
*/
void
_eglLinkResource(_EGLResource *res, _EGLResourceType type)
{
assert(res->Display);
simple_mtx_assert_locked(&res->Display->Mutex);
res->IsLinked = EGL_TRUE;
res->Next = res->Display->ResourceLists[type];
res->Display->ResourceLists[type] = res;
_eglGetResource(res);
}
/**
* Unlink a linked resource from its display.
*/
void
_eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
{
_EGLResource *prev;
simple_mtx_assert_locked(&res->Display->Mutex);
prev = res->Display->ResourceLists[type];
if (prev != res) {
while (prev) {
if (prev->Next == res)
break;
prev = prev->Next;
}
assert(prev);
prev->Next = res->Next;
} else {
res->Display->ResourceLists[type] = res->Next;
}
res->Next = NULL;
res->IsLinked = EGL_FALSE;
_eglPutResource(res);
/* We always unlink before destroy. The driver still owns a reference */
assert(res->RefCount);
}
#ifdef HAVE_X11_PLATFORM
_EGLDisplay *
_eglGetX11Display(Display *native_display, const EGLAttrib *attrib_list)
{
_EGLDisplay *dpy;
_EGLDevice *dev = NULL;
/* EGL_EXT_platform_x11 adds EGL_PLATFORM_X11_SCREEN_EXT,
* which is optional.
*/
if (attrib_list != NULL) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
switch (attrib) {
case EGL_DEVICE_EXT:
dev = _eglLookupDevice((void *)value);
if (!dev) {
_eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
return NULL;
}
break;
/* EGL_EXT_platform_x11 adds EGL_PLATFORM_X11_SCREEN_EXT,
* which is optional.
*/
case EGL_PLATFORM_X11_SCREEN_EXT:
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
}
}
dpy = _eglFindDisplay(_EGL_PLATFORM_X11, native_display, attrib_list);
if (dpy) {
dpy->Device = dev;
}
return dpy;
}
#endif /* HAVE_X11_PLATFORM */
#ifdef HAVE_XCB_PLATFORM
_EGLDisplay *
_eglGetXcbDisplay(xcb_connection_t *native_display,
const EGLAttrib *attrib_list)
{
_EGLDisplay *dpy;
_EGLDevice *dev = NULL;
/* EGL_EXT_platform_xcb recognizes exactly one attribute,
* EGL_PLATFORM_XCB_SCREEN_EXT, which is optional.
*/
if (attrib_list != NULL) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
switch (attrib) {
case EGL_DEVICE_EXT:
dev = _eglLookupDevice((void *)value);
if (!dev) {
_eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
return NULL;
}
break;
case EGL_PLATFORM_XCB_SCREEN_EXT:
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
}
}
dpy = _eglFindDisplay(_EGL_PLATFORM_XCB, native_display, attrib_list);
if (dpy) {
dpy->Device = dev;
}
return dpy;
}
#endif /* HAVE_XCB_PLATFORM */
#ifdef HAVE_DRM_PLATFORM
_EGLDisplay *
_eglGetGbmDisplay(struct gbm_device *native_display,
const EGLAttrib *attrib_list)
{
_EGLDisplay *dpy;
_EGLDevice *dev = NULL;
/* This platform recognizes only EXT_explicit_device */
if (attrib_list) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
switch (attrib) {
case EGL_DEVICE_EXT:
dev = _eglLookupDevice((void *)value);
if (!dev) {
_eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
return NULL;
}
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
}
}
dpy = _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list);
if (dpy) {
dpy->Device = dev;
}
return dpy;
}
#endif /* HAVE_DRM_PLATFORM */
#ifdef HAVE_WAYLAND_PLATFORM
_EGLDisplay *
_eglGetWaylandDisplay(struct wl_display *native_display,
const EGLAttrib *attrib_list)
{
_EGLDisplay *dpy;
_EGLDevice *dev = NULL;
/* This platform recognizes only EXT_explicit_device */
if (attrib_list) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
switch (attrib) {
case EGL_DEVICE_EXT:
dev = _eglLookupDevice((void *)value);
if (!dev) {
_eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
return NULL;
}
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
}
}
dpy = _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list);
if (dpy) {
dpy->Device = dev;
}
return dpy;
}
#endif /* HAVE_WAYLAND_PLATFORM */
_EGLDisplay *
_eglGetSurfacelessDisplay(void *native_display, const EGLAttrib *attrib_list)
{
_EGLDisplay *dpy;
_EGLDevice *dev = NULL;
/* Any native display must be an EGLDeviceEXT we know about */
if (native_display != NULL) {
_eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
return NULL;
}
/* This platform recognizes only EXT_explicit_device */
if (attrib_list) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
switch (attrib) {
case EGL_DEVICE_EXT:
dev = _eglLookupDevice((void *)value);
if (!dev) {
_eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
return NULL;
}
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
}
}
dpy = _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, NULL, attrib_list);
if (dpy) {
dpy->Device = dev;
}
return dpy;
}
#ifdef HAVE_ANDROID_PLATFORM
_EGLDisplay *
_eglGetAndroidDisplay(void *native_display, const EGLAttrib *attrib_list)
{
/* This platform recognizes no display attributes. */
if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
return _eglFindDisplay(_EGL_PLATFORM_ANDROID, native_display, attrib_list);
}
#endif /* HAVE_ANDROID_PLATFORM */
_EGLDisplay *
_eglGetDeviceDisplay(void *native_display, const EGLAttrib *attrib_list)
{
_EGLDevice *dev;
_EGLDisplay *display;
int fd = -1;
dev = _eglLookupDevice(native_display);
if (!dev) {
_eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
return NULL;
}
if (attrib_list) {
for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
EGLAttrib attrib = attrib_list[i];
EGLAttrib value = attrib_list[i + 1];
/* EGL_EXT_platform_device does not recognize any attributes,
* EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
*/
if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
attrib != EGL_DRM_MASTER_FD_EXT) {
_eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
return NULL;
}
fd = (int)value;
}
}
display = _eglFindDisplay(_EGL_PLATFORM_DEVICE, native_display, attrib_list);
if (!display) {
_eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
return NULL;
}
/* If the fd is explicitly provided and we did not dup() it yet, do so.
* The spec mandates that we do so, since we'll need it past the
* eglGetPlatformDisplay call.
*
* The new fd is guaranteed to be 3 or greater.
*/
if (fd != -1 && display->Options.fd == 0) {
display->Options.fd = os_dupfd_cloexec(fd);
if (display->Options.fd == -1) {
/* Do not (really) need to teardown the display */
_eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
return NULL;
}
}
return display;
}
+361
View File
@@ -0,0 +1,361 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLDISPLAY_INCLUDED
#define EGLDISPLAY_INCLUDED
#include "util/rwlock.h"
#include "util/simple_mtx.h"
#include "eglarray.h"
#include "egldefines.h"
#include "egltypedefs.h"
#ifdef HAVE_X11_PLATFORM
#include <X11/Xlib.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum _egl_platform_type {
_EGL_PLATFORM_X11,
_EGL_PLATFORM_XCB,
_EGL_PLATFORM_WAYLAND,
_EGL_PLATFORM_DRM,
_EGL_PLATFORM_ANDROID,
_EGL_PLATFORM_HAIKU,
_EGL_PLATFORM_SURFACELESS,
_EGL_PLATFORM_DEVICE,
_EGL_PLATFORM_WINDOWS,
_EGL_NUM_PLATFORMS,
_EGL_INVALID_PLATFORM = -1
};
typedef enum _egl_platform_type _EGLPlatformType;
enum _egl_resource_type {
_EGL_RESOURCE_CONTEXT,
_EGL_RESOURCE_SURFACE,
_EGL_RESOURCE_IMAGE,
_EGL_RESOURCE_SYNC,
_EGL_NUM_RESOURCES
};
/* this cannot and need not go into egltypedefs.h */
typedef enum _egl_resource_type _EGLResourceType;
/**
* A resource of a display.
*/
struct _egl_resource {
/* which display the resource belongs to */
_EGLDisplay *Display;
EGLBoolean IsLinked;
EGLint RefCount;
EGLLabelKHR Label;
/* used to link resources of the same type */
_EGLResource *Next;
};
/**
* Optional EGL extensions info.
*/
struct _egl_extensions {
/* Please keep these sorted alphabetically. */
EGLBoolean ANDROID_blob_cache;
EGLBoolean ANDROID_framebuffer_target;
EGLBoolean ANDROID_image_native_buffer;
EGLBoolean ANDROID_native_fence_sync;
EGLBoolean ANDROID_recordable;
EGLBoolean ANGLE_sync_control_rate;
EGLBoolean CHROMIUM_sync_control;
EGLBoolean EXT_buffer_age;
EGLBoolean EXT_config_select_group;
EGLBoolean EXT_create_context_robustness;
EGLBoolean EXT_image_dma_buf_import;
EGLBoolean EXT_image_dma_buf_import_modifiers;
EGLBoolean EXT_pixel_format_float;
EGLBoolean EXT_present_opaque;
EGLBoolean EXT_protected_content;
EGLBoolean EXT_protected_surface;
EGLBoolean EXT_query_reset_notification_strategy;
EGLBoolean EXT_surface_compression;
EGLBoolean EXT_surface_CTA861_3_metadata;
EGLBoolean EXT_surface_SMPTE2086_metadata;
EGLBoolean EXT_swap_buffers_with_damage;
unsigned int IMG_context_priority;
#define __EGL_CONTEXT_PRIORITY_LOW_BIT 0
#define __EGL_CONTEXT_PRIORITY_MEDIUM_BIT 1
#define __EGL_CONTEXT_PRIORITY_HIGH_BIT 2
#define __EGL_CONTEXT_PRIORITY_REALTIME_BIT 3
EGLBoolean KHR_cl_event2;
EGLBoolean KHR_config_attribs;
EGLBoolean KHR_context_flush_control;
EGLBoolean KHR_create_context;
EGLBoolean KHR_create_context_no_error;
EGLBoolean KHR_fence_sync;
EGLBoolean KHR_get_all_proc_addresses;
EGLBoolean KHR_gl_colorspace;
EGLBoolean KHR_gl_renderbuffer_image;
EGLBoolean KHR_gl_texture_2D_image;
EGLBoolean KHR_gl_texture_3D_image;
EGLBoolean KHR_gl_texture_cubemap_image;
EGLBoolean KHR_image;
EGLBoolean KHR_image_base;
EGLBoolean KHR_image_pixmap;
EGLBoolean KHR_mutable_render_buffer;
EGLBoolean KHR_no_config_context;
EGLBoolean KHR_partial_update;
EGLBoolean KHR_reusable_sync;
EGLBoolean KHR_surfaceless_context;
EGLBoolean KHR_wait_sync;
EGLBoolean MESA_gl_interop;
EGLBoolean MESA_image_dma_buf_export;
EGLBoolean MESA_query_driver;
EGLBoolean MESA_x11_native_visual_id;
EGLBoolean NOK_texture_from_pixmap;
EGLBoolean NV_context_priority_realtime;
EGLBoolean WL_bind_wayland_display;
EGLBoolean WL_create_wayland_buffer_from_image;
};
struct _egl_display {
/* used to link displays */
_EGLDisplay *Next;
/**
* The big-display-lock (BDL) which protects our internal state. EGL
* drivers should use their own locking, as needed, to protect their
* own state, rather than relying on this.
*/
simple_mtx_t Mutex;
/**
* The spec appears to allow eglTerminate() to race with more or less
* any other egl call. To allow for this, while relaxing the BDL to
* allow other egl calls to happen in parallel, a rwlock is used. All
* points where the BDL lock is acquired also acquire TerminateLock
* for reading, while eglTerminate() itself acquires the TerminateLock
* for writing.
*
* Note, we could conceivably just replace the BDL with a single
* rwlock. But there are a couple shortcomings of u_rwlock:
*
* 1) The WIN32 implementation does not allow promoting a read-
* lock to write-lock, nor recursive locking, whereas the
* pthread based implementation does. Because of this, it
* would be difficult to keep the eglapi layer portable if
* we depended on any less-than-trivial rwlock usage.
*
* 2) We'd lose simple_mtx_assert_locked().
*/
struct u_rwlock TerminateLock;
_EGLPlatformType Platform; /**< The type of the platform display */
void *PlatformDisplay; /**< A pointer to the platform display */
_EGLDevice *Device; /**< Device backing the display */
const _EGLDriver *Driver; /**< Matched driver of the display */
EGLBoolean Initialized; /**< True if the display is initialized */
/* options that affect how the driver initializes the display */
struct {
EGLBoolean Zink; /**< Use kopper only */
EGLBoolean ForceSoftware; /**< Use software path only */
EGLBoolean GalliumHudWarn; /**< Using hud, warn when querying buffer age */
EGLAttrib *Attribs; /**< Platform-specific options */
int fd; /**< Platform device specific, local fd */
} Options;
/* these fields are set by the driver during init */
void *DriverData; /**< Driver private data */
EGLint Version; /**< EGL version major*10+minor */
EGLint ClientAPIs; /**< Bitmask of APIs supported (EGL_xxx_BIT) */
_EGLExtensions Extensions; /**< Extensions supported */
EGLBoolean RobustBufferAccess; /**< Supports robust buffer access behavior */
/* these fields are derived from above */
char VersionString[100]; /**< EGL_VERSION */
char ClientAPIsString[100]; /**< EGL_CLIENT_APIS */
char ExtensionsString[_EGL_MAX_EXTENSIONS_LEN]; /**< EGL_EXTENSIONS */
_EGLArray *Configs;
/* lists of resources */
_EGLResource *ResourceLists[_EGL_NUM_RESOURCES];
EGLLabelKHR Label;
EGLSetBlobFuncANDROID BlobCacheSet;
EGLGetBlobFuncANDROID BlobCacheGet;
};
extern _EGLDisplay *
_eglLockDisplay(EGLDisplay dpy);
extern void
_eglUnlockDisplay(_EGLDisplay *disp);
extern _EGLPlatformType
_eglGetNativePlatform(void *nativeDisplay);
extern void
_eglFiniDisplay(void);
extern _EGLDisplay *
_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy, const EGLAttrib *attr);
extern void
_eglReleaseDisplayResources(_EGLDisplay *disp);
extern void
_eglCleanupDisplay(_EGLDisplay *disp);
extern EGLBoolean
_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp);
/**
* Return the handle of a linked display, or EGL_NO_DISPLAY.
*/
static inline EGLDisplay
_eglGetDisplayHandle(_EGLDisplay *disp)
{
return (EGLDisplay)((disp) ? disp : EGL_NO_DISPLAY);
}
static inline EGLBoolean
_eglHasAttrib(_EGLDisplay *disp, EGLAttrib attrib)
{
EGLAttrib *attribs = disp->Options.Attribs;
if (!attribs) {
return EGL_FALSE;
}
for (int i = 0; attribs[i] != EGL_NONE; i += 2) {
if (attrib == attribs[i]) {
return EGL_TRUE;
}
}
return EGL_FALSE;
}
extern void
_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp);
extern void
_eglGetResource(_EGLResource *res);
extern EGLBoolean
_eglPutResource(_EGLResource *res);
extern void
_eglLinkResource(_EGLResource *res, _EGLResourceType type);
extern void
_eglUnlinkResource(_EGLResource *res, _EGLResourceType type);
/**
* Return true if the resource is linked.
*/
static inline EGLBoolean
_eglIsResourceLinked(_EGLResource *res)
{
return res->IsLinked;
}
static inline size_t
_eglNumAttribs(const EGLAttrib *attribs)
{
size_t len = 0;
if (attribs) {
while (attribs[len] != EGL_NONE)
len += 2;
len++;
}
return len;
}
#ifdef HAVE_X11_PLATFORM
_EGLDisplay *
_eglGetX11Display(Display *native_display, const EGLAttrib *attrib_list);
#endif
#ifdef HAVE_XCB_PLATFORM
typedef struct xcb_connection_t xcb_connection_t;
_EGLDisplay *
_eglGetXcbDisplay(xcb_connection_t *native_display,
const EGLAttrib *attrib_list);
#endif
#ifdef HAVE_DRM_PLATFORM
struct gbm_device;
_EGLDisplay *
_eglGetGbmDisplay(struct gbm_device *native_display,
const EGLAttrib *attrib_list);
#endif
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_display;
_EGLDisplay *
_eglGetWaylandDisplay(struct wl_display *native_display,
const EGLAttrib *attrib_list);
#endif
_EGLDisplay *
_eglGetSurfacelessDisplay(void *native_display, const EGLAttrib *attrib_list);
#ifdef HAVE_ANDROID_PLATFORM
_EGLDisplay *
_eglGetAndroidDisplay(void *native_display, const EGLAttrib *attrib_list);
#endif
_EGLDisplay *
_eglGetDeviceDisplay(void *native_display, const EGLAttrib *attrib_list);
#ifdef __cplusplus
}
#endif
#endif /* EGLDISPLAY_INCLUDED */
+246
View File
@@ -0,0 +1,246 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLDRIVER_INCLUDED
#define EGLDRIVER_INCLUDED
#include <stdbool.h>
#include <stddef.h>
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Define an inline driver typecast function.
*
* Note that this macro defines a function and should not be ended with a
* semicolon when used.
*/
#define _EGL_DRIVER_TYPECAST(drvtype, egltype, code) \
static inline struct drvtype *drvtype(const egltype *obj) \
{ \
return (struct drvtype *)code; \
}
/**
* Define the driver typecast functions for _EGLDisplay,
* _EGLContext, _EGLSurface, and _EGLConfig.
*
* Note that this macro defines several functions and should not be ended with
* a semicolon when used.
*/
#define _EGL_DRIVER_STANDARD_TYPECASTS(drvname) \
/* note that this is not a direct cast */ \
_EGL_DRIVER_TYPECAST(drvname##_display, _EGLDisplay, obj->DriverData) \
_EGL_DRIVER_TYPECAST(drvname##_context, _EGLContext, obj) \
_EGL_DRIVER_TYPECAST(drvname##_surface, _EGLSurface, obj) \
_EGL_DRIVER_TYPECAST(drvname##_config, _EGLConfig, obj)
/**
* A generic function ptr type
*/
typedef void (*_EGLProc)(void);
struct wl_display;
struct mesa_glinterop_device_info;
struct mesa_glinterop_export_in;
struct mesa_glinterop_export_out;
struct mesa_glinterop_flush_out;
typedef struct __GLsync *GLsync;
#define EGL_UUID_SIZE 16
/**
* For use in EGL_EXT_device_query_name and EGL_EXT_device_persistent_id
*/
struct egl_device_info {
uint8_t device_uuid[EGL_UUID_SIZE];
uint8_t driver_uuid[EGL_UUID_SIZE];
/* Data below needs to be freed manually */
char *vendor_name;
char *renderer_name;
char *driver_name;
};
/**
* The API dispatcher jumps through these functions
*/
struct _egl_driver {
/* driver funcs */
EGLBoolean (*Initialize)(_EGLDisplay *disp);
EGLBoolean (*Terminate)(_EGLDisplay *disp);
/* context funcs */
_EGLContext *(*CreateContext)(_EGLDisplay *disp, _EGLConfig *config,
_EGLContext *share_list,
const EGLint *attrib_list);
EGLBoolean (*DestroyContext)(_EGLDisplay *disp, _EGLContext *ctx);
/* this is the only function (other than Initialize) that may be called
* with an uninitialized display
*/
EGLBoolean (*MakeCurrent)(_EGLDisplay *disp, _EGLSurface *draw,
_EGLSurface *read, _EGLContext *ctx);
/* surface funcs */
_EGLSurface *(*CreateWindowSurface)(_EGLDisplay *disp, _EGLConfig *config,
void *native_window,
const EGLint *attrib_list);
_EGLSurface *(*CreatePixmapSurface)(_EGLDisplay *disp, _EGLConfig *config,
void *native_pixmap,
const EGLint *attrib_list);
_EGLSurface *(*CreatePbufferSurface)(_EGLDisplay *disp, _EGLConfig *config,
const EGLint *attrib_list);
EGLBoolean (*DestroySurface)(_EGLDisplay *disp, _EGLSurface *surface);
EGLBoolean (*QuerySurface)(_EGLDisplay *disp, _EGLSurface *surface,
EGLint attribute, EGLint *value);
EGLBoolean (*BindTexImage)(_EGLDisplay *disp, _EGLSurface *surface,
EGLint buffer);
EGLBoolean (*ReleaseTexImage)(_EGLDisplay *disp, _EGLSurface *surface,
EGLint buffer);
EGLBoolean (*SwapInterval)(_EGLDisplay *disp, _EGLSurface *surf,
EGLint interval);
EGLBoolean (*SwapBuffers)(_EGLDisplay *disp, _EGLSurface *draw);
EGLBoolean (*CopyBuffers)(_EGLDisplay *disp, _EGLSurface *surface,
void *native_pixmap_target);
/* for EGL_KHR_partial_update */
EGLBoolean (*SetDamageRegion)(_EGLDisplay *disp, _EGLSurface *surface,
EGLint *rects, EGLint n_rects);
/* misc functions */
EGLBoolean (*WaitClient)(_EGLDisplay *disp, _EGLContext *ctx);
EGLBoolean (*WaitNative)(EGLint engine);
/* for EGL_KHR_image_base */
_EGLImage *(*CreateImageKHR)(_EGLDisplay *disp, _EGLContext *ctx,
EGLenum target, EGLClientBuffer buffer,
const EGLint *attr_list);
EGLBoolean (*DestroyImageKHR)(_EGLDisplay *disp, _EGLImage *image);
/* for EGL_KHR_reusable_sync/EGL_KHR_fence_sync */
_EGLSync *(*CreateSyncKHR)(_EGLDisplay *disp, EGLenum type,
const EGLAttrib *attrib_list);
EGLBoolean (*DestroySyncKHR)(_EGLDisplay *disp, _EGLSync *sync);
EGLint (*ClientWaitSyncKHR)(_EGLDisplay *disp, _EGLSync *sync, EGLint flags,
EGLTime timeout);
EGLint (*WaitSyncKHR)(_EGLDisplay *disp, _EGLSync *sync);
/* for EGL_KHR_reusable_sync */
EGLBoolean (*SignalSyncKHR)(_EGLDisplay *disp, _EGLSync *sync, EGLenum mode);
/* for EGL_ANDROID_native_fence_sync */
EGLint (*DupNativeFenceFDANDROID)(_EGLDisplay *disp, _EGLSync *sync);
#ifdef HAVE_BIND_WL_DISPLAY
/* for EGL_WL_bind_wayland_display */
EGLBoolean (*BindWaylandDisplayWL)(_EGLDisplay *disp,
struct wl_display *display);
EGLBoolean (*UnbindWaylandDisplayWL)(_EGLDisplay *disp,
struct wl_display *display);
EGLBoolean (*QueryWaylandBufferWL)(_EGLDisplay *displ,
struct wl_resource *buffer,
EGLint attribute, EGLint *value);
/* for EGL_WL_create_wayland_buffer_from_image */
struct wl_buffer *(*CreateWaylandBufferFromImageWL)(_EGLDisplay *disp,
_EGLImage *img);
#endif
/* for EGL_EXT_swap_buffers_with_damage */
EGLBoolean (*SwapBuffersWithDamageEXT)(_EGLDisplay *disp,
_EGLSurface *surface,
const EGLint *rects, EGLint n_rects);
/* for EGL_EXT_buffer_age/EGL_KHR_partial_update */
EGLint (*QueryBufferAge)(_EGLDisplay *disp, _EGLSurface *surface);
/* for EGL_CHROMIUM_sync_control */
EGLBoolean (*GetSyncValuesCHROMIUM)(_EGLDisplay *disp, _EGLSurface *surface,
EGLuint64KHR *ust, EGLuint64KHR *msc,
EGLuint64KHR *sbc);
EGLBoolean (*GetMscRateANGLE)(_EGLDisplay *disp, _EGLSurface *surface,
EGLint *numerator, EGLint *denominator);
/* for EGL_MESA_image_dma_buf_export */
EGLBoolean (*ExportDMABUFImageQueryMESA)(_EGLDisplay *disp, _EGLImage *img,
EGLint *fourcc, EGLint *nplanes,
EGLuint64KHR *modifiers);
EGLBoolean (*ExportDMABUFImageMESA)(_EGLDisplay *disp, _EGLImage *img,
EGLint *fds, EGLint *strides,
EGLint *offsets);
/* for EGL_MESA_query_driver */
const char *(*QueryDriverName)(_EGLDisplay *disp);
char *(*QueryDriverConfig)(_EGLDisplay *disp);
/* for EGL_EXT_device_query_name and EGL_EXT_device_persistent_id */
bool (*QueryDeviceInfo)(const void* driver_device_identifier,
struct egl_device_info *device_info);
/* for OpenGL-OpenCL interop; see include/GL/mesa_glinterop.h */
int (*GLInteropQueryDeviceInfo)(_EGLDisplay *disp, _EGLContext *ctx,
struct mesa_glinterop_device_info *out);
int (*GLInteropExportObject)(_EGLDisplay *disp, _EGLContext *ctx,
struct mesa_glinterop_export_in *in,
struct mesa_glinterop_export_out *out);
int (*GLInteropFlushObjects)(_EGLDisplay *disp, _EGLContext *ctx,
unsigned count,
struct mesa_glinterop_export_in *in,
struct mesa_glinterop_flush_out *out);
/* for EGL_EXT_image_dma_buf_import_modifiers */
EGLBoolean (*QueryDmaBufFormatsEXT)(_EGLDisplay *disp, EGLint max_formats,
EGLint *formats, EGLint *num_formats);
EGLBoolean (*QueryDmaBufModifiersEXT)(_EGLDisplay *disp, EGLint format,
EGLint max_modifiers,
EGLuint64KHR *modifiers,
EGLBoolean *external_only,
EGLint *num_modifiers);
/* for EGL_ANDROID_blob_cache */
void (*SetBlobCacheFuncsANDROID)(_EGLDisplay *disp,
EGLSetBlobFuncANDROID set,
EGLGetBlobFuncANDROID get);
/* for EGL_EXT_surface_compression */
EGLBoolean (*QuerySupportedCompressionRatesEXT)(_EGLDisplay *disp,
_EGLConfig *config,
const EGLAttrib *attr_list,
EGLint *rates,
EGLint rate_size,
EGLint *num_rates);
};
#ifdef __cplusplus
}
#endif
#endif /* EGLDRIVER_INCLUDED */
+98
View File
@@ -0,0 +1,98 @@
/* core functions queryable in the presence of
* EGL_KHR_get_all_proc_addresses or EGL 1.5
*/
/* clang-format off */
/* alphabetical order */
EGL_ENTRYPOINT(eglBindAPI)
EGL_ENTRYPOINT(eglBindTexImage)
#ifdef HAVE_BIND_WL_DISPLAY
EGL_ENTRYPOINT(eglBindWaylandDisplayWL)
#endif
EGL_ENTRYPOINT(eglChooseConfig)
EGL_ENTRYPOINT(eglClientWaitSync)
EGL_ENTRYPOINT(eglClientWaitSyncKHR)
EGL_ENTRYPOINT(eglCopyBuffers)
EGL_ENTRYPOINT(eglCreateContext)
EGL_ENTRYPOINT(eglCreateImage)
EGL_ENTRYPOINT(eglCreateImageKHR)
EGL_ENTRYPOINT(eglCreatePbufferFromClientBuffer)
EGL_ENTRYPOINT(eglCreatePbufferSurface)
EGL_ENTRYPOINT(eglCreatePixmapSurface)
EGL_ENTRYPOINT(eglCreatePlatformPixmapSurface)
EGL_ENTRYPOINT(eglCreatePlatformPixmapSurfaceEXT)
EGL_ENTRYPOINT(eglCreatePlatformWindowSurface)
EGL_ENTRYPOINT(eglCreatePlatformWindowSurfaceEXT)
EGL_ENTRYPOINT(eglCreateSync)
EGL_ENTRYPOINT(eglCreateSync64KHR)
EGL_ENTRYPOINT(eglCreateSyncKHR)
#ifdef HAVE_BIND_WL_DISPLAY
EGL_ENTRYPOINT(eglCreateWaylandBufferFromImageWL)
#endif
EGL_ENTRYPOINT(eglCreateWindowSurface)
EGL_ENTRYPOINT(eglDebugMessageControlKHR)
EGL_ENTRYPOINT(eglDestroyContext)
EGL_ENTRYPOINT(eglDestroyImage)
EGL_ENTRYPOINT(eglDestroyImageKHR)
EGL_ENTRYPOINT(eglDestroySurface)
EGL_ENTRYPOINT(eglDestroySync)
EGL_ENTRYPOINT(eglDestroySyncKHR)
EGL_ENTRYPOINT(eglDupNativeFenceFDANDROID)
EGL_ENTRYPOINT(eglExportDMABUFImageMESA)
EGL_ENTRYPOINT(eglExportDMABUFImageQueryMESA)
EGL_ENTRYPOINT2(eglGLInteropExportObjectMESA, MesaGLInteropEGLExportObject)
EGL_ENTRYPOINT2(eglGLInteropFlushObjectsMESA, MesaGLInteropEGLFlushObjects)
EGL_ENTRYPOINT2(eglGLInteropQueryDeviceInfoMESA, MesaGLInteropEGLQueryDeviceInfo)
EGL_ENTRYPOINT(eglGetConfigAttrib)
EGL_ENTRYPOINT(eglGetConfigs)
EGL_ENTRYPOINT(eglGetCurrentContext)
EGL_ENTRYPOINT(eglGetCurrentDisplay)
EGL_ENTRYPOINT(eglGetCurrentSurface)
EGL_ENTRYPOINT(eglGetDisplay)
EGL_ENTRYPOINT(eglGetDisplayDriverConfig)
EGL_ENTRYPOINT(eglGetDisplayDriverName)
EGL_ENTRYPOINT(eglGetError)
EGL_ENTRYPOINT(eglGetMscRateANGLE)
EGL_ENTRYPOINT(eglGetPlatformDisplay)
EGL_ENTRYPOINT(eglGetPlatformDisplayEXT)
EGL_ENTRYPOINT(eglGetProcAddress)
EGL_ENTRYPOINT(eglGetSyncAttrib)
EGL_ENTRYPOINT(eglGetSyncAttribKHR)
EGL_ENTRYPOINT(eglGetSyncValuesCHROMIUM)
EGL_ENTRYPOINT(eglInitialize)
EGL_ENTRYPOINT(eglLabelObjectKHR)
EGL_ENTRYPOINT(eglMakeCurrent)
EGL_ENTRYPOINT(eglQueryAPI)
EGL_ENTRYPOINT(eglQueryContext)
EGL_ENTRYPOINT(eglQueryDebugKHR)
EGL_ENTRYPOINT(eglQueryDeviceAttribEXT)
EGL_ENTRYPOINT(eglQueryDeviceBinaryEXT)
EGL_ENTRYPOINT(eglQueryDeviceStringEXT)
EGL_ENTRYPOINT(eglQueryDevicesEXT)
EGL_ENTRYPOINT(eglQueryDisplayAttribEXT)
EGL_ENTRYPOINT(eglQueryDmaBufFormatsEXT)
EGL_ENTRYPOINT(eglQueryDmaBufModifiersEXT)
EGL_ENTRYPOINT(eglQueryString)
EGL_ENTRYPOINT(eglQuerySupportedCompressionRatesEXT)
EGL_ENTRYPOINT(eglQuerySurface)
#ifdef HAVE_BIND_WL_DISPLAY
EGL_ENTRYPOINT(eglQueryWaylandBufferWL)
#endif
EGL_ENTRYPOINT(eglReleaseTexImage)
EGL_ENTRYPOINT(eglReleaseThread)
EGL_ENTRYPOINT(eglSetBlobCacheFuncsANDROID)
EGL_ENTRYPOINT(eglSetDamageRegionKHR)
EGL_ENTRYPOINT(eglSignalSyncKHR)
EGL_ENTRYPOINT(eglSurfaceAttrib)
EGL_ENTRYPOINT(eglSwapBuffers)
EGL_ENTRYPOINT(eglSwapBuffersWithDamageEXT)
EGL_ENTRYPOINT(eglSwapBuffersWithDamageKHR)
EGL_ENTRYPOINT(eglSwapInterval)
EGL_ENTRYPOINT(eglTerminate)
#ifdef HAVE_BIND_WL_DISPLAY
EGL_ENTRYPOINT(eglUnbindWaylandDisplayWL)
#endif
EGL_ENTRYPOINT(eglWaitClient)
EGL_ENTRYPOINT(eglWaitGL)
EGL_ENTRYPOINT(eglWaitNative)
EGL_ENTRYPOINT(eglWaitSync)
EGL_ENTRYPOINT(eglWaitSyncKHR)
+163
View File
@@ -0,0 +1,163 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util/simple_mtx.h"
#include "egldevice.h"
#include "egldisplay.h"
#include "eglglobals.h"
#include "util/macros.h"
#include "util/os_misc.h"
#ifdef HAVE_MINCORE
#include <unistd.h>
#include <sys/mman.h>
#endif
static simple_mtx_t _eglGlobalMutex = SIMPLE_MTX_INITIALIZER;
struct _egl_global _eglGlobal = {
.Mutex = &_eglGlobalMutex,
.DisplayList = NULL,
.DeviceList = &_eglSoftwareDevice,
#if USE_LIBGLVND
.ClientOnlyExtensionString =
#else
.ClientExtensionString =
#endif
"EGL_EXT_client_extensions"
#if !DETECT_OS_WINDOWS
" EGL_EXT_device_base"
" EGL_EXT_device_enumeration"
" EGL_EXT_device_query"
#endif
" EGL_EXT_platform_base"
" EGL_KHR_client_get_all_proc_addresses"
" EGL_KHR_debug"
#if USE_LIBGLVND
,
.PlatformExtensionString =
#else
" "
#endif
#if !DETECT_OS_WINDOWS
"EGL_EXT_platform_device"
" EGL_EXT_explicit_device"
#endif
#ifdef HAVE_WAYLAND_PLATFORM
" EGL_EXT_platform_wayland"
" EGL_KHR_platform_wayland"
#endif
#ifdef HAVE_X11_PLATFORM
" EGL_EXT_platform_x11"
" EGL_KHR_platform_x11"
#endif
#ifdef HAVE_XCB_PLATFORM
" EGL_EXT_platform_xcb"
#endif
#ifdef HAVE_DRM_PLATFORM
" EGL_MESA_platform_gbm"
" EGL_KHR_platform_gbm"
#endif
" EGL_MESA_platform_surfaceless"
"",
.debugCallback = NULL,
.debugTypesEnabled = _EGL_DEBUG_BIT_CRITICAL | _EGL_DEBUG_BIT_ERROR,
};
static void
_eglAtExit(void)
{
_eglFiniDisplay();
_eglFiniDevice(); /* always called last */
}
void
_eglRegisterAtExit(void)
{
static EGLBoolean registered = EGL_FALSE;
simple_mtx_lock(_eglGlobal.Mutex);
if (!registered) {
atexit(_eglAtExit);
registered = EGL_TRUE;
}
simple_mtx_unlock(_eglGlobal.Mutex);
}
EGLBoolean
_eglPointerIsDereferenceable(void *p)
{
uintptr_t addr = (uintptr_t)p;
uint64_t page_size = 0;
os_get_page_size(&page_size);
#ifdef HAVE_MINCORE
unsigned char valid = 0;
if (p == NULL)
return EGL_FALSE;
/* align addr to page_size */
addr &= ~(page_size - 1);
/* mincore expects &valid to be unsigned char* on Linux but char* on BSD:
* we cast pointers to void, to fix type mismatch warnings in all systems
*/
if (mincore((void *)addr, page_size, (void *)&valid) < 0) {
return EGL_FALSE;
}
/* mincore() returns 0 on success, and -1 on failure. The last parameter
* is a vector of bytes with one entry for each page queried. mincore
* returns page residency information in the first bit of each byte in the
* vector.
*
* Residency doesn't actually matter when determining whether a pointer is
* dereferenceable, so the output vector can be ignored. What matters is
* whether mincore succeeds. See:
*
* http://man7.org/linux/man-pages/man2/mincore.2.html
*/
return EGL_TRUE;
#else
// Without mincore(), we just assume that the first page is unmapped.
return addr >= page_size;
#endif
}
+93
View File
@@ -0,0 +1,93 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLGLOBALS_INCLUDED
#define EGLGLOBALS_INCLUDED
#include <stdbool.h>
#include "util/simple_mtx.h"
#include "egltypedefs.h"
enum {
_EGL_DEBUG_BIT_CRITICAL = 0x1,
_EGL_DEBUG_BIT_ERROR = 0x2,
_EGL_DEBUG_BIT_WARN = 0x4,
_EGL_DEBUG_BIT_INFO = 0x8,
};
/**
* Global library data
*/
struct _egl_global {
simple_mtx_t *Mutex;
/* the list of all displays */
_EGLDisplay *DisplayList;
_EGLDevice *DeviceList;
/*
* Under libglvnd, the client extension string has to be split into two
* strings, one for platform extensions, and one for everything else.
* For a non-glvnd build create a concatenated one.
*/
#if USE_LIBGLVND
const char *ClientOnlyExtensionString;
const char *PlatformExtensionString;
#else
const char *ClientExtensionString;
#endif
EGLDEBUGPROCKHR debugCallback;
unsigned int debugTypesEnabled;
};
extern struct _egl_global _eglGlobal;
extern void
_eglRegisterAtExit(void);
extern void
_eglAddAtExitCall(void (*func)(void));
static inline unsigned int
DebugBitFromType(EGLenum type)
{
assert(type >= EGL_DEBUG_MSG_CRITICAL_KHR && type <= EGL_DEBUG_MSG_INFO_KHR);
return (1 << (type - EGL_DEBUG_MSG_CRITICAL_KHR));
}
/**
* Perform validity checks on a generic pointer.
*/
extern EGLBoolean
_eglPointerIsDereferenceable(void *p);
#endif /* EGLGLOBALS_INCLUDED */
+101
View File
@@ -0,0 +1,101 @@
/*
* (C) Copyright 2016, NVIDIA CORPORATION.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Kyle Brenneman <[email protected]>
*/
#include <assert.h>
#include <string.h>
#include <glvnd/libeglabi.h>
#include "eglcurrent.h"
#include "egldispatchstubs.h"
#include "eglglobals.h"
static const __EGLapiExports *__eglGLVNDApiExports = NULL;
static const char *EGLAPIENTRY
__eglGLVNDQueryString(EGLDisplay dpy, EGLenum name)
{
// For client extensions, return the list of non-platform extensions. The
// platform extensions are returned by __eglGLVNDGetVendorString.
if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
return _eglGlobal.ClientOnlyExtensionString;
// For everything else, forward to the normal eglQueryString function.
return eglQueryString(dpy, name);
}
static const char *
__eglGLVNDGetVendorString(int name)
{
if (name == __EGL_VENDOR_STRING_PLATFORM_EXTENSIONS)
return _eglGlobal.PlatformExtensionString;
return NULL;
}
static EGLDisplay
__eglGLVNDGetPlatformDisplay(EGLenum platform, void *native_display,
const EGLAttrib *attrib_list)
{
if (platform == EGL_NONE) {
assert(native_display == (void *)EGL_DEFAULT_DISPLAY);
assert(attrib_list == NULL);
return eglGetDisplay((EGLNativeDisplayType)native_display);
} else {
return eglGetPlatformDisplay(platform, native_display, attrib_list);
}
}
static void *
__eglGLVNDGetProcAddress(const char *procName)
{
if (strcmp(procName, "eglQueryString") == 0)
return (void *)__eglGLVNDQueryString;
return (void *)eglGetProcAddress(procName);
}
PUBLIC EGLAPI EGLBoolean
__egl_Main(uint32_t version, const __EGLapiExports *exports,
__EGLvendorInfo *vendor, __EGLapiImports *imports)
{
if (EGL_VENDOR_ABI_GET_MAJOR_VERSION(version) !=
EGL_VENDOR_ABI_MAJOR_VERSION)
return EGL_FALSE;
__eglGLVNDApiExports = exports;
__eglInitDispatchStubs(exports);
imports->getPlatformDisplay = __eglGLVNDGetPlatformDisplay;
imports->getSupportsAPI = _eglIsApiValid;
imports->getVendorString = __eglGLVNDGetVendorString;
imports->getProcAddress = __eglGLVNDGetProcAddress;
imports->getDispatchAddress = __eglDispatchFindDispatchFunction;
imports->setDispatchIndex = __eglSetDispatchIndex;
return EGL_TRUE;
}
+297
View File
@@ -0,0 +1,297 @@
/**************************************************************************
*
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <assert.h>
#include <string.h>
#include "eglcurrent.h"
#include "eglimage.h"
#include "egllog.h"
static EGLint
_eglParseKHRImageAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
EGLint attr, EGLint val)
{
switch (attr) {
case EGL_IMAGE_PRESERVED_KHR:
if (!disp->Extensions.KHR_image_base)
return EGL_BAD_PARAMETER;
attrs->ImagePreserved = val;
break;
case EGL_GL_TEXTURE_LEVEL_KHR:
if (!disp->Extensions.KHR_gl_texture_2D_image)
return EGL_BAD_PARAMETER;
attrs->GLTextureLevel = val;
break;
case EGL_GL_TEXTURE_ZOFFSET_KHR:
if (!disp->Extensions.KHR_gl_texture_3D_image)
return EGL_BAD_PARAMETER;
attrs->GLTextureZOffset = val;
break;
case EGL_PROTECTED_CONTENT_EXT:
if (!disp->Extensions.EXT_protected_content &&
!disp->Extensions.EXT_protected_surface)
return EGL_BAD_PARAMETER;
attrs->ProtectedContent = val;
break;
default:
return EGL_BAD_PARAMETER;
}
return EGL_SUCCESS;
}
#ifdef HAVE_BIND_WL_DISPLAY
static EGLint
_eglParseWLBindWaylandDisplayAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
EGLint attr, EGLint val)
{
if (!disp->Extensions.WL_bind_wayland_display)
return EGL_BAD_PARAMETER;
switch (attr) {
case EGL_WAYLAND_PLANE_WL:
attrs->PlaneWL = val;
break;
default:
return EGL_BAD_PARAMETER;
}
return EGL_SUCCESS;
}
#endif
static EGLint
_eglParseEXTImageDmaBufImportAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
EGLint attr, EGLint val)
{
if (!disp->Extensions.EXT_image_dma_buf_import)
return EGL_BAD_PARAMETER;
switch (attr) {
case EGL_WIDTH:
attrs->Width = val;
break;
case EGL_HEIGHT:
attrs->Height = val;
break;
case EGL_LINUX_DRM_FOURCC_EXT:
attrs->DMABufFourCC.Value = val;
attrs->DMABufFourCC.IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE0_FD_EXT:
attrs->DMABufPlaneFds[0].Value = val;
attrs->DMABufPlaneFds[0].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE0_OFFSET_EXT:
attrs->DMABufPlaneOffsets[0].Value = val;
attrs->DMABufPlaneOffsets[0].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE0_PITCH_EXT:
attrs->DMABufPlanePitches[0].Value = val;
attrs->DMABufPlanePitches[0].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE1_FD_EXT:
attrs->DMABufPlaneFds[1].Value = val;
attrs->DMABufPlaneFds[1].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE1_OFFSET_EXT:
attrs->DMABufPlaneOffsets[1].Value = val;
attrs->DMABufPlaneOffsets[1].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE1_PITCH_EXT:
attrs->DMABufPlanePitches[1].Value = val;
attrs->DMABufPlanePitches[1].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE2_FD_EXT:
attrs->DMABufPlaneFds[2].Value = val;
attrs->DMABufPlaneFds[2].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE2_OFFSET_EXT:
attrs->DMABufPlaneOffsets[2].Value = val;
attrs->DMABufPlaneOffsets[2].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE2_PITCH_EXT:
attrs->DMABufPlanePitches[2].Value = val;
attrs->DMABufPlanePitches[2].IsPresent = EGL_TRUE;
break;
case EGL_YUV_COLOR_SPACE_HINT_EXT:
if (val != EGL_ITU_REC601_EXT && val != EGL_ITU_REC709_EXT &&
val != EGL_ITU_REC2020_EXT)
return EGL_BAD_ATTRIBUTE;
attrs->DMABufYuvColorSpaceHint.Value = val;
attrs->DMABufYuvColorSpaceHint.IsPresent = EGL_TRUE;
break;
case EGL_SAMPLE_RANGE_HINT_EXT:
if (val != EGL_YUV_FULL_RANGE_EXT && val != EGL_YUV_NARROW_RANGE_EXT)
return EGL_BAD_ATTRIBUTE;
attrs->DMABufSampleRangeHint.Value = val;
attrs->DMABufSampleRangeHint.IsPresent = EGL_TRUE;
break;
case EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT:
if (val != EGL_YUV_CHROMA_SITING_0_EXT &&
val != EGL_YUV_CHROMA_SITING_0_5_EXT)
return EGL_BAD_ATTRIBUTE;
attrs->DMABufChromaHorizontalSiting.Value = val;
attrs->DMABufChromaHorizontalSiting.IsPresent = EGL_TRUE;
break;
case EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT:
if (val != EGL_YUV_CHROMA_SITING_0_EXT &&
val != EGL_YUV_CHROMA_SITING_0_5_EXT)
return EGL_BAD_ATTRIBUTE;
attrs->DMABufChromaVerticalSiting.Value = val;
attrs->DMABufChromaVerticalSiting.IsPresent = EGL_TRUE;
break;
default:
return EGL_BAD_PARAMETER;
}
return EGL_SUCCESS;
}
static EGLint
_eglParseEXTImageDmaBufImportModifiersAttribs(_EGLImageAttribs *attrs,
_EGLDisplay *disp, EGLint attr,
EGLint val)
{
if (!disp->Extensions.EXT_image_dma_buf_import_modifiers)
return EGL_BAD_PARAMETER;
switch (attr) {
case EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT:
attrs->DMABufPlaneModifiersLo[0].Value = val;
attrs->DMABufPlaneModifiersLo[0].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT:
attrs->DMABufPlaneModifiersHi[0].Value = val;
attrs->DMABufPlaneModifiersHi[0].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT:
attrs->DMABufPlaneModifiersLo[1].Value = val;
attrs->DMABufPlaneModifiersLo[1].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT:
attrs->DMABufPlaneModifiersHi[1].Value = val;
attrs->DMABufPlaneModifiersHi[1].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT:
attrs->DMABufPlaneModifiersLo[2].Value = val;
attrs->DMABufPlaneModifiersLo[2].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT:
attrs->DMABufPlaneModifiersHi[2].Value = val;
attrs->DMABufPlaneModifiersHi[2].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE3_FD_EXT:
attrs->DMABufPlaneFds[3].Value = val;
attrs->DMABufPlaneFds[3].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE3_OFFSET_EXT:
attrs->DMABufPlaneOffsets[3].Value = val;
attrs->DMABufPlaneOffsets[3].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE3_PITCH_EXT:
attrs->DMABufPlanePitches[3].Value = val;
attrs->DMABufPlanePitches[3].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT:
attrs->DMABufPlaneModifiersLo[3].Value = val;
attrs->DMABufPlaneModifiersLo[3].IsPresent = EGL_TRUE;
break;
case EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT:
attrs->DMABufPlaneModifiersHi[3].Value = val;
attrs->DMABufPlaneModifiersHi[3].IsPresent = EGL_TRUE;
break;
default:
return EGL_BAD_PARAMETER;
}
return EGL_SUCCESS;
}
/**
* Parse the list of image attributes.
*
* Returns EGL_TRUE on success and EGL_FALSE otherwise.
* Function calls _eglError to set the correct error code.
*/
EGLBoolean
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *disp,
const EGLint *attrib_list)
{
EGLint i, err;
memset(attrs, 0, sizeof(*attrs));
if (!attrib_list)
return EGL_TRUE;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
err = _eglParseKHRImageAttribs(attrs, disp, attr, val);
if (err == EGL_SUCCESS)
continue;
#ifdef HAVE_BIND_WL_DISPLAY
err = _eglParseWLBindWaylandDisplayAttribs(attrs, disp, attr, val);
if (err == EGL_SUCCESS)
continue;
#endif
err = _eglParseEXTImageDmaBufImportAttribs(attrs, disp, attr, val);
if (err == EGL_SUCCESS)
continue;
/* EXT_image_dma_buf_import states that if invalid value is provided for
* its attributes, we should return EGL_BAD_ATTRIBUTE.
* Bail out ASAP, since follow-up calls can return another EGL_BAD error.
*/
if (err == EGL_BAD_ATTRIBUTE)
return _eglError(err, __func__);
err =
_eglParseEXTImageDmaBufImportModifiersAttribs(attrs, disp, attr, val);
if (err == EGL_SUCCESS)
continue;
return _eglError(err, __func__);
}
return EGL_TRUE;
}
+162
View File
@@ -0,0 +1,162 @@
/**************************************************************************
*
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLIMAGE_INCLUDED
#define EGLIMAGE_INCLUDED
#include "egldisplay.h"
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct _egl_image_attrib_int {
EGLint Value;
EGLBoolean IsPresent;
};
#define DMA_BUF_MAX_PLANES 4
struct _egl_image_attribs {
/* EGL_KHR_image_base */
EGLBoolean ImagePreserved;
/* EGL_KHR_gl_image */
EGLint GLTextureLevel;
EGLint GLTextureZOffset;
/* EGL_WL_bind_wayland_display */
EGLint PlaneWL;
/* EGL_EXT_image_dma_buf_import and
* EGL_EXT_image_dma_buf_import_modifiers */
EGLint Width;
EGLint Height;
struct _egl_image_attrib_int DMABufFourCC;
struct _egl_image_attrib_int DMABufPlaneFds[DMA_BUF_MAX_PLANES];
struct _egl_image_attrib_int DMABufPlaneOffsets[DMA_BUF_MAX_PLANES];
struct _egl_image_attrib_int DMABufPlanePitches[DMA_BUF_MAX_PLANES];
struct _egl_image_attrib_int DMABufPlaneModifiersLo[DMA_BUF_MAX_PLANES];
struct _egl_image_attrib_int DMABufPlaneModifiersHi[DMA_BUF_MAX_PLANES];
struct _egl_image_attrib_int DMABufYuvColorSpaceHint;
struct _egl_image_attrib_int DMABufSampleRangeHint;
struct _egl_image_attrib_int DMABufChromaHorizontalSiting;
struct _egl_image_attrib_int DMABufChromaVerticalSiting;
/* EGL_EXT_protected_content || EGL_EXT_protected_surface */
EGLBoolean ProtectedContent;
};
/**
* "Base" class for device driver images.
*/
struct _egl_image {
/* An image is a display resource */
_EGLResource Resource;
};
EGLBoolean
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *disp,
const EGLint *attrib_list);
static inline void
_eglInitImage(_EGLImage *img, _EGLDisplay *disp)
{
_eglInitResource(&img->Resource, sizeof(*img), disp);
}
/**
* Increment reference count for the image.
*/
static inline _EGLImage *
_eglGetImage(_EGLImage *img)
{
if (img)
_eglGetResource(&img->Resource);
return img;
}
/**
* Decrement reference count for the image.
*/
static inline EGLBoolean
_eglPutImage(_EGLImage *img)
{
return (img) ? _eglPutResource(&img->Resource) : EGL_FALSE;
}
/**
* Link an image to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
static inline EGLImage
_eglLinkImage(_EGLImage *img)
{
_eglLinkResource(&img->Resource, _EGL_RESOURCE_IMAGE);
return (EGLImage)img;
}
/**
* Unlink a linked image from its display.
* Accessing an unlinked image should generate EGL_BAD_PARAMETER error.
*/
static inline void
_eglUnlinkImage(_EGLImage *img)
{
_eglUnlinkResource(&img->Resource, _EGL_RESOURCE_IMAGE);
}
/**
* Lookup a handle to find the linked image.
* Return NULL if the handle has no corresponding linked image.
*/
static inline _EGLImage *
_eglLookupImage(EGLImage image, _EGLDisplay *disp)
{
_EGLImage *img = (_EGLImage *)image;
if (!disp || !_eglCheckResource((void *)img, _EGL_RESOURCE_IMAGE, disp))
img = NULL;
return img;
}
/**
* Return the handle of a linked image, or EGL_NO_IMAGE_KHR.
*/
static inline EGLImage
_eglGetImageHandle(_EGLImage *img)
{
_EGLResource *res = (_EGLResource *)img;
return (res && _eglIsResourceLinked(res)) ? (EGLImage)img : EGL_NO_IMAGE_KHR;
}
#ifdef __cplusplus
}
#endif
#endif /* EGLIMAGE_INCLUDED */
+161
View File
@@ -0,0 +1,161 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* Logging facility for debug/info messages.
* _EGL_FATAL messages are printed to stderr
* The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "c11/threads.h"
#include "util/log.h"
#include "util/macros.h"
#include "util/os_misc.h"
#include "util/simple_mtx.h"
#include "util/u_string.h"
#include "egllog.h"
#define MAXSTRING 1000
#define FALLBACK_LOG_LEVEL _EGL_WARNING
static struct {
simple_mtx_t mutex;
EGLBoolean initialized;
EGLint level;
} logging = {
.mutex = SIMPLE_MTX_INITIALIZER,
.initialized = EGL_FALSE,
.level = FALLBACK_LOG_LEVEL,
};
static const char *level_strings[] = {
[_EGL_FATAL] = "fatal",
[_EGL_WARNING] = "warning",
[_EGL_INFO] = "info",
[_EGL_DEBUG] = "debug",
};
/**
* The default logger.
*/
static void
_eglDefaultLogger(EGLint level, const char *msg)
{
static const int egl2log[] = {
[_EGL_FATAL] = MESA_LOG_ERROR,
[_EGL_WARNING] = MESA_LOG_WARN,
[_EGL_INFO] = MESA_LOG_INFO,
[_EGL_DEBUG] = MESA_LOG_DEBUG,
};
mesa_log(egl2log[level], "MESA-EGL", "%s", msg);
}
/**
* Initialize the logging facility.
*/
static void
_eglInitLogger(void)
{
const char *log_env;
EGLint i, level = -1;
if (logging.initialized)
return;
log_env = os_get_option("EGL_LOG_LEVEL");
if (log_env) {
for (i = 0; i < ARRAY_SIZE(level_strings); i++) {
if (strcasecmp(log_env, level_strings[i]) == 0) {
level = i;
break;
}
}
}
logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
logging.initialized = EGL_TRUE;
/* it is fine to call _eglLog now */
if (log_env && level < 0) {
_eglLog(_EGL_WARNING,
"Unrecognized EGL_LOG_LEVEL environment variable value. "
"Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
"Got \"%s\". Falling back to \"%s\".",
log_env, level_strings[FALLBACK_LOG_LEVEL]);
}
}
/**
* Return the log level.
*/
EGLint
_eglGetLogLevel(void)
{
return logging.level;
}
/**
* Log a message with message logger.
* \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
*/
void
_eglLog(EGLint level, const char *fmtStr, ...)
{
va_list args;
char msg[MAXSTRING];
int ret;
/* one-time initialization; a little race here is fine */
if (!logging.initialized)
_eglInitLogger();
if (level > logging.level || level < 0)
return;
simple_mtx_lock(&logging.mutex);
va_start(args, fmtStr);
ret = vsnprintf(msg, MAXSTRING, fmtStr, args);
if (ret < 0 || ret >= MAXSTRING)
strcpy(msg, "<message truncated>");
va_end(args);
_eglDefaultLogger(level, msg);
simple_mtx_unlock(&logging.mutex);
if (level == _EGL_FATAL)
exit(1); /* or abort()? */
}
+53
View File
@@ -0,0 +1,53 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLLOG_INCLUDED
#define EGLLOG_INCLUDED
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define _EGL_FATAL 0 /* unrecoverable error */
#define _EGL_WARNING 1 /* recoverable error/problem */
#define _EGL_INFO 2 /* just useful info */
#define _EGL_DEBUG 3 /* useful info for debugging */
extern EGLint
_eglGetLogLevel(void);
extern void
_eglLog(EGLint level, const char *fmtStr, ...);
#ifdef __cplusplus
}
#endif
#endif /* EGLLOG_INCLUDED */
+837
View File
@@ -0,0 +1,837 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* Surface-related functions.
*/
#include "eglsurface.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "eglconfig.h"
#include "eglcontext.h"
#include "eglcurrent.h"
#include "egldefines.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "egllog.h"
#include "util/macros.h"
/**
* Parse the list of surface attributes and return the proper error code.
*/
static EGLint
_eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
{
_EGLDisplay *disp = surf->Resource.Display;
EGLint type = surf->Type;
EGLint texture_type = EGL_PBUFFER_BIT;
EGLint i, err = EGL_SUCCESS;
EGLint attr = EGL_NONE;
EGLint val = EGL_NONE;
if (!attrib_list)
return EGL_SUCCESS;
if (disp->Extensions.NOK_texture_from_pixmap)
texture_type |= EGL_PIXMAP_BIT;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
attr = attrib_list[i++];
val = attrib_list[i];
switch (attr) {
/* common attributes */
case EGL_GL_COLORSPACE_KHR:
if (!disp->Extensions.KHR_gl_colorspace) {
err = EGL_BAD_ATTRIBUTE;
break;
}
switch (val) {
case EGL_GL_COLORSPACE_SRGB_KHR:
case EGL_GL_COLORSPACE_LINEAR_KHR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
}
if (err != EGL_SUCCESS)
break;
surf->GLColorspace = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_r.x = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_r.y = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_g.x = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_g.y = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_b.x = val;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.display_primary_b.y = val;
break;
case EGL_SMPTE2086_WHITE_POINT_X_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.white_point.x = val;
break;
case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.white_point.y = val;
break;
case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.max_luminance = val;
break;
case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
if (!disp->Extensions.EXT_surface_SMPTE2086_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.min_luminance = val;
break;
case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
if (!disp->Extensions.EXT_surface_CTA861_3_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.max_cll = val;
break;
case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
if (!disp->Extensions.EXT_surface_CTA861_3_metadata) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->HdrMetadata.max_fall = val;
break;
case EGL_VG_COLORSPACE:
switch (val) {
case EGL_VG_COLORSPACE_sRGB:
case EGL_VG_COLORSPACE_LINEAR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->VGColorspace = val;
break;
case EGL_VG_ALPHA_FORMAT:
switch (val) {
case EGL_VG_ALPHA_FORMAT_NONPRE:
case EGL_VG_ALPHA_FORMAT_PRE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->VGAlphaFormat = val;
break;
/* window surface attributes */
case EGL_RENDER_BUFFER:
if (type != EGL_WINDOW_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val != EGL_BACK_BUFFER && val != EGL_SINGLE_BUFFER) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->RequestedRenderBuffer = val;
if (surf->Config->SurfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR) {
/* Unlike normal EGLSurfaces, one with a mutable render buffer
* uses the application-chosen render buffer.
*/
surf->ActiveRenderBuffer = val;
}
break;
case EGL_PRESENT_OPAQUE_EXT:
if (!disp->Extensions.EXT_present_opaque) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (type != EGL_WINDOW_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val != EGL_TRUE && val != EGL_FALSE) {
err = EGL_BAD_PARAMETER;
break;
}
surf->PresentOpaque = val;
break;
case EGL_SURFACE_COMPRESSION_EXT:
if (type != EGL_WINDOW_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val < EGL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT ||
val > EGL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT) {
err = EGL_BAD_PARAMETER;
break;
}
surf->CompressionRate = val;
break;
/* pbuffer surface attributes */
case EGL_WIDTH:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Width = val;
break;
case EGL_HEIGHT:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Height = val;
break;
case EGL_LARGEST_PBUFFER:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->LargestPbuffer = !!val;
break;
/* for eglBindTexImage */
case EGL_TEXTURE_FORMAT:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
switch (val) {
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
case EGL_NO_TEXTURE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->TextureFormat = val;
break;
case EGL_TEXTURE_TARGET:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
switch (val) {
case EGL_TEXTURE_2D:
case EGL_NO_TEXTURE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->TextureTarget = val;
break;
case EGL_MIPMAP_TEXTURE:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->MipmapTexture = !!val;
break;
case EGL_PROTECTED_CONTENT_EXT:
if (!disp->Extensions.EXT_protected_content &&
!disp->Extensions.EXT_protected_surface) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->ProtectedContent = val;
break;
/* no pixmap surface specific attributes */
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
}
if (err == EGL_SUCCESS && type == EGL_PBUFFER_BIT) {
if ((surf->TextureTarget == EGL_NO_TEXTURE &&
surf->TextureFormat != EGL_NO_TEXTURE) ||
(surf->TextureFormat == EGL_NO_TEXTURE &&
surf->TextureTarget != EGL_NO_TEXTURE)) {
attr = surf->TextureTarget == EGL_NO_TEXTURE ? EGL_TEXTURE_TARGET
: EGL_TEXTURE_FORMAT;
err = EGL_BAD_MATCH;
}
}
if (err != EGL_SUCCESS)
_eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
return err;
}
/**
* Do error check on parameters and initialize the given _EGLSurface object.
* \return EGL_TRUE if no errors, EGL_FALSE otherwise.
*/
EGLBoolean
_eglInitSurface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type,
_EGLConfig *conf, const EGLint *attrib_list,
void *native_surface)
{
const char *func;
EGLint renderBuffer = EGL_BACK_BUFFER;
EGLint swapBehavior = EGL_BUFFER_DESTROYED;
EGLint err;
/* Swap behavior can be preserved only if config supports this. */
if (conf->SurfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
swapBehavior = EGL_BUFFER_PRESERVED;
switch (type) {
case EGL_WINDOW_BIT:
func = "eglCreateWindowSurface";
swapBehavior = EGL_BUFFER_DESTROYED;
break;
case EGL_PIXMAP_BIT:
func = "eglCreatePixmapSurface";
renderBuffer = EGL_SINGLE_BUFFER;
break;
case EGL_PBUFFER_BIT:
func = "eglCreatePBufferSurface";
break;
default:
_eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
return EGL_FALSE;
}
if ((conf->SurfaceType & type) == 0)
/* The config can't be used to create a surface of this type */
return _eglError(EGL_BAD_MATCH, func);
_eglInitResource(&surf->Resource, sizeof(*surf), disp);
surf->Type = type;
surf->Config = conf;
surf->Lost = EGL_FALSE;
surf->Width = 0;
surf->Height = 0;
surf->TextureFormat = EGL_NO_TEXTURE;
surf->TextureTarget = EGL_NO_TEXTURE;
surf->MipmapTexture = EGL_FALSE;
surf->LargestPbuffer = EGL_FALSE;
surf->RequestedRenderBuffer = renderBuffer;
surf->ActiveRenderBuffer = renderBuffer;
surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
surf->GLColorspace = EGL_GL_COLORSPACE_LINEAR_KHR;
surf->ProtectedContent = EGL_FALSE;
surf->PresentOpaque = EGL_FALSE;
surf->CompressionRate = EGL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT;
surf->MipmapLevel = 0;
surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
surf->SwapBehavior = swapBehavior;
surf->HorizontalResolution = EGL_UNKNOWN;
surf->VerticalResolution = EGL_UNKNOWN;
surf->AspectRatio = EGL_UNKNOWN;
surf->SetDamageRegionCalled = EGL_FALSE;
surf->BufferAgeRead = EGL_FALSE;
/* the default swap interval is 1 */
surf->SwapInterval = 1;
surf->HdrMetadata.display_primary_r.x = EGL_DONT_CARE;
surf->HdrMetadata.display_primary_r.y = EGL_DONT_CARE;
surf->HdrMetadata.display_primary_g.x = EGL_DONT_CARE;
surf->HdrMetadata.display_primary_g.y = EGL_DONT_CARE;
surf->HdrMetadata.display_primary_b.x = EGL_DONT_CARE;
surf->HdrMetadata.display_primary_b.y = EGL_DONT_CARE;
surf->HdrMetadata.white_point.x = EGL_DONT_CARE;
surf->HdrMetadata.white_point.y = EGL_DONT_CARE;
surf->HdrMetadata.max_luminance = EGL_DONT_CARE;
surf->HdrMetadata.min_luminance = EGL_DONT_CARE;
surf->HdrMetadata.max_cll = EGL_DONT_CARE;
surf->HdrMetadata.max_fall = EGL_DONT_CARE;
err = _eglParseSurfaceAttribList(surf, attrib_list);
if (err != EGL_SUCCESS)
return _eglError(err, func);
/* if EGL_LARGEST_PBUFFER in use, clamp width and height */
if (surf->LargestPbuffer) {
surf->Width = MIN2(surf->Width, _EGL_MAX_PBUFFER_WIDTH);
surf->Height = MIN2(surf->Height, _EGL_MAX_PBUFFER_HEIGHT);
}
surf->NativeSurface = native_surface;
return EGL_TRUE;
}
EGLBoolean
_eglQuerySurface(_EGLDisplay *disp, _EGLSurface *surface, EGLint attribute,
EGLint *value)
{
switch (attribute) {
case EGL_WIDTH:
*value = surface->Width;
break;
case EGL_HEIGHT:
*value = surface->Height;
break;
case EGL_CONFIG_ID:
*value = surface->Config->ConfigID;
break;
case EGL_LARGEST_PBUFFER:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->LargestPbuffer;
break;
case EGL_TEXTURE_FORMAT:
/* texture attributes: only for pbuffers, no error otherwise */
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->TextureFormat;
break;
case EGL_TEXTURE_TARGET:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->TextureTarget;
break;
case EGL_MIPMAP_TEXTURE:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->MipmapTexture;
break;
case EGL_MIPMAP_LEVEL:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->MipmapLevel;
break;
case EGL_SWAP_BEHAVIOR:
*value = surface->SwapBehavior;
break;
case EGL_RENDER_BUFFER:
/* From the EGL_KHR_mutable_render_buffer spec (v12):
*
* Querying EGL_RENDER_BUFFER returns the buffer which client API
* rendering is requested to use. For a window surface, this is the
* attribute value specified when the surface was created or last set
* via eglSurfaceAttrib.
*
* In other words, querying a window surface returns the value most
* recently *requested* by the user.
*
* The paragraph continues in the EGL 1.5 spec (2014.08.27):
*
* For a pbuffer surface, it is always EGL_BACK_BUFFER . For a pixmap
* surface, it is always EGL_SINGLE_BUFFER . To determine the actual
* buffer being rendered to by a context, call eglQueryContext.
*/
switch (surface->Type) {
default:
UNREACHABLE("bad EGLSurface type");
case EGL_WINDOW_BIT:
*value = surface->RequestedRenderBuffer;
break;
case EGL_PBUFFER_BIT:
*value = EGL_BACK_BUFFER;
break;
case EGL_PIXMAP_BIT:
*value = EGL_SINGLE_BUFFER;
break;
}
break;
case EGL_PIXEL_ASPECT_RATIO:
*value = surface->AspectRatio;
break;
case EGL_HORIZONTAL_RESOLUTION:
*value = surface->HorizontalResolution;
break;
case EGL_VERTICAL_RESOLUTION:
*value = surface->VerticalResolution;
break;
case EGL_MULTISAMPLE_RESOLVE:
*value = surface->MultisampleResolve;
break;
case EGL_VG_ALPHA_FORMAT:
*value = surface->VGAlphaFormat;
break;
case EGL_VG_COLORSPACE:
*value = surface->VGColorspace;
break;
case EGL_GL_COLORSPACE_KHR:
if (!disp->Extensions.KHR_gl_colorspace)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
*value = surface->GLColorspace;
break;
case EGL_BUFFER_AGE_EXT:
/* Both EXT_buffer_age and KHR_partial_update accept EGL_BUFFER_AGE_EXT.
* To be precise, the KHR one accepts EGL_BUFFER_AGE_KHR which is an
* alias with the same numeric value.
*/
if (!disp->Extensions.EXT_buffer_age &&
!disp->Extensions.KHR_partial_update)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
_EGLContext *ctx = _eglGetCurrentContext();
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
ctx->DrawSurface != surface)
return _eglError(EGL_BAD_SURFACE, "eglQuerySurface");
EGLint result = disp->Driver->QueryBufferAge(disp, surface);
if (result < 0)
return EGL_FALSE;
if (disp->Options.GalliumHudWarn && result > 0) {
_eglLog(_EGL_WARNING,
"GALLIUM_HUD is not accounted for when querying "
"buffer age, possibly causing artifacts, try running with "
"MESA_EXTENSION_OVERRIDE=\"-EGL_EXT_buffer_age "
"-EGL_KHR_partial_update\"");
disp->Options.GalliumHudWarn = EGL_FALSE;
}
*value = result;
surface->BufferAgeRead = EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
*value = surface->HdrMetadata.display_primary_r.x;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
*value = surface->HdrMetadata.display_primary_r.y;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
*value = surface->HdrMetadata.display_primary_g.x;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
*value = surface->HdrMetadata.display_primary_g.y;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
*value = surface->HdrMetadata.display_primary_b.x;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
*value = surface->HdrMetadata.display_primary_b.y;
break;
case EGL_SMPTE2086_WHITE_POINT_X_EXT:
*value = surface->HdrMetadata.white_point.x;
break;
case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
*value = surface->HdrMetadata.white_point.y;
break;
case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
*value = surface->HdrMetadata.max_luminance;
break;
case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
*value = surface->HdrMetadata.min_luminance;
break;
case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
*value = surface->HdrMetadata.max_cll;
break;
case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
*value = surface->HdrMetadata.max_fall;
break;
case EGL_PROTECTED_CONTENT_EXT:
if (!disp->Extensions.EXT_protected_content &&
!disp->Extensions.EXT_protected_surface)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
*value = surface->ProtectedContent;
break;
case EGL_PRESENT_OPAQUE_EXT:
if (!disp->Extensions.EXT_present_opaque)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
*value = surface->PresentOpaque;
break;
case EGL_SURFACE_COMPRESSION_EXT:
*value = surface->CompressionRate;
break;
default:
return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
}
return EGL_TRUE;
}
/**
* Default fallback routine - drivers might override this.
*/
EGLBoolean
_eglSurfaceAttrib(_EGLDisplay *disp, _EGLSurface *surface, EGLint attribute,
EGLint value)
{
EGLint confval;
EGLint err = EGL_SUCCESS;
EGLint all_es_bits =
EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
switch (attribute) {
case EGL_MIPMAP_LEVEL:
confval = surface->Config->RenderableType;
if (!(confval & all_es_bits)) {
err = EGL_BAD_PARAMETER;
break;
}
surface->MipmapLevel = value;
break;
case EGL_MULTISAMPLE_RESOLVE:
switch (value) {
case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
break;
case EGL_MULTISAMPLE_RESOLVE_BOX:
confval = surface->Config->SurfaceType;
if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
err = EGL_BAD_MATCH;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surface->MultisampleResolve = value;
break;
case EGL_RENDER_BUFFER:
if (!disp->Extensions.KHR_mutable_render_buffer) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (value != EGL_BACK_BUFFER && value != EGL_SINGLE_BUFFER) {
err = EGL_BAD_PARAMETER;
break;
}
/* From the EGL_KHR_mutable_render_buffer spec (v12):
*
* If attribute is EGL_RENDER_BUFFER, and the EGL_SURFACE_TYPE
* attribute of the EGLConfig used to create surface does not contain
* EGL_MUTABLE_RENDER_BUFFER_BIT_KHR, [...] an EGL_BAD_MATCH error is
* generated [...].
*/
if (!(surface->Config->SurfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR)) {
err = EGL_BAD_MATCH;
break;
}
surface->RequestedRenderBuffer = value;
break;
case EGL_SWAP_BEHAVIOR:
switch (value) {
case EGL_BUFFER_DESTROYED:
break;
case EGL_BUFFER_PRESERVED:
confval = surface->Config->SurfaceType;
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
err = EGL_BAD_MATCH;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surface->SwapBehavior = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
surface->HdrMetadata.display_primary_r.x = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
surface->HdrMetadata.display_primary_r.y = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
surface->HdrMetadata.display_primary_g.x = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
surface->HdrMetadata.display_primary_g.y = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
surface->HdrMetadata.display_primary_b.x = value;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
surface->HdrMetadata.display_primary_b.y = value;
break;
case EGL_SMPTE2086_WHITE_POINT_X_EXT:
surface->HdrMetadata.white_point.x = value;
break;
case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
surface->HdrMetadata.white_point.y = value;
break;
case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
surface->HdrMetadata.max_luminance = value;
break;
case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
surface->HdrMetadata.min_luminance = value;
break;
case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
surface->HdrMetadata.max_cll = value;
break;
case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
surface->HdrMetadata.max_fall = value;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglSurfaceAttrib");
return EGL_TRUE;
}
EGLBoolean
_eglBindTexImage(_EGLDisplay *disp, _EGLSurface *surface, EGLint buffer)
{
EGLint texture_type = EGL_PBUFFER_BIT;
/* Just do basic error checking and return success/fail.
* Drivers must implement the real stuff.
*/
if (disp->Extensions.NOK_texture_from_pixmap)
texture_type |= EGL_PIXMAP_BIT;
if (!(surface->Type & texture_type))
return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
if (surface->TextureFormat == EGL_NO_TEXTURE)
return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
if (surface->TextureTarget == EGL_NO_TEXTURE)
return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
if (buffer != EGL_BACK_BUFFER)
return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
surface->BoundToTexture = EGL_TRUE;
return EGL_TRUE;
}
EGLBoolean
_eglReleaseTexImage(_EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
{
/* Just do basic error checking and return success/fail.
* Drivers must implement the real stuff.
*/
EGLint texture_type = EGL_PBUFFER_BIT;
if (surf == EGL_NO_SURFACE)
return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
if (!surf->BoundToTexture) {
/* Not an error, simply nothing to do */
return EGL_TRUE;
}
if (surf->TextureFormat == EGL_NO_TEXTURE)
return _eglError(EGL_BAD_MATCH, "eglReleaseTexImage");
if (buffer != EGL_BACK_BUFFER)
return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
if (disp->Extensions.NOK_texture_from_pixmap)
texture_type |= EGL_PIXMAP_BIT;
if (!(surf->Type & texture_type))
return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
surf->BoundToTexture = EGL_FALSE;
return EGL_TRUE;
}
EGLBoolean
_eglSurfaceHasMutableRenderBuffer(_EGLSurface *surf)
{
return surf->Type == EGL_WINDOW_BIT && surf->Config &&
(surf->Config->SurfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR);
}
EGLBoolean
_eglSurfaceInSharedBufferMode(_EGLSurface *surf)
{
return _eglSurfaceHasMutableRenderBuffer(surf) &&
surf->ActiveRenderBuffer == EGL_SINGLE_BUFFER;
}
+271
View File
@@ -0,0 +1,271 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLSURFACE_INCLUDED
#define EGLSURFACE_INCLUDED
#include "egldisplay.h"
#include "egltypedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct _egl_xy {
EGLint x;
EGLint y;
};
struct _egl_hdr_metadata {
struct _egl_xy display_primary_r;
struct _egl_xy display_primary_g;
struct _egl_xy display_primary_b;
struct _egl_xy white_point;
EGLint max_luminance;
EGLint min_luminance;
EGLint max_cll;
EGLint max_fall;
};
/**
* "Base" class for device driver surfaces.
*/
struct _egl_surface {
/* A surface is a display resource */
_EGLResource Resource;
/* The context that is currently bound to the surface */
_EGLContext *CurrentContext;
_EGLConfig *Config;
EGLint Type; /* one of EGL_WINDOW_BIT, EGL_PIXMAP_BIT or EGL_PBUFFER_BIT */
/* The native surface is lost. The EGL spec requires certain functions
* to generate EGL_BAD_NATIVE_WINDOW when given this surface.
*/
EGLBoolean Lost;
/* attributes set by attribute list */
EGLint Width, Height;
EGLenum TextureFormat;
EGLenum TextureTarget;
EGLBoolean MipmapTexture;
EGLBoolean LargestPbuffer;
/**
* Value of EGL_RENDER_BUFFER selected at creation.
*
* The user may select, for window surfaces, the EGL_RENDER_BUFFER through
* the attribute list of eglCreateWindowSurface(). The EGL spec allows the
* implementation to ignore request, though; hence why we maintain both
* RequestedRenderBuffer and ActiveRenderBuffer. For pbuffer and pixmap
* surfaces, the EGL spec hard-codes the EGL_RENDER_BUFFER value and the
* user must not provide it in the attribute list.
*
* Normally, the attribute is immutable and after surface creation.
* However, EGL_KHR_mutable_render_buffer allows the user to change it in
* window surfaces via eglSurfaceAttrib, in which case
* eglQuerySurface(EGL_RENDER_BUFFER) will immediately afterwards return
* the requested value but the actual render buffer used by the context
* does not change until completion of the next eglSwapBuffers call.
*
* From the EGL_KHR_mutable_render_buffer spec (v12):
*
* Querying EGL_RENDER_BUFFER returns the buffer which client API
* rendering is requested to use. For a window surface, this is the
* attribute value specified when the surface was created or last set
* via eglSurfaceAttrib.
*
* eglQueryContext(EGL_RENDER_BUFFER) ignores this.
*/
EGLenum RequestedRenderBuffer;
/**
* The EGL_RENDER_BUFFER in use by the context.
*
* This is valid only when bound as the draw surface. This may differ from
* the RequestedRenderBuffer.
*
* Refer to eglQueryContext(EGL_RENDER_BUFFER) in the EGL spec.
* eglQuerySurface(EGL_RENDER_BUFFER) ignores this.
*
* If a window surface is bound as the draw surface and has a pending,
* user-requested change to EGL_RENDER_BUFFER, then the next eglSwapBuffers
* will flush the pending change. (The flush of EGL_RENDER_BUFFER state may
* occur without the implicit glFlush induced by eglSwapBuffers). The spec
* requires that the flush occur at that time and nowhere else. During the
* state-flush, we copy RequestedRenderBuffer to ActiveRenderBuffer.
*
* From the EGL_KHR_mutable_render_buffer spec (v12):
*
* If [...] there is a pending change to the EGL_RENDER_BUFFER
* attribute, eglSwapBuffers performs an implicit flush operation on the
* context and effects the attribute change.
*/
EGLenum ActiveRenderBuffer;
EGLenum VGAlphaFormat;
EGLenum VGColorspace;
EGLenum GLColorspace;
/* EGL_EXT_surface_compression
* Value of EGL_SURFACE_COMPRESSION_EXT attribute selected at creation.
*/
EGLint CompressionRate;
/* attributes set by eglSurfaceAttrib */
EGLint MipmapLevel;
EGLenum MultisampleResolve;
EGLenum SwapBehavior;
EGLint HorizontalResolution, VerticalResolution;
EGLint AspectRatio;
EGLint SwapInterval;
/* EGL_KHR_partial_update
* True if the damage region is already set
* between frame boundaries.
*/
EGLBoolean SetDamageRegionCalled;
/* EGL_KHR_partial_update
* True if the buffer age is read by the client
* between frame boundaries.
*/
EGLBoolean BufferAgeRead;
/* True if the surface is bound to an OpenGL ES texture */
EGLBoolean BoundToTexture;
EGLBoolean ProtectedContent;
EGLBoolean PresentOpaque;
struct _egl_hdr_metadata HdrMetadata;
void *NativeSurface;
};
extern EGLBoolean
_eglInitSurface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type,
_EGLConfig *config, const EGLint *attrib_list,
void *native_surface);
extern EGLBoolean
_eglQuerySurface(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute,
EGLint *value);
extern EGLBoolean
_eglSurfaceAttrib(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute,
EGLint value);
extern EGLBoolean
_eglBindTexImage(_EGLDisplay *disp, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean
_eglReleaseTexImage(_EGLDisplay *disp, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean
_eglSurfaceHasMutableRenderBuffer(_EGLSurface *surf);
extern EGLBoolean
_eglSurfaceInSharedBufferMode(_EGLSurface *surf);
/**
* Increment reference count for the surface.
*/
static inline _EGLSurface *
_eglGetSurface(_EGLSurface *surf)
{
if (surf)
_eglGetResource(&surf->Resource);
return surf;
}
/**
* Decrement reference count for the surface.
*/
static inline EGLBoolean
_eglPutSurface(_EGLSurface *surf)
{
return (surf) ? _eglPutResource(&surf->Resource) : EGL_FALSE;
}
/**
* Link a surface to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
static inline EGLSurface
_eglLinkSurface(_EGLSurface *surf)
{
_eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
return (EGLSurface)surf;
}
/**
* Unlink a linked surface from its display.
* Accessing an unlinked surface should generate EGL_BAD_SURFACE error.
*/
static inline void
_eglUnlinkSurface(_EGLSurface *surf)
{
_eglUnlinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
}
/**
* Lookup a handle to find the linked surface.
* Return NULL if the handle has no corresponding linked surface.
*/
static inline _EGLSurface *
_eglLookupSurface(EGLSurface surface, _EGLDisplay *disp)
{
_EGLSurface *surf = (_EGLSurface *)surface;
if (!disp || !_eglCheckResource((void *)surf, _EGL_RESOURCE_SURFACE, disp))
surf = NULL;
return surf;
}
/**
* Return the handle of a linked surface, or EGL_NO_SURFACE.
*/
static inline EGLSurface
_eglGetSurfaceHandle(_EGLSurface *surf)
{
_EGLResource *res = (_EGLResource *)surf;
return (res && _eglIsResourceLinked(res)) ? (EGLSurface)surf
: EGL_NO_SURFACE;
}
#ifdef __cplusplus
}
#endif
#endif /* EGLSURFACE_INCLUDED */
+151
View File
@@ -0,0 +1,151 @@
/**************************************************************************
*
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <inttypes.h>
#include <string.h>
#include "eglcurrent.h"
#include "egldriver.h"
#include "egllog.h"
#include "eglsync.h"
/**
* Parse the list of sync attributes and return the proper error code.
*/
static EGLint
_eglParseSyncAttribList(_EGLSync *sync, const EGLAttrib *attrib_list)
{
EGLint i;
if (!attrib_list)
return EGL_SUCCESS;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLAttrib attr = attrib_list[i++];
EGLAttrib val = attrib_list[i];
EGLint err = EGL_SUCCESS;
switch (attr) {
case EGL_CL_EVENT_HANDLE_KHR:
if (sync->Type == EGL_SYNC_CL_EVENT_KHR) {
sync->CLEvent = val;
} else {
err = EGL_BAD_ATTRIBUTE;
}
break;
case EGL_SYNC_NATIVE_FENCE_FD_ANDROID:
if (sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID) {
/* we take ownership of the native fd, so no dup(): */
sync->SyncFd = val;
} else {
err = EGL_BAD_ATTRIBUTE;
}
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_DEBUG, "bad sync attribute 0x%" PRIxPTR, attr);
return err;
}
}
return EGL_SUCCESS;
}
EGLBoolean
_eglInitSync(_EGLSync *sync, _EGLDisplay *disp, EGLenum type,
const EGLAttrib *attrib_list)
{
EGLint err;
_eglInitResource(&sync->Resource, sizeof(*sync), disp);
sync->Type = type;
sync->SyncStatus = EGL_UNSIGNALED_KHR;
sync->SyncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
err = _eglParseSyncAttribList(sync, attrib_list);
switch (type) {
case EGL_SYNC_CL_EVENT_KHR:
sync->SyncCondition = EGL_SYNC_CL_EVENT_COMPLETE_KHR;
break;
case EGL_SYNC_NATIVE_FENCE_ANDROID:
if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID)
sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
else
sync->SyncCondition = EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID;
break;
default:
sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglCreateSyncKHR");
if (type == EGL_SYNC_CL_EVENT_KHR && !sync->CLEvent)
return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
return EGL_TRUE;
}
EGLBoolean
_eglGetSyncAttrib(_EGLDisplay *disp, _EGLSync *sync, EGLint attribute,
EGLAttrib *value)
{
switch (attribute) {
case EGL_SYNC_TYPE_KHR:
*value = sync->Type;
break;
case EGL_SYNC_STATUS_KHR:
/* update the sync status */
if (sync->SyncStatus != EGL_SIGNALED_KHR &&
(sync->Type == EGL_SYNC_FENCE_KHR ||
sync->Type == EGL_SYNC_CL_EVENT_KHR ||
sync->Type == EGL_SYNC_REUSABLE_KHR ||
sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID))
disp->Driver->ClientWaitSyncKHR(disp, sync, 0, 0);
*value = sync->SyncStatus;
break;
case EGL_SYNC_CONDITION_KHR:
if (sync->Type != EGL_SYNC_FENCE_KHR &&
sync->Type != EGL_SYNC_CL_EVENT_KHR &&
sync->Type != EGL_SYNC_NATIVE_FENCE_ANDROID)
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR");
*value = sync->SyncCondition;
break;
default:
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR");
break;
}
return EGL_TRUE;
}
+119
View File
@@ -0,0 +1,119 @@
/**************************************************************************
*
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLSYNC_INCLUDED
#define EGLSYNC_INCLUDED
#include "egldisplay.h"
#include "egltypedefs.h"
/**
* "Base" class for device driver syncs.
*/
struct _egl_sync {
/* A sync is a display resource */
_EGLResource Resource;
EGLenum Type;
EGLenum SyncStatus;
EGLenum SyncCondition;
EGLAttrib CLEvent;
EGLint SyncFd;
};
extern EGLBoolean
_eglInitSync(_EGLSync *sync, _EGLDisplay *disp, EGLenum type,
const EGLAttrib *attrib_list);
extern EGLBoolean
_eglGetSyncAttrib(_EGLDisplay *disp, _EGLSync *sync, EGLint attribute,
EGLAttrib *value);
/**
* Increment reference count for the sync.
*/
static inline _EGLSync *
_eglGetSync(_EGLSync *sync)
{
if (sync)
_eglGetResource(&sync->Resource);
return sync;
}
/**
* Decrement reference count for the sync.
*/
static inline EGLBoolean
_eglPutSync(_EGLSync *sync)
{
return (sync) ? _eglPutResource(&sync->Resource) : EGL_FALSE;
}
/**
* Link a sync to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
static inline EGLSync
_eglLinkSync(_EGLSync *sync)
{
_eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC);
return (EGLSync)sync;
}
/**
* Unlink a linked sync from its display.
*/
static inline void
_eglUnlinkSync(_EGLSync *sync)
{
_eglUnlinkResource(&sync->Resource, _EGL_RESOURCE_SYNC);
}
/**
* Lookup a handle to find the linked sync.
* Return NULL if the handle has no corresponding linked sync.
*/
static inline _EGLSync *
_eglLookupSync(EGLSync handle, _EGLDisplay *disp)
{
_EGLSync *sync = (_EGLSync *)handle;
if (!disp || !_eglCheckResource((void *)sync, _EGL_RESOURCE_SYNC, disp))
sync = NULL;
return sync;
}
/**
* Return the handle of a linked sync, or EGL_NO_SYNC_KHR.
*/
static inline EGLSync
_eglGetSyncHandle(_EGLSync *sync)
{
_EGLResource *res = (_EGLResource *)sync;
return (res && _eglIsResourceLinked(res)) ? (EGLSync)sync : EGL_NO_SYNC_KHR;
}
#endif /* EGLSYNC_INCLUDED */
+76
View File
@@ -0,0 +1,76 @@
/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <[email protected]>
* Copyright 2010 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef EGLTYPEDEFS_INCLUDED
#define EGLTYPEDEFS_INCLUDED
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglext_angle.h>
#include <EGL/eglmesaext.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _egl_array _EGLArray;
typedef struct _egl_config _EGLConfig;
typedef struct _egl_context _EGLContext;
typedef struct _egl_device _EGLDevice;
typedef struct _egl_display _EGLDisplay;
typedef struct _egl_driver _EGLDriver;
typedef struct _egl_extensions _EGLExtensions;
typedef struct _egl_image _EGLImage;
typedef struct _egl_image_attribs _EGLImageAttribs;
typedef struct _egl_mode _EGLMode;
typedef struct _egl_resource _EGLResource;
typedef struct _egl_screen _EGLScreen;
typedef struct _egl_surface _EGLSurface;
typedef struct _egl_sync _EGLSync;
typedef struct _egl_thread_info _EGLThreadInfo;
#ifdef __cplusplus
}
#endif
#endif /* EGLTYPEDEFS_INCLUDED */
+272
View File
@@ -0,0 +1,272 @@
# Copyright © 2017-2019 Intel Corporation
# SPDX-License-Identifier: MIT
inc_egl = include_directories('.', 'main')
c_args_for_egl = [asan_c_args]
cpp_args_for_egl = []
link_args_for_egl = []
link_deps_for_egl = []
link_for_egl = []
if with_dri
link_for_egl += libgallium_dri
endif
if with_platform_windows
link_for_egl += libgallium_wgl
endif
deps_for_egl = []
incs_for_egl = [inc_include, inc_src, inc_egl]
files_egl = files(
'main/eglapi.c',
'main/eglarray.c',
'main/eglarray.h',
'main/eglconfigdebug.c',
'main/eglconfigdebug.h',
'main/eglconfig.c',
'main/eglconfig.h',
'main/eglcontext.c',
'main/eglcontext.h',
'main/eglcurrent.c',
'main/eglcurrent.h',
'main/egldefines.h',
'main/egldevice.c',
'main/egldevice.h',
'main/egldisplay.c',
'main/egldisplay.h',
'main/egldriver.h',
'main/eglglobals.c',
'main/eglglobals.h',
'main/eglimage.c',
'main/eglimage.h',
'main/egllog.c',
'main/egllog.h',
'main/eglsurface.c',
'main/eglsurface.h',
'main/eglsync.c',
'main/eglsync.h',
'main/eglentrypoint.h',
'main/egltypedefs.h',
)
# Remove the argument parsing from gen_egl_dispatch.py when removing this
# option
gen_args = []
if with_wayland_bind_display
gen_args += [ '--bind-wl-display' ]
endif
g_egldispatchstubs_c = custom_target(
'g_egldispatchstubs.c',
input : [
'generate/gen_egl_dispatch.py',
'generate/egl.xml', 'generate/egl_other.xml'
],
output : 'g_egldispatchstubs.c',
command : [
prog_python, '@INPUT0@', gen_args, 'source', '@INPUT1@', '@INPUT2@'
],
depend_files : [ 'generate/eglFunctionList.py', glapi_xml_py_deps],
capture : true,
)
g_egldispatchstubs_h = custom_target(
'g_egldispatchstubs.h',
input : [
'generate/gen_egl_dispatch.py',
'generate/egl.xml', 'generate/egl_other.xml'
],
output : 'g_egldispatchstubs.h',
command : [
prog_python, '@INPUT0@', gen_args, 'header', '@INPUT1@', '@INPUT2@'
],
depend_files : [ 'generate/eglFunctionList.py', glapi_xml_py_deps],
capture : true,
)
if with_dri
files_egl += files(
'drivers/dri2/egl_dri2.c',
'drivers/dri2/egl_dri2.h',
)
files_egl += sha1_h
files_egl += main_dispatch_h
deps_for_egl += idep_xmlconfig
link_for_egl += libloader
incs_for_egl += inc_loader
incs_for_egl += inc_gallium
incs_for_egl += inc_gallium_aux
incs_for_egl += inc_mesa
incs_for_egl += inc_st_dri
files_egl += files(
'drivers/dri2/platform_device.c',
'drivers/dri2/platform_surfaceless.c',
)
if with_platform_x11
files_egl += files('drivers/dri2/platform_x11.c')
incs_for_egl += inc_loader_x11
link_for_egl += libloader_x11
if with_dri_platform == 'drm' or with_dri_platform == 'pseudo-drm'
files_egl += files('drivers/dri2/platform_x11_dri3.c')
endif
deps_for_egl += [dep_x11_xcb, dep_xcb_xrandr, dep_xcb_xfixes, dep_xcb_shm]
endif
if with_gbm and not with_platform_android
files_egl += files('drivers/dri2/platform_drm.c')
incs_for_egl += [include_directories('../gbm/backends/dri')]
deps_for_egl += [dep_libdrm, dep_gbm]
endif
if with_platform_wayland
deps_for_egl += [dep_wayland_client, dep_wayland_server, dep_wayland_egl_headers]
link_for_egl += libloader_wayland_helper
files_egl += files('drivers/dri2/platform_wayland.c')
files_egl += wp_files['linux-dmabuf-unstable-v1']
files_egl += wp_files['presentation-time']
if with_wayland_bind_display
files_egl += [wayland_drm_client_protocol_h]
link_for_egl += [libwayland_drm]
incs_for_egl += include_directories('wayland/wayland-drm')
c_args_for_egl += [
'-DHAVE_BIND_WL_DISPLAY'
]
endif
endif
if with_platform_android
deps_for_egl += [dep_android, idep_u_gralloc]
files_egl += files('drivers/dri2/platform_android.c')
endif
elif with_platform_haiku
c_args_for_egl += [
'-D_EGL_BUILT_IN_DRIVER_HAIKU',
]
files_egl += files('drivers/haiku/egl_haiku.cpp')
incs_for_egl += [inc_gallium, inc_gallium_aux, inc_gallium_drivers, inc_gallium_winsys, inc_gallium_winsys_sw]
incs_for_egl += [inc_mesa]
incs_for_egl += [include_directories('../gallium/frontends/hgl')]
link_for_egl += [libmesa, libgallium, libswhgl, libsthgl, libglapi]
deps_for_egl += [cpp.find_library('be'), driver_swrast]
elif with_platform_windows
c_args_for_egl += [
'-DEGLAPI=', '-DPUBLIC='
]
files_egl += files('drivers/wgl/egl_wgl.c')
files_egl += main_dispatch_h
incs_for_egl += [inc_wgl, inc_gallium, inc_gallium_aux, inc_mesa]
link_for_egl += libgallium_wgl
else
error('No EGL driver available.')
endif
if cc.has_function('mincore')
c_args_for_egl += '-DHAVE_MINCORE'
endif
if not with_glvnd
egl_lib_name = 'EGL' + get_option('egl-lib-suffix')
egl_lib_version = '1.0.0'
egl_lib_soversion = host_machine.system() == 'windows' ? '' : '1'
else
egl_lib_name = 'EGL_@0@'.format(glvnd_vendor_name)
egl_lib_version = '0.0.0'
egl_lib_soversion = '0'
deps_for_egl += dep_glvnd
files_egl += [g_egldispatchstubs_h, g_egldispatchstubs_c]
files_egl += files('main/eglglvnd.c', 'main/egldispatchstubs.c')
endif
if with_ld_version_script
if with_glvnd
link_args_for_egl += [
'-Wl,--version-script', join_paths(meson.current_source_dir(), 'egl-glvnd.sym')
]
link_deps_for_egl += files('egl-glvnd.sym')
else
link_args_for_egl += [
'-Wl,--version-script', join_paths(meson.current_source_dir(), 'egl.sym')
]
link_deps_for_egl += files('egl.sym')
endif
endif
egl_def = custom_target(
'egl.def',
input: 'main/egl.def.in',
output : 'egl.def',
command : gen_vs_module_defs_normal_command,
)
libegl = shared_library(
egl_lib_name,
files_egl,
c_args : [
c_args_for_egl,
'-D_EGL_NATIVE_PLATFORM=_EGL_PLATFORM_@0@'.format(egl_native_platform.to_upper()),
],
cpp_args : [cpp_args_for_egl],
gnu_symbol_visibility : 'hidden',
include_directories : incs_for_egl,
link_with : [link_for_egl],
link_args : [ld_args_bsymbolic, ld_args_gc_sections, link_args_for_egl],
link_depends : [link_deps_for_egl],
dependencies : [deps_for_egl, dep_dl, dep_libdrm, dep_clock, dep_thread, idep_mesautil],
install : true,
version : egl_lib_version,
soversion : egl_lib_soversion,
name_prefix : host_machine.system() == 'windows' ? 'lib' : [], # always use lib, but avoid warnings on !windows
vs_module_defs : egl_def
)
if with_glvnd
configure_file(
configuration: {'library_path' : 'libEGL_@[email protected]'.format(glvnd_vendor_name)},
input : 'main/50_mesa.json',
output: '50_@[email protected]'.format(glvnd_vendor_name),
install : true,
install_tag : 'runtime',
install_dir : join_paths(get_option('datadir'), 'glvnd', 'egl_vendor.d')
)
devenv_glvnd_egl_json_file = configure_file(
configuration: {'library_path' : libegl.full_path()},
input : 'main/50_mesa.json',
output: 'devenv_glvnd_egl.json',
)
devenv.set('__EGL_VENDOR_LIBRARY_FILENAMES', devenv_glvnd_egl_json_file.full_path())
else
pkg.generate(
name : 'egl',
description : 'Mesa EGL Library',
version : meson.project_version(),
libraries : libegl,
libraries_private: gl_priv_libs,
requires_private : gl_priv_reqs,
extra_cflags : gl_pkgconfig_c_flags,
)
endif
if with_symbols_check
if with_glvnd
egl_symbols = files('egl-glvnd-symbols.txt')
else
egl_symbols = files('egl-symbols.txt')
endif
test('egl-symbols-check',
symbols_check,
args : [
'--lib', libegl,
'--symbols-file', egl_symbols,
symbols_check_args,
],
suite : ['egl'],
)
test('egl-entrypoint-check',
prog_python,
args : files('egl-entrypoint-check.py', 'main/eglentrypoint.h'),
suite : ['egl'],
)
endif
+2
View File
@@ -0,0 +1,2 @@
[*.{c,h}]
indent_style = tab
+18
View File
@@ -0,0 +1,18 @@
# Copyright © 2017 Intel Corporation
# SPDX-License-Identifier: MIT
inc_wayland_drm = include_directories('.')
_wl_drm = mod_wl.scan_xml('wayland-drm.xml', server : true, include_core_only : false)
wayland_drm_protocol_c = _wl_drm[0]
wayland_drm_client_protocol_h = _wl_drm[1]
wayland_drm_server_protocol_h = _wl_drm[2]
libwayland_drm = static_library(
'wayland_drm',
['wayland-drm.c', wayland_drm_protocol_c, wayland_drm_server_protocol_h],
gnu_symbol_visibility : 'hidden',
dependencies : [dep_wayland_server],
include_directories : inc_include,
build_by_default : false,
)
+272
View File
@@ -0,0 +1,272 @@
/*
* Copyright © 2011 Kristian Høgsberg
* Copyright © 2011 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Kristian Høgsberg <[email protected]>
* Benjamin Franzke <[email protected]>
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "EGL/egl.h"
#include "EGL/eglext.h"
#include "wayland-drm-server-protocol.h"
#include "wayland-drm.h"
#include <wayland-server.h>
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
static void
destroy_buffer(struct wl_resource *resource)
{
struct wl_drm_buffer *buffer = wl_resource_get_user_data(resource);
struct wl_drm *drm = buffer->drm;
drm->callbacks.release_buffer(drm->user_data, buffer);
free(buffer);
}
static void
buffer_destroy(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
drm_create_buffer(struct wl_client *client, struct wl_resource *resource,
uint32_t id, uint32_t name, int32_t width, int32_t height,
uint32_t stride, uint32_t format)
{
wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME,
"global GEM names are no longer supported");
}
static void
drm_create_planar_buffer(struct wl_client *client, struct wl_resource *resource,
uint32_t id, uint32_t name, int32_t width,
int32_t height, uint32_t format, int32_t offset0,
int32_t stride0, int32_t offset1, int32_t stride1,
int32_t offset2, int32_t stride2)
{
wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME,
"global GEM names are no longer supported");
}
static void
drm_create_prime_buffer(struct wl_client *client, struct wl_resource *resource,
uint32_t id, int fd, int32_t width, int32_t height,
uint32_t format, int32_t offset0, int32_t stride0,
int32_t offset1, int32_t stride1, int32_t offset2,
int32_t stride2)
{
struct wl_drm *drm = wl_resource_get_user_data(resource);
struct wl_drm_buffer *buffer;
buffer = calloc(1, sizeof *buffer);
if (buffer == NULL) {
wl_resource_post_no_memory(resource);
return;
}
buffer->drm = drm;
buffer->width = width;
buffer->height = height;
buffer->format = format;
buffer->offset[0] = offset0;
buffer->stride[0] = stride0;
buffer->offset[1] = offset1;
buffer->stride[1] = stride1;
buffer->offset[2] = offset2;
buffer->stride[2] = stride2;
switch (format) {
case WL_DRM_FORMAT_ARGB2101010:
case WL_DRM_FORMAT_ABGR2101010:
case WL_DRM_FORMAT_ARGB8888:
buffer->egl_components = EGL_TEXTURE_RGBA;
break;
case WL_DRM_FORMAT_XRGB2101010:
case WL_DRM_FORMAT_XBGR2101010:
case WL_DRM_FORMAT_XRGB8888:
case WL_DRM_FORMAT_BGR888:
case WL_DRM_FORMAT_RGB888:
case WL_DRM_FORMAT_RGB565:
buffer->egl_components = EGL_TEXTURE_RGB;
break;
case WL_DRM_FORMAT_YUV410:
case WL_DRM_FORMAT_YUV411:
case WL_DRM_FORMAT_YUV420:
case WL_DRM_FORMAT_YUV422:
case WL_DRM_FORMAT_YUV444:
buffer->egl_components = EGL_TEXTURE_Y_U_V_WL;
break;
case WL_DRM_FORMAT_NV12:
case WL_DRM_FORMAT_NV16:
buffer->egl_components = EGL_TEXTURE_Y_UV_WL;
break;
case WL_DRM_FORMAT_YUYV:
buffer->egl_components = EGL_TEXTURE_Y_XUXV_WL;
break;
}
drm->callbacks.reference_buffer(drm->user_data, fd, buffer);
close(fd);
if (buffer->driver_buffer == NULL) {
wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME,
"invalid name");
free(buffer);
return;
}
buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id);
if (!buffer->resource) {
wl_resource_post_no_memory(resource);
free(buffer);
return;
}
wl_resource_set_implementation(buffer->resource,
(void (**)(void)) & drm->buffer_interface,
buffer, destroy_buffer);
}
static void
drm_authenticate(struct wl_client *client, struct wl_resource *resource,
uint32_t id)
{
struct wl_drm *drm = wl_resource_get_user_data(resource);
if (!drm->callbacks.authenticate ||
drm->callbacks.authenticate(drm->user_data, id) < 0)
wl_resource_post_error(resource, WL_DRM_ERROR_AUTHENTICATE_FAIL,
"authenticate failed");
else
wl_resource_post_event(resource, WL_DRM_AUTHENTICATED);
}
static const struct wl_drm_interface drm_interface = {
drm_authenticate,
drm_create_buffer,
drm_create_planar_buffer,
drm_create_prime_buffer,
};
static void
bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct wl_drm *drm = data;
struct wl_resource *resource;
resource =
wl_resource_create(client, &wl_drm_interface, MIN(version, 2), id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &drm_interface, data, NULL);
wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name);
if (drm->callbacks.is_format_supported(drm->user_data,
WL_DRM_FORMAT_ARGB2101010)) {
wl_resource_post_event(resource, WL_DRM_FORMAT,
WL_DRM_FORMAT_ARGB2101010);
}
if (drm->callbacks.is_format_supported(drm->user_data,
WL_DRM_FORMAT_XRGB2101010)) {
wl_resource_post_event(resource, WL_DRM_FORMAT,
WL_DRM_FORMAT_XRGB2101010);
}
if (drm->callbacks.is_format_supported(drm->user_data,
WL_DRM_FORMAT_ABGR2101010)) {
wl_resource_post_event(resource, WL_DRM_FORMAT,
WL_DRM_FORMAT_ABGR2101010);
}
if (drm->callbacks.is_format_supported(drm->user_data,
WL_DRM_FORMAT_XBGR2101010)) {
wl_resource_post_event(resource, WL_DRM_FORMAT,
WL_DRM_FORMAT_XBGR2101010);
}
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_ARGB8888);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_XRGB8888);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_BGR888);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_RGB888);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_RGB565);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16);
wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV);
if (version >= 2) {
wl_resource_post_event(resource, WL_DRM_CAPABILITIES,
WL_DRM_CAPABILITY_PRIME);
}
}
struct wl_drm *
wayland_drm_init(struct wl_display *display, char *device_name,
const struct wayland_drm_callbacks *callbacks, void *user_data)
{
struct wl_drm *drm;
drm = malloc(sizeof *drm);
if (!drm)
return NULL;
drm->display = display;
drm->device_name = strdup(device_name);
drm->callbacks = *callbacks;
drm->user_data = user_data;
drm->buffer_interface.destroy = buffer_destroy;
drm->wl_drm_global =
wl_global_create(display, &wl_drm_interface, 2, drm, bind_drm);
return drm;
}
void
wayland_drm_uninit(struct wl_drm *drm)
{
free(drm->device_name);
wl_global_destroy(drm->wl_drm_global);
free(drm);
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef WAYLAND_DRM_H
#define WAYLAND_DRM_H
#include <wayland-server.h>
struct wl_display;
struct wl_resource;
struct wl_drm_buffer;
struct wayland_drm_callbacks {
int (*authenticate)(void *user_data, uint32_t id);
void (*reference_buffer)(void *user_data, int fd,
struct wl_drm_buffer *buffer);
void (*release_buffer)(void *user_data, struct wl_drm_buffer *buffer);
bool (*is_format_supported)(void *user_data, uint32_t format);
};
struct wl_drm {
struct wl_display *display;
struct wl_global *wl_drm_global;
void *user_data;
char *device_name;
struct wayland_drm_callbacks callbacks;
struct wl_buffer_interface buffer_interface;
};
struct wl_drm_buffer {
struct wl_resource *resource;
struct wl_drm *drm;
int32_t width, height;
uint32_t format;
uint32_t egl_components;
int32_t offset[3];
int32_t stride[3];
void *driver_buffer;
};
static inline struct wl_drm_buffer *
wayland_drm_buffer_get(struct wl_drm *drm, struct wl_resource *resource)
{
if (resource == NULL)
return NULL;
if (wl_resource_instance_of(resource, &wl_buffer_interface,
&drm->buffer_interface))
return wl_resource_get_user_data(resource);
else
return NULL;
}
struct wl_drm *
wayland_drm_init(struct wl_display *display, char *device_name,
const struct wayland_drm_callbacks *callbacks, void *user_data);
void
wayland_drm_uninit(struct wl_drm *drm);
#endif
+189
View File
@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="drm">
<copyright>
Copyright © 2008-2011 Kristian Høgsberg
Copyright © 2010-2011 Intel Corporation
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that\n the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<!-- drm support. This object is created by the server and published
using the display's global event. -->
<interface name="wl_drm" version="2">
<enum name="error">
<entry name="authenticate_fail" value="0"/>
<entry name="invalid_format" value="1"/>
<entry name="invalid_name" value="2"/>
</enum>
<enum name="format">
<!-- The drm format codes match the #defines in drm_fourcc.h.
The formats actually supported by the compositor will be
reported by the format event. New codes must not be added,
unless directly taken from drm_fourcc.h. -->
<entry name="c8" value="0x20203843"/>
<entry name="rgb332" value="0x38424752"/>
<entry name="bgr233" value="0x38524742"/>
<entry name="xrgb4444" value="0x32315258"/>
<entry name="xbgr4444" value="0x32314258"/>
<entry name="rgbx4444" value="0x32315852"/>
<entry name="bgrx4444" value="0x32315842"/>
<entry name="argb4444" value="0x32315241"/>
<entry name="abgr4444" value="0x32314241"/>
<entry name="rgba4444" value="0x32314152"/>
<entry name="bgra4444" value="0x32314142"/>
<entry name="xrgb1555" value="0x35315258"/>
<entry name="xbgr1555" value="0x35314258"/>
<entry name="rgbx5551" value="0x35315852"/>
<entry name="bgrx5551" value="0x35315842"/>
<entry name="argb1555" value="0x35315241"/>
<entry name="abgr1555" value="0x35314241"/>
<entry name="rgba5551" value="0x35314152"/>
<entry name="bgra5551" value="0x35314142"/>
<entry name="rgb565" value="0x36314752"/>
<entry name="bgr565" value="0x36314742"/>
<entry name="rgb888" value="0x34324752"/>
<entry name="bgr888" value="0x34324742"/>
<entry name="xrgb8888" value="0x34325258"/>
<entry name="xbgr8888" value="0x34324258"/>
<entry name="rgbx8888" value="0x34325852"/>
<entry name="bgrx8888" value="0x34325842"/>
<entry name="argb8888" value="0x34325241"/>
<entry name="abgr8888" value="0x34324241"/>
<entry name="rgba8888" value="0x34324152"/>
<entry name="bgra8888" value="0x34324142"/>
<entry name="xrgb2101010" value="0x30335258"/>
<entry name="xbgr2101010" value="0x30334258"/>
<entry name="rgbx1010102" value="0x30335852"/>
<entry name="bgrx1010102" value="0x30335842"/>
<entry name="argb2101010" value="0x30335241"/>
<entry name="abgr2101010" value="0x30334241"/>
<entry name="rgba1010102" value="0x30334152"/>
<entry name="bgra1010102" value="0x30334142"/>
<entry name="yuyv" value="0x56595559"/>
<entry name="yvyu" value="0x55595659"/>
<entry name="uyvy" value="0x59565955"/>
<entry name="vyuy" value="0x59555956"/>
<entry name="ayuv" value="0x56555941"/>
<entry name="xyuv8888" value="0x56555958"/>
<entry name="nv12" value="0x3231564e"/>
<entry name="nv21" value="0x3132564e"/>
<entry name="nv16" value="0x3631564e"/>
<entry name="nv61" value="0x3136564e"/>
<entry name="yuv410" value="0x39565559"/>
<entry name="yvu410" value="0x39555659"/>
<entry name="yuv411" value="0x31315559"/>
<entry name="yvu411" value="0x31315659"/>
<entry name="yuv420" value="0x32315559"/>
<entry name="yvu420" value="0x32315659"/>
<entry name="yuv422" value="0x36315559"/>
<entry name="yvu422" value="0x36315659"/>
<entry name="yuv444" value="0x34325559"/>
<entry name="yvu444" value="0x34325659"/>
<entry name="abgr16f" value="0x48344241"/>
<entry name="xbgr16f" value="0x48344258"/>
</enum>
<!-- Call this request with the magic received from drmGetMagic().
It will be passed on to the drmAuthMagic() or
DRIAuthConnection() call. This authentication must be
completed before create_buffer could be used. -->
<request name="authenticate">
<arg name="id" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="stride" type="uint"/>
<arg name="format" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_planar_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
<!-- Notification of the path of the drm device which is used by
the server. The client should use this device for creating
local buffers. Only buffers created from this device should
be be passed to the server using this drm object's
create_buffer request. -->
<event name="device">
<arg name="name" type="string"/>
</event>
<event name="format">
<arg name="format" type="uint"/>
</event>
<!-- Raised if the authenticate request succeeded -->
<event name="authenticated"/>
<enum name="capability" since="2">
<description summary="wl_drm capability bitmask">
Bitmask of capabilities.
</description>
<entry name="prime" value="1" summary="wl_drm prime available"/>
</enum>
<event name="capabilities">
<arg name="value" type="uint"/>
</event>
<!-- Version 2 additions -->
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
buffers. Pass 0 for offset and stride for unused planes. -->
<request name="create_prime_buffer" since="2">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="fd"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
</interface>
</protocol>