OSDN Git Service

d8eb5fd463fc098a50f63022db2f34c3ca5e4ff4
[android-x86/external-mesa.git] / src / egl / drivers / android / egl_android.c
1 /*
2  * Copyright (C) 2009 Chia-I Wu <olvaffe@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 #define LOG_TAG "DROID-EGL"
25 #include <utils/Log.h>
26
27 #include "glapi/glapi.h"
28
29 #include "eglconfig.h"
30 #include "eglcontext.h"
31 #include "egldisplay.h"
32 #include "egldriver.h"
33 #include "eglglobals.h"
34 #include "egllog.h"
35 #include "eglsurface.h"
36 #include "eglimage.h"
37
38 #include "droid.h"
39
40 #ifndef DROID_DEVICE_PATH
41 #define DROID_DEVICE_PATH "/dev/dri/card0"
42 #endif
43
44 struct droid_egl_driver
45 {
46    _EGLDriver base;
47
48    /* EGL_DEFAULT_DISPLAY */
49    struct droid_egl_display *default_display;
50    void (*flush_current)(void);
51    void (*finish_current)(void);
52 };
53
54 struct droid_egl_display
55 {
56    EGLint refcnt;
57
58    EGLint apis;
59    EGLint major;
60    EGLint minor;
61
62    struct droid_backend *backend;
63    struct droid_screen *screen;
64 };
65
66 struct droid_egl_context {
67    _EGLContext base;
68    struct droid_context *context;
69 };
70
71 struct droid_egl_surface {
72    _EGLSurface base;
73    struct droid_drawable *drawable;
74    struct droid_surface *surface;
75 };
76
77 struct droid_egl_image {
78    _EGLImage base;
79    struct droid_drawable *drawable;
80    struct droid_surface *surface;
81 };
82
83 struct droid_egl_config {
84    _EGLConfig base;
85    const __DRIconfig *config;
86 };
87
88 static INLINE struct droid_egl_driver *
89 lookup_driver(_EGLDriver *drv)
90 {
91    return (struct droid_egl_driver *) drv;
92 }
93
94 static INLINE struct droid_egl_display *
95 lookup_display(_EGLDisplay *dpy)
96 {
97    return (struct droid_egl_display *) dpy->DriverData;
98 }
99
100 static INLINE struct droid_egl_context *
101 lookup_context(_EGLContext *context)
102 {
103    return (struct droid_egl_context *) context;
104 }
105
106 static INLINE struct droid_egl_surface *
107 lookup_surface(_EGLSurface *surface)
108 {
109    return (struct droid_egl_surface *) surface;
110 }
111
112 static INLINE struct droid_egl_image *
113 lookup_image(_EGLImage *image)
114 {
115    return (struct droid_egl_image *) image;
116 }
117
118 static INLINE struct droid_egl_config *
119 lookup_config(_EGLConfig *conf)
120 {
121    return (struct droid_egl_config *) conf;
122 }
123
124 static void
125 droid_create_configs(_EGLDisplay *dpy, struct droid_egl_display *droid_dpy,
126                      const __DRIconfig **configs, EGLint num_configs)
127 {
128    EGLint i;
129    EGLint id = 1;
130
131    for (i = 0; i < num_configs; i++) {
132       struct droid_egl_config *droid_conf = calloc(1, sizeof(*droid_conf));
133       EGLint val;
134
135       if (!droid_conf)
136          break;
137
138       _eglInitConfig(&droid_conf->base, id);
139       droid_conf->config = configs[i];
140       if (!droid_screen_convert_config(droid_dpy->screen, droid_conf->config,
141                                        &droid_conf->base)) {
142          free(droid_conf);
143          continue;
144       }
145
146       val = GET_CONFIG_ATTRIB(&droid_conf->base, EGL_CONFIG_CAVEAT);
147       /* we do not want slow configs */
148       if (val == EGL_SLOW_CONFIG) {
149          free(droid_conf);
150       } else {
151          _eglAddConfig(dpy, &droid_conf->base);
152          id++;
153       }
154    }
155 }
156
157
158 static EGLBoolean
159 droid_initialize_display(struct droid_egl_display *droid_dpy)
160 {
161    const char *path = DROID_DEVICE_PATH;
162
163    droid_dpy->backend = droid_backend_create_intel(path);
164    if (!droid_dpy->backend)
165       return EGL_FALSE;
166
167    droid_dpy->screen = droid_screen_create(droid_dpy->backend);
168    if (!droid_dpy->screen) {
169       free(droid_dpy->backend);
170       droid_dpy->backend = NULL;
171       return EGL_FALSE;
172    }
173
174    droid_dpy->apis = EGL_OPENGL_ES_BIT;
175    droid_dpy->major = 1;
176    droid_dpy->major = 4;
177
178    return EGL_TRUE;
179 }
180
181 static EGLBoolean
182 droid_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,
183                     EGLint *major, EGLint *minor)
184 {
185    struct droid_egl_driver *droid_drv = lookup_driver(drv);
186    struct droid_egl_display *droid_dpy;
187
188    if (dpy->NativeDisplay != EGL_DEFAULT_DISPLAY)
189       return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
190
191    /* the default display */
192    droid_dpy = droid_drv->default_display;
193    if (!droid_dpy) {
194       droid_dpy = calloc(1, sizeof(*droid_dpy));
195       if (!droid_dpy)
196          return _eglError(EGL_BAD_ALLOC, "eglInitialize");
197       if (!droid_initialize_display(droid_dpy))
198          return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
199
200       droid_create_configs(dpy, droid_dpy, droid_dpy->screen->dri_configs,
201                            droid_dpy->screen->num_dri_configs);
202
203 #if EGL_KHR_image_base
204       if (droid_dpy->backend->create_image_surface) {
205          dpy->Extensions.KHR_image = EGL_TRUE;
206          dpy->Extensions.KHR_image_base = EGL_TRUE;
207          dpy->Extensions.KHR_image_pixmap = EGL_TRUE;
208       }
209 #endif
210
211       droid_drv->default_display = droid_dpy;
212    }
213
214    dpy->DriverData = (void *) droid_dpy;
215    droid_dpy->refcnt++;
216
217    *major = droid_dpy->major;
218    *minor = droid_dpy->minor;
219
220    return EGL_TRUE;
221 }
222
223 static EGLBoolean
224 droid_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
225 {
226    struct droid_egl_driver *droid_drv = lookup_driver(drv);
227    struct droid_egl_display *droid_dpy = lookup_display(dpy);
228
229    dpy->DriverData = NULL;
230    droid_dpy->refcnt--;
231    if (!droid_dpy->refcnt) {
232       _eglReleaseDisplayResources(drv, dpy);
233       _eglCleanupDisplay(dpy);
234
235       free(droid_dpy);
236       droid_drv->default_display = NULL;
237    }
238
239    return EGL_TRUE;
240 }
241
242 static _EGLProc
243 droid_eglGetProcAddress(const char *procname)
244 {
245    return (_EGLProc) _glapi_get_proc_address(procname);
246 }
247
248 static _EGLContext *
249 droid_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
250                        _EGLContext *share_list, const EGLint *attrib_list)
251 {
252    struct droid_egl_display *droid_dpy = lookup_display(dpy);
253    struct droid_egl_config *droid_conf = lookup_config(conf);
254    struct droid_egl_context *shared = lookup_context(share_list);
255    struct droid_egl_context *ctx;
256
257    ctx = calloc(1, sizeof(*ctx));
258    if (!ctx) {
259       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
260       return NULL;
261    }
262
263    if (!_eglInitContext(drv, &ctx->base, &droid_conf->base, attrib_list)) {
264       free(ctx);
265       return NULL;
266    }
267
268    ctx->context =
269       droid_screen_create_context(droid_dpy->screen, droid_conf->config,
270                                   (shared) ? shared->context : NULL);
271    if (!ctx->context) {
272       free(ctx);
273       return NULL;
274    }
275
276    return &ctx->base;
277 }
278
279 static EGLBoolean
280 droid_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
281 {
282    struct droid_egl_display *droid_dpy = lookup_display(dpy);
283    struct droid_egl_context *droid_ctx = lookup_context(ctx);
284
285    if (!_eglIsContextBound(ctx))
286       droid_screen_destroy_context(droid_dpy->screen, droid_ctx->context);
287
288    return EGL_TRUE;
289 }
290
291 static EGLBoolean
292 droid_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d,
293                      _EGLSurface *r, _EGLContext *ctx)
294 {
295    struct droid_egl_driver *droid_drv = lookup_driver(drv);
296    struct droid_egl_display *droid_dpy = lookup_display(dpy);
297    struct droid_egl_surface *draw = lookup_surface(d);
298    struct droid_egl_surface *read = lookup_surface(r);
299    struct droid_egl_context *droid_ctx = lookup_context(ctx);
300    _EGLContext *old;
301    struct droid_egl_context *droid_old;
302
303    old = _eglGetCurrentContext();
304    /* an unlinked context will be invalid after context switch */
305    if (!_eglIsContextLinked(old))
306       old = NULL;
307
308    droid_old = lookup_context(old);
309
310    if (!_eglMakeCurrent(drv, dpy, d, r, ctx))
311       return EGL_FALSE;
312
313    if (droid_old && droid_old != droid_ctx && droid_drv->flush_current)
314       droid_drv->flush_current();
315
316    _glapi_check_multithread();
317
318    /* bind new context or unbind old one */
319    if (droid_ctx)
320       droid_screen_bind_context(droid_dpy->screen,
321                                 draw->drawable, read->drawable,
322                                 droid_ctx->context);
323    else if (droid_old)
324       droid_screen_bind_context(droid_dpy->screen,
325                                 NULL, NULL,
326                                 droid_old->context);
327
328    return EGL_TRUE;
329 }
330
331 static _EGLSurface *
332 droid_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
333                              NativeWindowType window, const EGLint *attrib_list)
334 {
335    struct droid_egl_display *droid_dpy = lookup_display(dpy);
336    struct droid_egl_config *droid_conf = lookup_config(conf);
337    struct droid_egl_surface *surf;
338
339    surf = calloc(1, sizeof(*surf));
340    if (!surf) {
341       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
342       return NULL;
343    }
344
345    if (!_eglInitSurface(drv, &surf->base, EGL_WINDOW_BIT, &droid_conf->base, attrib_list)) {
346       free(surf);
347       return NULL;
348    }
349
350    surf->surface =
351       droid_dpy->backend->create_window_surface(droid_dpy->backend,
352                                                 &surf->base, window);
353    if (!surf->surface) {
354       free(surf);
355       return NULL;
356    }
357
358    surf->drawable = droid_screen_create_drawable(droid_dpy->screen,
359                                                  droid_conf->config,
360                                                  surf->surface);
361    if (!surf->drawable) {
362       droid_dpy->backend->destroy_surface(droid_dpy->backend, surf->surface);
363       free(surf);
364       return NULL;
365    }
366
367    return &surf->base;
368 }
369
370 static EGLBoolean
371 droid_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
372 {
373    struct droid_egl_display *droid_dpy = lookup_display(dpy);
374    struct droid_egl_surface *droid_surf = lookup_surface(surf);
375
376    if (_eglIsSurfaceBound(&droid_surf->base))
377       return EGL_TRUE;
378
379    droid_screen_destroy_drawable(droid_dpy->screen, droid_surf->drawable);
380    droid_dpy->backend->destroy_surface(droid_dpy->backend, droid_surf->surface);
381    free(droid_surf);
382
383    return EGL_TRUE;
384 }
385
386 static EGLBoolean
387 droid_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
388 {
389    struct droid_egl_driver *droid_drv = lookup_driver(drv);
390    struct droid_egl_display *droid_dpy = lookup_display(dpy);
391    struct droid_egl_surface *droid_surf = lookup_surface(surf);
392    _EGLContext *ctx = _eglGetCurrentContext();
393    struct droid_egl_context *droid_ctx = lookup_context(ctx);
394
395    if (droid_ctx) {
396       if (droid_drv->flush_current)
397          droid_drv->flush_current();
398
399       droid_screen_swap_buffers(droid_dpy->screen,
400                                 droid_ctx->context,
401                                 droid_surf->drawable);
402    }
403
404    return EGL_TRUE;
405 }
406
407 #if EGL_KHR_image_base
408
409 static _EGLImage *
410 droid_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
411                        EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list)
412 {
413    struct droid_egl_display *droid_dpy = lookup_display(dpy);
414    struct droid_egl_image *droid_img;
415    struct droid_egl_config *droid_conf;
416    _EGLConfig *conf;
417    EGLint val, i;
418
419    /* only EGL_KHR_image_pixmap is supported */
420    if (target != EGL_NATIVE_PIXMAP_KHR || ctx) {
421       _eglError(EGL_BAD_PARAMETER, "eglCreateImageKHR");
422       return NULL;
423    }
424
425    for (i = 0; i < dpy->NumConfigs; i++) {
426       conf = dpy->Configs[i];
427       if (droid_dpy->backend->match_pixmap(droid_dpy->backend, conf,
428                                            (NativePixmapType) buffer)) {
429          EGLint val;
430          val = GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB);
431          val |= GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA);
432          if (val)
433             break;
434       }
435    }
436    if (i >= dpy->NumConfigs)
437       return NULL;
438
439    droid_img = calloc(1, sizeof(*droid_img));
440    if (!droid_img) {
441       _eglError(EGL_BAD_ALLOC, "eglCreateImageKHR");
442       return NULL;
443    }
444
445    if (!_eglInitImage(drv, &droid_img->base, attr_list)) {
446       free(droid_img);
447       return NULL;
448    }
449
450    droid_img->surface = 
451       droid_dpy->backend->create_image_surface(droid_dpy->backend,
452                                                (NativePixmapType) buffer);
453    if (!droid_img->surface) {
454       free(droid_img);
455       return NULL;
456    }
457
458    droid_conf = lookup_config(conf);
459    droid_img->drawable =
460       droid_screen_create_drawable(droid_dpy->screen, droid_conf->config,
461                                    droid_img->surface);
462
463    if (!droid_img->drawable) {
464       droid_dpy->backend->destroy_surface(droid_dpy->backend,
465                                           droid_img->surface);
466       free(droid_img);
467       return NULL;
468    }
469
470    droid_img->base.ClientData =
471       droid_screen_get_drawable_data(droid_dpy->screen, droid_img->drawable);
472
473    return &droid_img->base;
474 }
475
476
477 static EGLBoolean
478 droid_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img)
479 {
480    struct droid_egl_display *droid_dpy = lookup_display(dpy);
481    struct droid_egl_image *droid_img = lookup_image(img);
482
483    droid_screen_destroy_drawable(droid_dpy->screen, droid_img->drawable);
484    droid_dpy->backend->destroy_surface(droid_dpy->backend, droid_img->surface);
485    free(droid_img);
486
487    return EGL_TRUE;
488 }
489
490 #endif /* EGL_KHR_image_base */
491
492 static EGLBoolean
493 droid_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy)
494 {
495    struct droid_egl_driver *droid_drv = lookup_driver(drv);
496    _EGLContext *ctx = _eglGetCurrentContext();
497
498    if (!ctx || !droid_drv->finish_current)
499       return EGL_TRUE;
500
501    if (!_eglIsSurfaceLinked(ctx->DrawSurface))
502       return _eglError(EGL_BAD_CURRENT_SURFACE, "eglWaitClient");
503
504    droid_drv->finish_current();
505
506    return EGL_TRUE;
507 }
508
509 static EGLBoolean
510 droid_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
511 {
512    struct droid_egl_display *droid_dpy = lookup_display(dpy);
513    _EGLContext *ctx = _eglGetCurrentContext();
514    struct droid_egl_surface *droid_surf;
515
516    if (engine != EGL_CORE_NATIVE_ENGINE)
517       return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
518
519    if (!ctx) 
520       return EGL_TRUE;
521
522    if (!_eglIsSurfaceLinked(ctx->DrawSurface))
523       return _eglError(EGL_BAD_CURRENT_SURFACE, "eglWaitNative");
524
525    droid_surf = lookup_surface(ctx->DrawSurface);
526    droid_dpy->backend->swap_native_buffers(droid_dpy->backend,
527                                            droid_surf->surface);
528
529    return EGL_TRUE;
530 }
531
532 static void
533 droid_Unload(_EGLDriver *drv)
534 {
535    struct droid_egl_driver *droid_drv = lookup_driver(drv);
536    free(droid_drv);
537 }
538
539 static void
540 droid_Log(EGLint level, const char *msg)
541 {
542    switch (level) {
543    case _EGL_DEBUG:
544       LOGD(msg);
545       break;
546    case _EGL_INFO:
547       LOGI(msg);
548       break;
549    case _EGL_WARNING:
550       LOGW(msg);
551       break;
552    case _EGL_FATAL:
553       LOGE(msg);
554       break;
555    }
556 }
557
558 _EGLDriver *
559 _eglMain(const char *args)
560 {
561    struct droid_egl_driver *droid_drv = calloc(1, sizeof(*droid_drv));
562    if (!droid_drv)
563       return NULL;
564
565    _eglInitDriverFallbacks(&droid_drv->base);
566    droid_drv->base.API.Initialize = droid_eglInitialize;
567    droid_drv->base.API.Terminate = droid_eglTerminate;
568
569    droid_drv->base.API.GetProcAddress = droid_eglGetProcAddress;
570
571    droid_drv->base.API.CreateContext = droid_eglCreateContext;
572    droid_drv->base.API.DestroyContext = droid_eglDestroyContext;
573    droid_drv->base.API.MakeCurrent = droid_eglMakeCurrent;
574    droid_drv->base.API.CreateWindowSurface = droid_eglCreateWindowSurface;
575    droid_drv->base.API.DestroySurface = droid_eglDestroySurface;
576    droid_drv->base.API.SwapBuffers = droid_eglSwapBuffers;
577 #if EGL_KHR_image_base
578    droid_drv->base.API.CreateImageKHR = droid_eglCreateImageKHR;
579    droid_drv->base.API.DestroyImageKHR = droid_eglDestroyImageKHR;
580 #endif /* EGL_KHR_image_base */
581    droid_drv->base.API.WaitClient = droid_eglWaitClient;
582    droid_drv->base.API.WaitNative = droid_eglWaitNative;
583
584    droid_drv->base.Name = "Android/i915";
585    droid_drv->base.Unload = droid_Unload;
586
587    /* we need a way to flush commands */
588    droid_drv->flush_current =
589       (void (*)(void)) droid_eglGetProcAddress("glFlush");
590    droid_drv->finish_current =
591       (void (*)(void)) droid_eglGetProcAddress("glFinish");
592
593    _eglSetLogProc(droid_Log);
594
595    return &droid_drv->base;
596 }