OSDN Git Service

7dc846afb0881b75c04348b73dd2754129047dfe
[android-x86/external-mesa.git] / src / egl / drivers / android / droid_loader.c
1 /*
2  * Copyright (C) 2009 Chia-I Wu <olvaffe@gmail.com>
3  *
4  * This is based on the work of eagle, by
5  * Copyright © 2008, 2009 Kristian Høgsberg
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */
26
27 #define LOG_TAG "DROID-LOADER"
28 #include <utils/Log.h>
29
30 #include <string.h>
31 #include <errno.h>
32 #include <dlfcn.h>
33 #include <assert.h>
34
35 #include "droid.h"
36 #include "EGL/internal/eglimage_dri.h"
37
38 #ifndef DROID_DRIVER_PATH
39 #define DROID_DRIVER_PATH "/system/lib"
40 #endif
41
42 struct droid_loader {
43    struct droid_backend *backend;
44
45    char *filename;
46    void *handle;
47
48    __DRIcoreExtension *core;
49    __DRIdri2Extension *dri2;
50 };
51
52 struct droid_context {
53    __DRIcontext *dri_context;
54 };
55
56 struct droid_drawable {
57    struct droid_loader *loader;
58    struct droid_surface *surface;
59
60    __DRIdrawable *dri_drawable;
61    const __DRIconfig *dri_config;
62    __DRIEGLImage *dri_image;
63 };
64
65 static __DRIbuffer *
66 loader_ext_get_buffers_with_format(__DRIdrawable *driDrawable,
67                                    int *width, int *height,
68                                    unsigned int *attachments, int count,
69                                    int *out_count, void *loaderPrivate)
70 {
71    struct droid_drawable *drawable = (struct droid_drawable *) loaderPrivate;
72    struct droid_loader *loader = drawable->loader;
73    __DRIbuffer *buffers;
74
75    buffers = loader->backend->get_surface_buffers(loader->backend,
76                                                   drawable->surface,
77                                                   width, height,
78                                                   attachments, count,
79                                                   out_count, 1);
80
81    return buffers;
82 }
83
84 static const __DRIdri2LoaderExtension loader_ext_dri2_loader = {
85    { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION },
86    NULL,
87    NULL,
88    loader_ext_get_buffers_with_format,
89 };
90
91 static int
92 loader_ext_get_ust(int64_t *ust)
93 {
94    struct timeval tv;
95
96    if (ust == NULL)
97       return -EFAULT;
98
99    if (gettimeofday(&tv, NULL) == 0) {
100       ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
101       return 0;
102    } else {
103       return -errno;
104    }
105 }
106
107 static const __DRIsystemTimeExtension loader_ext_system_time = {
108    { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
109    loader_ext_get_ust,
110    NULL,
111 };
112
113 static const __DRIextension *loader_extensions[] = {
114    &loader_ext_dri2_loader.base,
115    &loader_ext_system_time.base,
116    NULL
117 };
118
119 static struct droid_loader *
120 loader_create(struct droid_backend *backend)
121 {
122    struct droid_loader *loader;
123
124    loader = calloc(1, sizeof(*loader));
125    if (!loader)
126       return NULL;
127
128    loader->backend = backend;
129
130    return loader;
131 }
132
133 static void
134 loader_destroy(struct droid_loader *loader)
135 {
136    if (loader->filename)
137       free(loader->filename);
138    if (loader->handle)
139       dlclose(loader->handle);
140    free(loader);
141 }
142
143 static int
144 loader_load(struct droid_loader *loader, const char *filename)
145 {
146    const __DRIextension **extensions;
147    const char *path = NULL;
148    int i;
149
150    LOGD("Loading DRI driver %s", filename);
151
152    loader->handle = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
153    if (loader->handle == NULL) {
154       LOGE("dlopen: %s", dlerror());
155       return 0;
156    }
157
158    extensions = dlsym(loader->handle, __DRI_DRIVER_EXTENSIONS);
159    if (extensions == NULL) {
160       LOGE("dlsym: %s", dlerror());
161       dlclose(loader->handle);
162       loader->handle = NULL;
163       return 0;
164    }
165
166    for (i = 0; extensions[i]; i++) {
167       if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
168           extensions[i]->version >= __DRI_CORE_VERSION) {
169          loader->core = (__DRIcoreExtension *) extensions[i];
170       }
171
172       if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 &&
173           extensions[i]->version >= __DRI_DRI2_VERSION) {
174          loader->dri2 = (__DRIdri2Extension *) extensions[i];
175       }
176    }
177
178    if (loader->core == NULL || loader->dri2 == NULL) {
179       LOGE("missing required DRI extensions");
180       dlclose(loader->handle);
181       loader->handle = NULL;
182       return 0;
183    }
184
185    return 1;
186 }
187
188 static int
189 loader_init(struct droid_loader *loader)
190 {
191    char filename[1024];
192    const char *path;
193
194    path = DROID_DRIVER_PATH;
195    snprintf(filename, sizeof(filename), "%s/%s_dri.so",
196             path, loader->backend->driver_name);
197
198    if (!loader_load(loader, filename))
199       return 0;
200
201    loader->filename = strdup(filename);
202
203    return 1;
204 }
205
206 void
207 droid_backend_destroy(struct droid_backend *backend)
208 {
209    backend->destroy(backend);
210 }
211
212 static void
213 screen_find_image_configs(struct droid_screen *screen)
214 {
215    struct droid_loader *loader = screen->loader;
216    int depth, i;
217
218    for (depth = 0; depth < DROID_MAX_IMAGE_DEPTH + 1; depth++) {
219       for (i = 0; i < screen->num_dri_configs; i++) {
220          const __DRIconfig *conf = screen->dri_configs[i];
221          _EGLConfig egl_conf;
222          EGLint rgba, val;
223
224          droid_screen_convert_config(screen, conf, &egl_conf);
225
226          val = GET_CONFIG_ATTRIB(&egl_conf, EGL_CONFIG_CAVEAT);
227          if (val == EGL_SLOW_CONFIG)
228             continue;
229
230          rgba  = GET_CONFIG_ATTRIB(&egl_conf, EGL_RED_SIZE);
231          rgba += GET_CONFIG_ATTRIB(&egl_conf, EGL_GREEN_SIZE);
232          rgba += GET_CONFIG_ATTRIB(&egl_conf, EGL_BLUE_SIZE);
233          rgba += GET_CONFIG_ATTRIB(&egl_conf, EGL_ALPHA_SIZE);
234          if (depth != rgba)
235             continue;
236
237          if (depth == 32) {
238             val = GET_CONFIG_ATTRIB(&egl_conf, EGL_BIND_TO_TEXTURE_RGBA);
239             if (val) {
240                screen->image_configs[depth] = conf;
241                break;
242             }
243          }
244
245          val = GET_CONFIG_ATTRIB(&egl_conf, EGL_BIND_TO_TEXTURE_RGB);
246          if (val) {
247             screen->image_configs[depth] = conf;
248             break;
249          }
250       }
251    }
252 }
253
254 struct droid_screen *
255 droid_screen_create(struct droid_backend *backend)
256 {
257    struct droid_screen *screen = NULL;
258    struct droid_loader *loader;
259    const __DRIextension **extensions;
260    int fd, screen_number;
261    int i;
262
263    loader = loader_create(backend);
264    if (!loader || !loader_init(loader)) {
265       LOGE("failed to initialize loader");
266       goto fail;
267    }
268
269    screen = calloc(1, sizeof(*screen));
270    if (!screen) {
271       LOGE("failed to allocate new screen");
272       goto fail;
273    }
274
275    if (!loader->backend->initialize(loader->backend, &fd, &screen_number)) {
276       LOGE("failed to initialize backend");
277       goto fail;
278    }
279
280    screen->loader = loader;
281    screen->dri_screen =
282       loader->dri2->createNewScreen(screen_number, fd,
283                                     loader_extensions,
284                                     &screen->dri_configs, NULL);
285    if (!screen->dri_screen) {
286       LOGE("failed to create DRI screen");
287       goto fail;
288    }
289
290    extensions = loader->core->getExtensions(screen->dri_screen);
291
292    for (i = 0; extensions && extensions[i]; i++) {
293       if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0 &&
294           extensions[i]->version >= __DRI_TEX_BUFFER_VERSION)
295          screen->tex_buffer = (__DRItexBufferExtension *) extensions[i];
296
297       if (strcmp(extensions[i]->name, __DRI_COPY_BUFFER) == 0 &&
298           extensions[i]->version >= __DRI_COPY_BUFFER_VERSION)
299          screen->copy_buffer = (__DRIcopyBufferExtension *) extensions[i];
300    }
301
302    if (!screen->tex_buffer) {
303       LOGE("DRI driver has no TexBuffer extension");
304       goto fail;
305    }
306
307    if (!screen->tex_buffer) {
308       LOGE("DRI driver has no CopyBuffer extension");
309       goto fail;
310    }
311
312    for (i = 0; screen->dri_configs[i]; i++)
313       ;
314    screen->num_dri_configs = i;
315
316    screen_find_image_configs(screen);
317
318    return screen;
319
320 fail:
321    if (screen)
322       droid_screen_destroy(screen);
323    if (loader)
324       loader_destroy(loader);
325
326    return NULL;
327 }
328
329 void
330 droid_screen_destroy(struct droid_screen *screen)
331 {
332    struct droid_loader *loader = screen->loader;
333    if (screen->dri_screen)
334       loader->core->destroyScreen(screen->dri_screen);
335    free(screen);
336 }
337
338 static const struct {
339    EGLenum egl_attrib;
340    unsigned int dri_attrib;
341 } droid_attrib_map[] = {
342    { EGL_BUFFER_SIZE,              __DRI_ATTRIB_BUFFER_SIZE },
343    { EGL_RED_SIZE,                 __DRI_ATTRIB_RED_SIZE },
344    { EGL_GREEN_SIZE,               __DRI_ATTRIB_GREEN_SIZE },
345    { EGL_BLUE_SIZE,                __DRI_ATTRIB_BLUE_SIZE },
346    { EGL_ALPHA_SIZE,               __DRI_ATTRIB_ALPHA_SIZE },
347    { EGL_BIND_TO_TEXTURE_RGB,      __DRI_ATTRIB_BIND_TO_TEXTURE_RGB },
348    { EGL_BIND_TO_TEXTURE_RGBA,     __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA },
349    { EGL_CONFIG_CAVEAT,            __DRI_ATTRIB_CONFIG_CAVEAT },
350    { EGL_DEPTH_SIZE,               __DRI_ATTRIB_DEPTH_SIZE },
351    { EGL_LEVEL,                    __DRI_ATTRIB_LEVEL },
352    { EGL_MAX_PBUFFER_WIDTH,        __DRI_ATTRIB_MAX_PBUFFER_WIDTH },
353    { EGL_MAX_PBUFFER_HEIGHT,       __DRI_ATTRIB_MAX_PBUFFER_HEIGHT },
354    { EGL_MAX_PBUFFER_PIXELS,       __DRI_ATTRIB_MAX_PBUFFER_PIXELS },
355    { EGL_SAMPLE_BUFFERS,           __DRI_ATTRIB_SAMPLE_BUFFERS },
356    { EGL_SAMPLES,                  __DRI_ATTRIB_SAMPLES },
357    { EGL_STENCIL_SIZE,             __DRI_ATTRIB_STENCIL_SIZE },
358 };
359
360 void
361 droid_screen_convert_config(struct droid_screen *screen,
362                             const __DRIconfig *conf, _EGLConfig *egl_conf)
363 {
364    struct droid_loader *loader = screen->loader;
365    const int num_attrs =
366       sizeof(droid_attrib_map) / sizeof(droid_attrib_map[0]);
367    int i;
368
369    for (i = 0; i < num_attrs; i++) {
370       unsigned int dri_attrib = droid_attrib_map[i].dri_attrib;
371       unsigned int dri_value;
372       EGLenum egl_attrib = droid_attrib_map[i].egl_attrib;
373       EGLint egl_value;
374
375       if (!loader->core->getConfigAttrib(conf, dri_attrib, &dri_value)) {
376          LOGE("failed to get attribute %02d for %p", dri_attrib, conf);
377          continue;
378       }
379
380       switch (egl_attrib) {
381       case EGL_CONFIG_CAVEAT:
382          if (dri_value & __DRI_ATTRIB_SLOW_BIT)
383             egl_value = EGL_SLOW_CONFIG;
384          else if  (dri_value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
385             egl_value = EGL_NON_CONFORMANT_CONFIG;
386          else
387             egl_value = EGL_NONE;
388          break;
389       default:
390          egl_value = (EGLint) dri_value;
391          break;
392       }
393       SET_CONFIG_ATTRIB(egl_conf, egl_attrib, egl_value);
394    }
395 }
396
397 struct droid_context *
398 droid_screen_create_context(struct droid_screen *screen,
399                             const __DRIconfig *conf,
400                             struct droid_context *shared)
401 {
402    struct droid_loader *loader = screen->loader;
403    struct droid_context *ctx;
404
405    ctx = calloc(1, sizeof(*ctx));
406    if (!ctx) {
407       LOGE("failed to allocate context");
408       return NULL;
409    }
410
411    ctx->dri_context =
412       loader->dri2->createNewContext(screen->dri_screen, conf,
413                                      (shared) ? shared->dri_context : NULL,
414                                      NULL);
415    if (!ctx->dri_context) {
416       LOGE("failed to create DRI context");
417       free(ctx);
418       return NULL;
419    }
420
421    return ctx;
422 }
423
424 void
425 droid_screen_destroy_context(struct droid_screen *screen,
426                              struct droid_context *ctx)
427 {
428    struct droid_loader *loader = screen->loader;
429    loader->core->destroyContext(ctx->dri_context);
430    free(ctx);
431 }
432
433 struct droid_drawable *
434 droid_screen_create_drawable(struct droid_screen *screen,
435                              const __DRIconfig *conf,
436                              struct droid_surface *surf)
437 {
438    struct droid_loader *loader = screen->loader;
439    struct droid_drawable *drawable;
440
441    drawable = calloc(1, sizeof(*drawable));
442    if (!drawable) {
443       LOGE("failed to allocate drawable");
444       return NULL;
445    }
446
447    /* needed in GetBuffers */
448    drawable->loader = loader;
449    drawable->surface = surf;
450    drawable->dri_config = conf;
451
452    drawable->dri_drawable =
453       loader->dri2->createNewDrawable(screen->dri_screen,
454                                       conf, (void *) drawable);
455    if (!drawable->dri_drawable) {
456       LOGE("failed to create DRI drawable");
457       free(drawable);
458       return NULL;
459    }
460
461    return drawable;
462 }
463
464 void *
465 droid_screen_get_drawable_data(struct droid_screen *screen,
466                                struct droid_drawable *drawable)
467 {
468    struct droid_loader *loader = screen->loader;
469    __DRIEGLImage *img = drawable->dri_image;
470
471    if (!img) {
472       unsigned int val;
473
474       img = calloc(1, sizeof(__DRIEGLImage));
475       if (!img)
476          return NULL;
477
478       img->magic = __DRI_EGL_IMAGE_MAGIC;
479       img->drawable = drawable->dri_drawable;
480       img->level = 0;
481       if (drawable->dri_config == screen->image_configs[32] &&
482           loader->core->getConfigAttrib(drawable->dri_config,
483                                         __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA,
484                                         &val))
485          img->texture_format_rgba = val;
486
487       drawable->dri_image = img;
488    }
489
490    return (void *) img;
491 }
492
493 void
494 droid_screen_destroy_drawable(struct droid_screen *screen,
495                               struct droid_drawable *drawable)
496 {
497    struct droid_loader *loader = screen->loader;
498    if (drawable->dri_image)
499       free(drawable->dri_image);
500    loader->core->destroyDrawable(drawable->dri_drawable);
501    free(drawable);
502 }
503
504 int
505 droid_screen_bind_context(struct droid_screen *screen,
506                           struct droid_drawable *draw,
507                           struct droid_drawable *read,
508                           struct droid_context *ctx)
509 {
510    struct droid_loader *loader = screen->loader;
511    int ret = 0;
512
513    if (ctx) {
514       if (draw && read)
515          ret = loader->core->bindContext(ctx->dri_context,
516                                          draw->dri_drawable,
517                                          read->dri_drawable);
518       else if (!draw && !read)
519          ret = loader->core->unbindContext(ctx->dri_context);
520    }
521
522    if (!ret)
523       LOGE("failed to bind context %p", ctx);
524
525    return ret;
526 }
527
528 int
529 droid_screen_swap_buffers(struct droid_screen *screen,
530                           struct droid_context *ctx,
531                           struct droid_drawable *drawable)
532 {
533    struct droid_loader *loader = screen->loader;
534    __DRIbuffer *native;
535    int width, height;
536    int err = 0;
537
538    native = loader->backend->get_native_buffer(loader->backend,
539                                                drawable->surface,
540                                                &width, &height);
541
542    /* copy from front buffer to native buffer */
543    if (native)
544       err = screen->copy_buffer->copyBuffer(ctx->dri_context, native, 0, 0,
545                                             drawable->dri_drawable,
546                                             __DRI_BUFFER_FRONT_LEFT, 0, 0,
547                                             width, height);
548
549    if (!err)
550       loader->backend->swap_native_buffers(loader->backend, drawable->surface);
551
552    return (!err);
553 }