diff options
author | Chia-I Wu <olv@lunarg.com> | 2010-10-11 17:58:10 +0800 |
---|---|---|
committer | Chia-I Wu <olvaffe@gmail.com> | 2010-12-09 20:01:35 -0500 |
commit | 121fc671f48f6fe5b58d44d55ef9ec421f6abde1 (patch) | |
tree | f2fa0535fd046628659ca46707ffeb1c918e88b1 | |
parent | 8148db591a7b0e7a51f664930301cc8d774a90a8 (diff) |
android: Add new classic EGL driver for Android.
-rw-r--r-- | src/egl/drivers/android/droid.c | 649 | ||||
-rw-r--r-- | src/egl/drivers/android/droid.h | 126 | ||||
-rw-r--r-- | src/egl/drivers/android/droid_core.c | 327 | ||||
-rw-r--r-- | src/egl/drivers/android/droid_image.c | 132 | ||||
-rw-r--r-- | src/egl/drivers/android/egl_android.c | 42 |
5 files changed, 1276 insertions, 0 deletions
diff --git a/src/egl/drivers/android/droid.c b/src/egl/drivers/android/droid.c new file mode 100644 index 0000000000..60c100bb13 --- /dev/null +++ b/src/egl/drivers/android/droid.c @@ -0,0 +1,649 @@ +/* + * Copyright © 2010 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 <krh@bitplanet.net> + */ + +#define LOG_TAG "MESA-EGL" + +#include <cutils/log.h> + +#include "glapi/glapi.h" +#include "droid.h" + +static const __DRIuseInvalidateExtension use_invalidate = { + { __DRI_USE_INVALIDATE, 1 } +}; + +static __DRIimage * +droid_lookup_egl_image(__DRIscreen *screen, void *image, void *data) +{ + _EGLDisplay *disp = data; + struct droid_egl_image *dimg; + _EGLImage *img; + + (void) screen; + + img = _eglLookupImage(image, disp); + if (img == NULL) { + _eglError(EGL_BAD_PARAMETER, "droid_lookup_egl_image"); + return NULL; + } + + dimg = droid_egl_image(image); + + return dimg->dri_image; +} + +static const __DRIimageLookupExtension image_lookup_extension = { + { __DRI_IMAGE_LOOKUP, 1 }, + droid_lookup_egl_image +}; + +static int +get_format_bpp(int native) +{ + int bpp; + + /* see libpixelflinger/format.cpp */ + switch (native) { + case GGL_PIXEL_FORMAT_RGBA_8888: + case GGL_PIXEL_FORMAT_RGBX_8888: + case GGL_PIXEL_FORMAT_BGRA_8888: + bpp = 4; + break; + case GGL_PIXEL_FORMAT_RGB_888: + bpp = 3; + break; + case GGL_PIXEL_FORMAT_RGB_565: + case GGL_PIXEL_FORMAT_RGBA_5551: + case GGL_PIXEL_FORMAT_RGBA_4444: + case GGL_PIXEL_FORMAT_LA_88: + bpp = 2; + break; + case GGL_PIXEL_FORMAT_RGB_332: + case GGL_PIXEL_FORMAT_A_8: + case GGL_PIXEL_FORMAT_L_8: + bpp = 1; + break; + default: + bpp = 0; + break; + } + + return bpp; +} + +#include <gralloc_gem.h> +int +get_native_buffer_name(struct android_native_buffer_t *buf) +{ + struct drm_bo_t *bo; + + bo = drm_gem_get(buf->handle); + + return (bo) ? bo->name : 0; +} + +EGLBoolean +droid_dequeue_buffer(struct droid_egl_surface *dsurf) +{ + __DRIbuffer *buf = &dsurf->dri_buffer; + + if (dsurf->window->dequeueBuffer(dsurf->window, &dsurf->buffer)) + return EGL_FALSE; + + dsurf->buffer->common.incRef(&dsurf->buffer->common); + dsurf->window->lockBuffer(dsurf->window, dsurf->buffer); + + buf->attachment = __DRI_BUFFER_FAKE_FRONT_LEFT; + buf->name = get_native_buffer_name(dsurf->buffer); + buf->cpp = get_format_bpp(dsurf->buffer->format); + buf->pitch = dsurf->buffer->stride * buf->cpp; + buf->flags = 0; + + return EGL_TRUE; +} + +EGLBoolean +droid_enqueue_buffer(struct droid_egl_surface *dsurf) +{ + dsurf->window->queueBuffer(dsurf->window, dsurf->buffer); + + dsurf->buffer->common.decRef(&dsurf->buffer->common); + dsurf->buffer = NULL; + + return EGL_TRUE; +} + +static void +droid_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +{ +} + +static __DRIbuffer * +droid_get_buffers_with_format(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + struct droid_egl_surface *dsurf = loaderPrivate; + struct droid_egl_display *ddpy = + droid_egl_display(dsurf->base.Resource.Display); + + if (!dsurf->buffer) { + if (!droid_dequeue_buffer(dsurf)) + return NULL; + } + + if (width) + *width = dsurf->buffer->width; + if (height) + *height = dsurf->buffer->height; + + *out_count = 1; + + return &dsurf->dri_buffer; +} + +static const EGLint droid_to_egl_attribute_map[] = { + 0, + EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */ + EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */ + EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */ + EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */ + EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */ + EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */ + EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */ + 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */ + EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */ + EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */ + EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */ + EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */ + 0, /* __DRI_ATTRIB_RENDER_TYPE, */ + 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */ + 0, /* __DRI_ATTRIB_CONFORMANT */ + 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */ + 0, /* __DRI_ATTRIB_STEREO */ + 0, /* __DRI_ATTRIB_AUX_BUFFERS */ + 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */ + 0, /* __DRI_ATTRIB_FLOAT_MODE */ + 0, /* __DRI_ATTRIB_RED_MASK */ + 0, /* __DRI_ATTRIB_GREEN_MASK */ + 0, /* __DRI_ATTRIB_BLUE_MASK */ + 0, /* __DRI_ATTRIB_ALPHA_MASK */ + EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */ + EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */ + EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */ + 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */ + 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */ + 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */ + 0, /* __DRI_ATTRIB_SWAP_METHOD */ + EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */ + EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */ + 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */ + EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */ +}; + +static struct droid_egl_config * +droid_add_config(_EGLDisplay *dpy, const __DRIconfig *dri_config, int id, + int depth, EGLint surface_type, int rgba_masks[4]) +{ + struct droid_egl_config *conf; + struct droid_egl_display *ddpy; + _EGLConfig base; + unsigned int attrib, value, double_buffer; + EGLint key, bind_to_texture_rgb, bind_to_texture_rgba; + int dri_masks[4] = { 0, 0, 0, 0 }; + int i; + + ddpy = dpy->DriverData; + _eglInitConfig(&base, dpy, id); + + i = 0; + double_buffer = 0; + bind_to_texture_rgb = 0; + bind_to_texture_rgba = 0; + + while (ddpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) { + switch (attrib) { + case __DRI_ATTRIB_RENDER_TYPE: + if (value & __DRI_ATTRIB_RGBA_BIT) + value = EGL_RGB_BUFFER; + else if (value & __DRI_ATTRIB_LUMINANCE_BIT) + value = EGL_LUMINANCE_BUFFER; + else + assert(0); + _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value); + break; + + case __DRI_ATTRIB_CONFIG_CAVEAT: + if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) + value = EGL_NON_CONFORMANT_CONFIG; + else if (value & __DRI_ATTRIB_SLOW_BIT) + value = EGL_SLOW_CONFIG; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value); + break; + + case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB: + bind_to_texture_rgb = value; + break; + + case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA: + bind_to_texture_rgba = value; + break; + + case __DRI_ATTRIB_DOUBLE_BUFFER: + double_buffer = value; + break; + + case __DRI_ATTRIB_RED_MASK: + dri_masks[0] = value; + break; + + case __DRI_ATTRIB_GREEN_MASK: + dri_masks[1] = value; + break; + + case __DRI_ATTRIB_BLUE_MASK: + dri_masks[2] = value; + break; + + case __DRI_ATTRIB_ALPHA_MASK: + dri_masks[3] = value; + break; + + default: + key = droid_to_egl_attribute_map[attrib]; + if (key != 0) + _eglSetConfigKey(&base, key, value); + break; + } + } + + /* In EGL, double buffer or not isn't a config attribute. Pixmaps + * surfaces are always single buffered, pbuffer surfaces are always + * back buffers and windows can be either, selected by passing an + * attribute at window surface construction time. To support this + * we ignore all double buffer configs and manipulate the buffer we + * return in the getBuffer callback to get the behaviour we want. */ + + if (double_buffer) + return NULL; + + if (depth > 0 && depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE)) + return NULL; + + if (memcmp(dri_masks, rgba_masks, sizeof(rgba_masks))) + return NULL; + + _eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE); + + _eglSetConfigKey(&base, EGL_SURFACE_TYPE, surface_type); + if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) { + _eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb); + if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0) + _eglSetConfigKey(&base, + EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba); + } + + _eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, dpy->ClientAPIsMask); + _eglSetConfigKey(&base, EGL_CONFORMANT, dpy->ClientAPIsMask); + + if (!_eglValidateConfig(&base, EGL_FALSE)) { + _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id); + return NULL; + } + + conf = calloc(1, sizeof(*conf)); + if (conf != NULL) { + memcpy(&conf->base, &base, sizeof(base)); + conf->dri_config = dri_config; + _eglLinkConfig(&conf->base); + } + + return conf; +} + +static EGLBoolean +droid_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *dpy) +{ + struct droid_egl_display *ddpy = droid_egl_display(dpy); + const struct { + int format; + int size; + int rgba_masks[4]; + } visuals[] = { + { GGL_PIXEL_FORMAT_RGBA_8888, 32, { 0xff, 0xff00, 0xff0000, 0xff000000 } }, + { GGL_PIXEL_FORMAT_RGBX_8888, 32, { 0xff, 0xff00, 0xff0000, 0x0 } }, + { GGL_PIXEL_FORMAT_RGB_888, 24, { 0xff, 0xff00, 0xff0000, 0x0 } }, + { GGL_PIXEL_FORMAT_RGB_565, 16, { 0xf800, 0x7e0, 0x1f, 0x0 } }, + { GGL_PIXEL_FORMAT_BGRA_8888, 32, { 0xff0000, 0xff00, 0xff, 0xff000000 } }, + { GGL_PIXEL_FORMAT_A_8, 8, { 0xf800, 0x7e0, 0x1f, 0x0 } }, + { 0, 0, { 0, 0, 0, 0 } } + }; + int count, i, j; + + count = 0; + for (i = 0; visuals[i].format; i++) { + int format_count = 0; + + for (j = 0; ddpy->dri_configs[j]; j++) { + struct droid_egl_config *dconf; + + dconf = droid_add_config(dpy, ddpy->dri_configs[j], count + 1, + visuals[i].size, EGL_WINDOW_BIT, visuals[i].rgba_masks); + if (dconf) { + _eglSetConfigKey(&dconf->base, + EGL_NATIVE_VISUAL_TYPE, visuals[i].format); + count++; + format_count++; + } + } + + if (!format_count) { + _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x", + visuals[i].format); + } + } + + return (count != 0); +} + +struct droid_extension_match { + const char *name; + int version; + int offset; +}; + +static struct droid_extension_match droid_driver_extensions[] = { + { __DRI_CORE, 1, offsetof(struct droid_egl_display, core) }, + { __DRI_DRI2, 1, offsetof(struct droid_egl_display, dri2) }, + { NULL, 0, 0 } +}; + +static struct droid_extension_match droid_core_extensions[] = { + { __DRI2_FLUSH, 1, offsetof(struct droid_egl_display, flush) }, + { __DRI_IMAGE, 1, offsetof(struct droid_egl_display, image) }, + { NULL, 0, 0 } +}; + +extern const __DRIextension *__driDriverExtensions[]; + +static EGLBoolean +droid_bind_extensions(struct droid_egl_display *ddpy, + struct droid_extension_match *matches, + const __DRIextension **extensions) +{ + int i, j, ret = EGL_TRUE; + void *field; + + for (i = 0; extensions[i]; i++) { + _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name); + for (j = 0; matches[j].name; j++) { + if (strcmp(extensions[i]->name, matches[j].name) == 0 && + extensions[i]->version >= matches[j].version) { + field = ((char *) ddpy + matches[j].offset); + *(const __DRIextension **) field = extensions[i]; + _eglLog(_EGL_INFO, "DRI2: found extension %s version %d", + extensions[i]->name, extensions[i]->version); + } + } + } + + for (j = 0; matches[j].name; j++) { + field = ((char *) ddpy + matches[j].offset); + if (*(const __DRIextension **) field == NULL) { + _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d", + matches[j].name, matches[j].version); + ret = EGL_FALSE; + } + } + + return ret; +} + +static EGLBoolean +droid_create_screen(_EGLDisplay *dpy) +{ + struct droid_egl_display *ddpy = droid_egl_display(dpy); + const __DRIextension **extensions; + unsigned int api_mask; + + ddpy->dri_screen = + ddpy->dri2->createNewScreen(0, ddpy->fd, ddpy->extensions, + &ddpy->dri_configs, dpy); + if (ddpy->dri_screen == NULL) { + _eglLog(_EGL_WARNING, "failed to create dri screen"); + return EGL_FALSE; + } + + extensions = ddpy->core->getExtensions(ddpy->dri_screen); + if (!droid_bind_extensions(ddpy, droid_core_extensions, extensions)) { + ddpy->core->destroyScreen(ddpy->dri_screen); + return EGL_FALSE; + } + + if (ddpy->dri2->base.version >= 2) + api_mask = ddpy->dri2->getAPIMask(ddpy->dri_screen); + else + api_mask = __DRI_API_OPENGL; + + dpy->ClientAPIsMask = 0; + if (api_mask & (1 <<__DRI_API_OPENGL)) + dpy->ClientAPIsMask |= EGL_OPENGL_BIT; + if (api_mask & (1 <<__DRI_API_GLES)) + dpy->ClientAPIsMask |= EGL_OPENGL_ES_BIT; + if (api_mask & (1 << __DRI_API_GLES2)) + dpy->ClientAPIsMask |= EGL_OPENGL_ES2_BIT; + + if (ddpy->dri2->base.version >= 2) { + dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; + } + + return EGL_TRUE; +} + +static EGLBoolean +droid_load_driver(_EGLDisplay *disp) +{ + struct droid_egl_display *ddpy = disp->DriverData; + const __DRIextension **extensions; + + extensions = __driDriverExtensions; + + if (!droid_bind_extensions(ddpy, droid_driver_extensions, extensions)) + return EGL_FALSE; + + return EGL_TRUE; +} + +static EGLBoolean +droid_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy, + EGLint *major, EGLint *minor) +{ + struct droid_egl_display *ddpy; + int fd = -1, err, i; + const hw_module_t *mod; + + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod); + if (!err) { + const gralloc_module_t *gr = (gralloc_module_t *) mod; + + err = -EINVAL; + if (gr->perform) + err = gr->perform(gr, GRALLOC_MODULE_PERFORM_GET_DRM_FD, &fd); + } + if (err || fd < 0) { + _eglLog(_EGL_WARNING, "fail to get drm fd"); + return EGL_FALSE; + } + + ddpy = calloc(1, sizeof(*ddpy)); + if (!ddpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + dpy->DriverData = (void *) ddpy; + + ddpy->fd = fd; + if (!droid_load_driver(dpy)) + return EGL_FALSE; + + ddpy->loader_extension.base.name = __DRI_DRI2_LOADER; + ddpy->loader_extension.base.version = 3; + ddpy->loader_extension.getBuffers = NULL; + ddpy->loader_extension.flushFrontBuffer = droid_flush_front_buffer; + ddpy->loader_extension.getBuffersWithFormat = + droid_get_buffers_with_format; + + ddpy->extensions[0] = &ddpy->loader_extension.base; + ddpy->extensions[1] = &image_lookup_extension.base; + ddpy->extensions[2] = &use_invalidate.base; + ddpy->extensions[3] = NULL; + + if (!droid_create_screen(dpy)) { + free(ddpy); + return EGL_FALSE; + } + + if (!droid_add_configs_for_visuals(drv, dpy)) { + ddpy->core->destroyScreen(ddpy->dri_screen); + free(ddpy); + } + + dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE; + dpy->Extensions.KHR_image_base = EGL_TRUE; + + /* we're supporting EGL 1.4 */ + *major = 1; + *minor = 4; + + return EGL_TRUE; +} + +static EGLBoolean +droid_terminate(_EGLDriver *drv, _EGLDisplay *dpy) +{ + struct droid_egl_display *ddpy = droid_egl_display(dpy); + + _eglReleaseDisplayResources(drv, dpy); + _eglCleanupDisplay(dpy); + + ddpy->core->destroyScreen(ddpy->dri_screen); + free(ddpy); + dpy->DriverData = NULL; + + return EGL_TRUE; +} + +static EGLBoolean +droid_initialize(_EGLDriver *drv, _EGLDisplay *dpy, + EGLint *major, EGLint *minor) +{ + switch (dpy->Platform) { + case _EGL_PLATFORM_ANDROID: + return droid_initialize_android(drv, dpy, major, minor); + default: + return EGL_FALSE; + } +} + +static _EGLProc +droid_get_proc_address(_EGLDriver *drv, const char *procname) +{ + return (_EGLProc) _glapi_get_proc_address(procname); +} + + +static void +droid_unload(_EGLDriver *drv) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + + free(ddrv); +} + +static void +droid_log(EGLint level, const char *msg) +{ + switch (level) { + case _EGL_DEBUG: + LOGD(msg); + break; + case _EGL_INFO: + LOGI(msg); + break; + case _EGL_WARNING: + LOGW(msg); + break; + case _EGL_FATAL: + LOG_FATAL(msg); + break; + default: + break; + } +} + +_EGLDriver * +droid_create_driver(void) +{ + struct droid_egl_driver *ddrv; + + ddrv = calloc(1, sizeof(*ddrv)); + if (!ddrv) + return NULL; + + _eglSetLogProc(droid_log); + + ddrv->base.Name = "Droid"; + ddrv->base.Unload = droid_unload; + + _eglInitDriverFallbacks(&ddrv->base); + ddrv->base.API.Initialize = droid_initialize; + ddrv->base.API.Terminate = droid_terminate; + ddrv->base.API.GetProcAddress = droid_get_proc_address; + + ddrv->glFlush = + (void (*)(void)) droid_get_proc_address(&ddrv->base, "glFlush"); + ddrv->glFinish = + (void (*)(void)) droid_get_proc_address(&ddrv->base, "glFinish"); + + return &ddrv->base; +} diff --git a/src/egl/drivers/android/droid.h b/src/egl/drivers/android/droid.h new file mode 100644 index 0000000000..20e32a6588 --- /dev/null +++ b/src/egl/drivers/android/droid.h @@ -0,0 +1,126 @@ +/* + * Copyright © 2010 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 <krh@bitplanet.net> + */ + +#ifndef _DROID_H_ +#define _DROID_H_ + +#include <errno.h> + +#include <ui/egl/android_natives.h> +#include <ui/android_native_buffer.h> +#include <pixelflinger/format.h> + +#include <GL/gl.h> +#include <GL/internal/dri_interface.h> + +#include "egldriver.h" +#include "egldisplay.h" +#include "eglcontext.h" +#include "eglsurface.h" +#include "eglconfig.h" +#include "eglimage.h" +#include "eglcurrent.h" +#include "egllog.h" + +struct droid_egl_driver +{ + _EGLDriver base; + + void (*glFlush)(void); + void (*glFinish)(void); +}; + +struct droid_egl_display +{ + int fd; + + __DRIscreen *dri_screen; + const __DRIconfig **dri_configs; + __DRIcoreExtension *core; + __DRIdri2Extension *dri2; + __DRI2flushExtension *flush; + __DRIimageExtension *image; + + __DRIdri2LoaderExtension loader_extension; + const __DRIextension *extensions[8]; +}; + +struct droid_egl_context +{ + _EGLContext base; + + __DRIcontext *dri_context; +}; + +struct droid_egl_surface +{ + _EGLSurface base; + + __DRIdrawable *dri_drawable; + __DRIbuffer dri_buffer; + + android_native_window_t *window; + android_native_buffer_t *buffer; +}; + +struct droid_egl_config +{ + _EGLConfig base; + + const __DRIconfig *dri_config; +}; + +struct droid_egl_image +{ + _EGLImage base; + + __DRIimage *dri_image; +}; + +/* standard typecasts */ +_EGL_DRIVER_STANDARD_TYPECASTS(droid_egl) +_EGL_DRIVER_TYPECAST(droid_egl_image, _EGLImage, obj) + +_EGLDriver * +droid_create_driver(void); + +void +droid_init_core_functions(_EGLDriver *drv); + +void +droid_init_image_functions(_EGLDriver *drv); + +EGLBoolean +droid_dequeue_buffer(struct droid_egl_surface *dsurf); + +EGLBoolean +droid_enqueue_buffer(struct droid_egl_surface *dsurf); + +int +get_native_buffer_name(struct android_native_buffer_t *buf); + +#endif /* _DROID_H_ */ diff --git a/src/egl/drivers/android/droid_core.c b/src/egl/drivers/android/droid_core.c new file mode 100644 index 0000000000..82c21d4aa9 --- /dev/null +++ b/src/egl/drivers/android/droid_core.c @@ -0,0 +1,327 @@ +/* + * Copyright © 2010 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 <krh@bitplanet.net> + */ + +#include "droid.h" + +static _EGLContext * +droid_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, + _EGLContext *share_list, const EGLint *attrib_list) +{ + struct droid_egl_context *dctx; + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_context *dctx_shared = droid_egl_context(share_list); + struct droid_egl_config *dconf = droid_egl_config(conf); + const __DRIconfig *dri_config; + int api; + + (void) drv; + + dctx = calloc(1, sizeof *dctx); + if (!dctx) { + _eglError(EGL_BAD_ALLOC, "eglCreateContext"); + return NULL; + } + + if (!_eglInitContext(&dctx->base, disp, conf, attrib_list)) + goto cleanup; + + switch (dctx->base.ClientAPI) { + case EGL_OPENGL_ES_API: + switch (dctx->base.ClientVersion) { + case 1: + api = __DRI_API_GLES; + break; + case 2: + api = __DRI_API_GLES2; + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); + return NULL; + } + break; + case EGL_OPENGL_API: + api = __DRI_API_OPENGL; + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); + return NULL; + } + + if (conf != NULL) + dri_config = dconf->dri_config; + else + dri_config = NULL; + + if (ddpy->dri2->base.version >= 2) { + dctx->dri_context = + ddpy->dri2->createNewContextForAPI(ddpy->dri_screen, + api, + dri_config, + dctx_shared ? + dctx_shared->dri_context : NULL, + dctx); + } else if (api == __DRI_API_OPENGL) { + dctx->dri_context = + ddpy->dri2->createNewContext(ddpy->dri_screen, + dconf->dri_config, + dctx_shared ? + dctx_shared->dri_context : NULL, + dctx); + } else { + /* fail */ + } + + if (!dctx->dri_context) + goto cleanup; + + return &dctx->base; + + cleanup: + free(dctx); + return NULL; +} + +static _EGLSurface * +droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) +{ + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_config *dconf = droid_egl_config(conf); + struct droid_egl_surface *dsurf; + int format, vis_type; + + (void) drv; + + if (!window || window->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { + _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface"); + return NULL; + } + if (window->query(window, NATIVE_WINDOW_FORMAT, &format)) { + _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface"); + return NULL; + } + + vis_type = _eglGetConfigKey(&dconf->base, EGL_NATIVE_VISUAL_TYPE); + if (format != vis_type) { + _eglLog(_EGL_WARNING, "Native format mismatch: 0x%x != 0x%x", + format, vis_type); + } + + dsurf = calloc(1, sizeof *dsurf); + if (!dsurf) { + _eglError(EGL_BAD_ALLOC, "droid_create_surface"); + return NULL; + } + + if (!_eglInitSurface(&dsurf->base, disp, type, conf, attrib_list)) + goto cleanup_surf; + + dsurf->dri_drawable = + (*ddpy->dri2->createNewDrawable) (ddpy->dri_screen, + dconf->dri_config, dsurf); + if (dsurf->dri_drawable == NULL) { + _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); + goto cleanup_pixmap; + } + + window->common.incRef(&window->common); + window->query(window, NATIVE_WINDOW_WIDTH, &dsurf->base.Width); + window->query(window, NATIVE_WINDOW_HEIGHT, &dsurf->base.Height); + + dsurf->window = window; + + return &dsurf->base; + + cleanup_dri_drawable: + ddpy->core->destroyDrawable(dsurf->dri_drawable); + cleanup_pixmap: + cleanup_surf: + free(dsurf); + + return NULL; +} + +static _EGLSurface * +droid_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) +{ + return droid_create_surface(drv, disp, EGL_WINDOW_BIT, conf, + window, attrib_list); +} + +static _EGLSurface * +droid_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativePixmapType pixmap, + const EGLint *attrib_list) +{ + return NULL; +} + +static _EGLSurface * +droid_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, const EGLint *attrib_list) +{ + return NULL; +} + +static EGLBoolean +droid_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) +{ + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_surface *dsurf = droid_egl_surface(surf); + + (void) drv; + + if (!_eglPutSurface(surf)) + return EGL_TRUE; + + (*ddpy->core->destroyDrawable)(dsurf->dri_drawable); + + droid_enqueue_buffer(dsurf); + dsurf->window->common.decRef(&dsurf->window->common); + + free(surf); + + return EGL_TRUE; +} + +static EGLBoolean +droid_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, + _EGLSurface *rsurf, _EGLContext *ctx) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_surface *droid_dsurf = droid_egl_surface(dsurf); + struct droid_egl_surface *droid_rsurf = droid_egl_surface(rsurf); + struct droid_egl_context *dctx = droid_egl_context(ctx); + _EGLContext *old_ctx; + _EGLSurface *old_dsurf, *old_rsurf; + __DRIdrawable *ddraw, *rdraw; + __DRIcontext *cctx; + + /* make new bindings */ + if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) + return EGL_FALSE; + + /* flush before context switch */ + if (old_ctx && ddrv->glFlush) + ddrv->glFlush(); + + ddraw = (droid_dsurf) ? droid_dsurf->dri_drawable : NULL; + rdraw = (droid_rsurf) ? droid_rsurf->dri_drawable : NULL; + cctx = (dctx) ? dctx->dri_context : NULL; + + if ((cctx == NULL && ddraw == NULL && rdraw == NULL) || + ddpy->core->bindContext(cctx, ddraw, rdraw)) { + droid_destroy_surface(drv, disp, old_dsurf); + droid_destroy_surface(drv, disp, old_rsurf); + if (old_ctx) { + /* unbind the old context only when there is no new context bound */ + if (!ctx) { + __DRIcontext *old_cctx = droid_egl_context(old_ctx)->dri_context; + ddpy->core->unbindContext(old_cctx); + } + /* no destroy? */ + _eglPutContext(old_ctx); + } + + return EGL_TRUE; + } else { + /* undo the previous _eglBindContext */ + _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf); + assert(&dctx->base == ctx && + &droid_dsurf->base == dsurf && + &droid_rsurf->base == rsurf); + + _eglPutSurface(dsurf); + _eglPutSurface(rsurf); + _eglPutContext(ctx); + + _eglPutSurface(old_dsurf); + _eglPutSurface(old_rsurf); + _eglPutContext(old_ctx); + + return EGL_FALSE; + } +} + +static EGLBoolean +droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_surface *dsurf = droid_egl_surface(draw); + _EGLContext *ctx; + + if (ddrv->glFlush) { + ctx = _eglGetCurrentContext(); + if (ctx && ctx->DrawSurface == &dsurf->base) + ddrv->glFlush(); + } + + (*ddpy->flush->flush)(dsurf->dri_drawable); + + if (dsurf->buffer) + droid_enqueue_buffer(dsurf); + + (*ddpy->flush->invalidate)(dsurf->dri_drawable); + + return EGL_TRUE; +} + +static EGLBoolean +droid_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_surface *dsurf = droid_egl_surface(ctx->DrawSurface); + + if (ddrv->glFinish) + ddrv->glFinish(); + + if (dsurf) + (*ddpy->flush->flush)(dsurf->dri_drawable); + + return EGL_TRUE; +} + +void +droid_init_core_functions(_EGLDriver *drv) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + + ddrv->base.API.CreateContext = droid_create_context; + ddrv->base.API.CreateWindowSurface = droid_create_window_surface; + ddrv->base.API.CreatePixmapSurface = droid_create_pixmap_surface; + ddrv->base.API.CreatePbufferSurface = droid_create_pbuffer_surface; + ddrv->base.API.DestroySurface = droid_destroy_surface; + ddrv->base.API.MakeCurrent = droid_make_current; + ddrv->base.API.SwapBuffers = droid_swap_buffers; + ddrv->base.API.WaitClient = droid_wait_client; +} diff --git a/src/egl/drivers/android/droid_image.c b/src/egl/drivers/android/droid_image.c new file mode 100644 index 0000000000..509335bce6 --- /dev/null +++ b/src/egl/drivers/android/droid_image.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2010 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 <krh@bitplanet.net> + */ + +#include "droid.h" + +static _EGLImage * +droid_create_image_android_native_buffer(_EGLDisplay *disp, + EGLClientBuffer buffer) +{ + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct android_native_buffer_t *buf = + (struct android_native_buffer_t *) buffer; + struct droid_egl_image *dimg; + EGLint format, name; + + if (!buf || buf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC || + buf->common.version != sizeof(*buf)) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + name = get_native_buffer_name(buf); + if (!name) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + switch (buf->format) { + case HAL_PIXEL_FORMAT_BGRA_8888: + format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + case HAL_PIXEL_FORMAT_RGB_565: + format = __DRI_IMAGE_FORMAT_RGB565; + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + /* unsupported */ + default: + _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", buf->format); + return NULL; + break; + } + + dimg = calloc(1, sizeof(*dimg)); + if (!dimg) { + _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm"); + return NULL; + } + + if (!_eglInitImage(&dimg->base, disp)) { + free(dimg); + return NULL; + } + + dimg->dri_image = + ddpy->image->createImageFromName(ddpy->dri_screen, + buf->width, + buf->height, + format, + name, + buf->stride, + dimg); + if (!dimg->dri_image) { + free(dimg); + _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm"); + return NULL; + } + + return &dimg->base; +} + +static _EGLImage * +droid_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, + _EGLContext *ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + switch (target) { + case EGL_NATIVE_BUFFER_ANDROID: + return droid_create_image_android_native_buffer(disp, buffer); + default: + _eglError(EGL_BAD_PARAMETER, "droid_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } +} + +static EGLBoolean +droid_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image) +{ + struct droid_egl_display *ddpy = droid_egl_display(disp); + struct droid_egl_image *dimg = droid_egl_image(image); + + ddpy->image->destroyImage(dimg->dri_image); + free(dimg); + + return EGL_TRUE; +} + +void +droid_init_image_functions(_EGLDriver *drv) +{ + struct droid_egl_driver *ddrv = droid_egl_driver(drv); + + ddrv->base.API.CreateImageKHR = droid_create_image_khr; + ddrv->base.API.DestroyImageKHR = droid_destroy_image_khr; +} diff --git a/src/egl/drivers/android/egl_android.c b/src/egl/drivers/android/egl_android.c new file mode 100644 index 0000000000..3f1cb36b78 --- /dev/null +++ b/src/egl/drivers/android/egl_android.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2010 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 <krh@bitplanet.net> + */ + +#include "droid.h" + +_EGLDriver * +_eglMain(const char *args) +{ + _EGLDriver *drv; + + drv = droid_create_driver(); + if (drv) { + droid_init_core_functions(drv); + droid_init_image_functions(drv); + } + + return drv; +} |