summaryrefslogtreecommitdiff
path: root/src/egl/drivers/android/droid_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers/android/droid_loader.c')
-rw-r--r--src/egl/drivers/android/droid_loader.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/src/egl/drivers/android/droid_loader.c b/src/egl/drivers/android/droid_loader.c
new file mode 100644
index 0000000000..1d02b49322
--- /dev/null
+++ b/src/egl/drivers/android/droid_loader.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2009 Chia-I Wu <olvaffe@gmail.com>
+ *
+ * This is based on the work of eagle, by
+ * Copyright © 2008, 2009 Kristian Høgsberg
+ *
+ * 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.
+ */
+
+#define LOG_TAG "DROID-LOADER"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+#include "droid.h"
+
+#ifndef DROID_DRIVER_PATH
+#define DROID_DRIVER_PATH "/system/lib"
+#endif
+
+struct droid_loader {
+ struct droid_backend *backend;
+
+ char *filename;
+ void *handle;
+
+ __DRIcoreExtension *core;
+ __DRIdri2Extension *dri2;
+};
+
+struct droid_context {
+ __DRIcontext *dri_context;
+};
+
+struct droid_drawable {
+ struct droid_loader *loader;
+ struct droid_surface *surface;
+
+ __DRIdrawable *dri_drawable;
+};
+
+static __DRIbuffer *
+loader_ext_get_buffers_with_format(__DRIdrawable *driDrawable,
+ int *width, int *height,
+ unsigned int *attachments, int count,
+ int *out_count, void *loaderPrivate)
+{
+ struct droid_drawable *drawable = (struct droid_drawable *) loaderPrivate;
+ struct droid_loader *loader = drawable->loader;
+ __DRIbuffer *buffers;
+
+ buffers = loader->backend->get_surface_buffers(loader->backend,
+ drawable->surface,
+ width, height,
+ attachments, count,
+ out_count, 1);
+
+ return buffers;
+}
+
+static const __DRIdri2LoaderExtension loader_ext_dri2_loader = {
+ { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION },
+ NULL,
+ NULL,
+ loader_ext_get_buffers_with_format,
+};
+
+static int
+loader_ext_get_ust(int64_t *ust)
+{
+ struct timeval tv;
+
+ if (ust == NULL)
+ return -EFAULT;
+
+ if (gettimeofday(&tv, NULL) == 0) {
+ ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
+ return 0;
+ } else {
+ return -errno;
+ }
+}
+
+static const __DRIsystemTimeExtension loader_ext_system_time = {
+ { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
+ loader_ext_get_ust,
+ NULL,
+};
+
+static const __DRIextension *loader_extensions[] = {
+ &loader_ext_dri2_loader.base,
+ &loader_ext_system_time.base,
+ NULL
+};
+
+static struct droid_loader *
+loader_create(struct droid_backend *backend)
+{
+ struct droid_loader *loader;
+
+ loader = calloc(1, sizeof(*loader));
+ if (!loader)
+ return NULL;
+
+ loader->backend = backend;
+
+ return loader;
+}
+
+static void
+loader_destroy(struct droid_loader *loader)
+{
+ if (loader->filename)
+ free(loader->filename);
+ if (loader->handle)
+ dlclose(loader->handle);
+ free(loader);
+}
+
+static int
+loader_load(struct droid_loader *loader, const char *filename)
+{
+ const __DRIextension **extensions;
+ const char *path = NULL;
+ int i;
+
+ LOGD("Loading DRI driver %s", filename);
+
+ loader->handle = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
+ if (loader->handle == NULL) {
+ LOGE("dlopen: %s", dlerror());
+ return 0;
+ }
+
+ extensions = dlsym(loader->handle, __DRI_DRIVER_EXTENSIONS);
+ if (extensions == NULL) {
+ LOGE("dlsym: %s", dlerror());
+ dlclose(loader->handle);
+ loader->handle = NULL;
+ return 0;
+ }
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
+ extensions[i]->version >= __DRI_CORE_VERSION) {
+ loader->core = (__DRIcoreExtension *) extensions[i];
+ }
+
+ if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 &&
+ extensions[i]->version >= __DRI_DRI2_VERSION) {
+ loader->dri2 = (__DRIdri2Extension *) extensions[i];
+ }
+ }
+
+ if (loader->core == NULL || loader->dri2 == NULL) {
+ LOGE("missing required DRI extensions");
+ dlclose(loader->handle);
+ loader->handle = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+loader_init(struct droid_loader *loader)
+{
+ char filename[1024];
+ const char *path;
+
+ path = DROID_DRIVER_PATH;
+ snprintf(filename, sizeof(filename), "%s/%s_dri.so",
+ path, loader->backend->driver_name);
+
+ if (!loader_load(loader, filename))
+ return 0;
+
+ loader->filename = strdup(filename);
+
+ return 1;
+}
+
+void
+droid_backend_destroy(struct droid_backend *backend)
+{
+ backend->destroy(backend);
+}
+
+struct droid_screen *
+droid_screen_create(struct droid_backend *backend)
+{
+ struct droid_screen *screen = NULL;
+ struct droid_loader *loader;
+ const __DRIextension **extensions;
+ int fd, screen_number;
+ int i;
+
+ loader = loader_create(backend);
+ if (!loader || !loader_init(loader)) {
+ LOGE("failed to initialize loader");
+ goto fail;
+ }
+
+ screen = calloc(1, sizeof(*screen));
+ if (!screen) {
+ LOGE("failed to allocate new screen");
+ goto fail;
+ }
+
+ if (!loader->backend->initialize(loader->backend, &fd, &screen_number)) {
+ LOGE("failed to initialize backend");
+ goto fail;
+ }
+
+ screen->loader = loader;
+ screen->dri_screen =
+ loader->dri2->createNewScreen(screen_number, fd,
+ loader_extensions,
+ &screen->dri_configs, NULL);
+ if (!screen->dri_screen) {
+ LOGE("failed to create DRI screen");
+ goto fail;
+ }
+
+ extensions = loader->core->getExtensions(screen->dri_screen);
+
+ for (i = 0; extensions && extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0 &&
+ extensions[i]->version >= __DRI_TEX_BUFFER_VERSION)
+ screen->tex_buffer = (__DRItexBufferExtension *) extensions[i];
+
+ if (strcmp(extensions[i]->name, __DRI_COPY_BUFFER) == 0 &&
+ extensions[i]->version >= __DRI_COPY_BUFFER_VERSION)
+ screen->copy_buffer = (__DRIcopyBufferExtension *) extensions[i];
+ }
+
+ if (!screen->tex_buffer) {
+ LOGE("DRI driver has no TexBuffer extension");
+ goto fail;
+ }
+
+ if (!screen->tex_buffer) {
+ LOGE("DRI driver has no CopyBuffer extension");
+ goto fail;
+ }
+
+ for (i = 0; screen->dri_configs[i]; i++)
+ ;
+ screen->num_dri_configs = i;
+
+ return screen;
+
+fail:
+ if (screen)
+ droid_screen_destroy(screen);
+ if (loader)
+ loader_destroy(loader);
+
+ return NULL;
+}
+
+void
+droid_screen_destroy(struct droid_screen *screen)
+{
+ struct droid_loader *loader = screen->loader;
+ if (screen->dri_screen)
+ loader->core->destroyScreen(screen->dri_screen);
+ free(screen);
+}
+
+static const struct {
+ EGLenum egl_attrib;
+ unsigned int dri_attrib;
+} droid_attrib_map[] = {
+ { EGL_BUFFER_SIZE, __DRI_ATTRIB_BUFFER_SIZE },
+ { EGL_RED_SIZE, __DRI_ATTRIB_RED_SIZE },
+ { EGL_GREEN_SIZE, __DRI_ATTRIB_GREEN_SIZE },
+ { EGL_BLUE_SIZE, __DRI_ATTRIB_BLUE_SIZE },
+ { EGL_ALPHA_SIZE, __DRI_ATTRIB_ALPHA_SIZE },
+ { EGL_BIND_TO_TEXTURE_RGB, __DRI_ATTRIB_BIND_TO_TEXTURE_RGB },
+ { EGL_BIND_TO_TEXTURE_RGBA, __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA },
+ { EGL_CONFIG_CAVEAT, __DRI_ATTRIB_CONFIG_CAVEAT },
+ { EGL_DEPTH_SIZE, __DRI_ATTRIB_DEPTH_SIZE },
+ { EGL_LEVEL, __DRI_ATTRIB_LEVEL },
+ { 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 },
+ { EGL_SAMPLE_BUFFERS, __DRI_ATTRIB_SAMPLE_BUFFERS },
+ { EGL_SAMPLES, __DRI_ATTRIB_SAMPLES },
+ { EGL_STENCIL_SIZE, __DRI_ATTRIB_STENCIL_SIZE },
+};
+
+void
+droid_screen_convert_config(struct droid_screen *screen,
+ const __DRIconfig *conf, _EGLConfig *egl_conf)
+{
+ struct droid_loader *loader = screen->loader;
+ const int num_attrs =
+ sizeof(droid_attrib_map) / sizeof(droid_attrib_map[0]);
+ int i;
+
+ for (i = 0; i < num_attrs; i++) {
+ unsigned int dri_attrib = droid_attrib_map[i].dri_attrib;
+ unsigned int dri_value;
+ EGLenum egl_attrib = droid_attrib_map[i].egl_attrib;
+ EGLint egl_value;
+
+ if (!loader->core->getConfigAttrib(conf, dri_attrib, &dri_value)) {
+ LOGE("failed to get attribute %02d for %p", dri_attrib, conf);
+ continue;
+ }
+
+ switch (egl_attrib) {
+ case EGL_CONFIG_CAVEAT:
+ if (dri_value & __DRI_ATTRIB_SLOW_BIT)
+ egl_value = EGL_SLOW_CONFIG;
+ else if (dri_value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
+ egl_value = EGL_NON_CONFORMANT_CONFIG;
+ else
+ egl_value = EGL_NONE;
+ break;
+ default:
+ egl_value = (EGLint) dri_value;
+ break;
+ }
+ SET_CONFIG_ATTRIB(egl_conf, egl_attrib, egl_value);
+ }
+}
+
+struct droid_context *
+droid_screen_create_context(struct droid_screen *screen,
+ const __DRIconfig *conf,
+ struct droid_context *shared)
+{
+ struct droid_loader *loader = screen->loader;
+ struct droid_context *ctx;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ LOGE("failed to allocate context");
+ return NULL;
+ }
+
+ ctx->dri_context =
+ loader->dri2->createNewContext(screen->dri_screen, conf,
+ (shared) ? shared->dri_context : NULL,
+ NULL);
+ if (!ctx->dri_context) {
+ LOGE("failed to create DRI context");
+ free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void
+droid_screen_destroy_context(struct droid_screen *screen,
+ struct droid_context *ctx)
+{
+ struct droid_loader *loader = screen->loader;
+ loader->core->destroyContext(ctx->dri_context);
+ free(ctx);
+}
+
+struct droid_drawable *
+droid_screen_create_drawable(struct droid_screen *screen,
+ const __DRIconfig *conf,
+ struct droid_surface *surf)
+{
+ struct droid_loader *loader = screen->loader;
+ struct droid_drawable *drawable;
+
+ drawable = calloc(1, sizeof(*drawable));
+ if (!drawable) {
+ LOGE("failed to allocate drawable");
+ return NULL;
+ }
+
+ /* needed in GetBuffers */
+ drawable->loader = loader;
+ drawable->surface = surf;
+
+ drawable->dri_drawable =
+ loader->dri2->createNewDrawable(screen->dri_screen,
+ conf, (void *) drawable);
+ if (!drawable->dri_drawable) {
+ LOGE("failed to create DRI drawable");
+ free(drawable);
+ return NULL;
+ }
+
+ return drawable;
+}
+
+void
+droid_screen_destroy_drawable(struct droid_screen *screen,
+ struct droid_drawable *drawable)
+{
+ struct droid_loader *loader = screen->loader;
+ loader->core->destroyDrawable(drawable->dri_drawable);
+ free(drawable);
+}
+
+int
+droid_screen_bind_context(struct droid_screen *screen,
+ struct droid_drawable *draw,
+ struct droid_drawable *read,
+ struct droid_context *ctx)
+{
+ struct droid_loader *loader = screen->loader;
+ int ret = 0;
+
+ if (ctx) {
+ if (draw && read)
+ ret = loader->core->bindContext(ctx->dri_context,
+ draw->dri_drawable,
+ read->dri_drawable);
+ else if (!draw && !read)
+ ret = loader->core->unbindContext(ctx->dri_context);
+ }
+
+ if (!ret)
+ LOGE("failed to bind context %p", ctx);
+
+ return ret;
+}
+
+int
+droid_screen_swap_buffers(struct droid_screen *screen,
+ struct droid_context *ctx,
+ struct droid_drawable *drawable)
+{
+ struct droid_loader *loader = screen->loader;
+ __DRIbuffer *native;
+ int width, height;
+ int err = 0;
+
+ native = loader->backend->get_native_buffer(loader->backend,
+ drawable->surface,
+ &width, &height);
+
+ /* copy from front buffer to native buffer */
+ if (native)
+ err = screen->copy_buffer->copyBuffer(ctx->dri_context, native, 0, 0,
+ drawable->dri_drawable,
+ __DRI_BUFFER_FRONT_LEFT, 0, 0,
+ width, height);
+
+ if (!err)
+ loader->backend->swap_native_buffers(loader->backend, drawable->surface);
+
+ return (!err);
+}