OSDN Git Service

e9e011468326ae50495fd50d80a950a2332f943e
[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 #include "glapi/glapi.h"
25
26 #include "eglconfig.h"
27 #include "eglcontext.h"
28 #include "egldisplay.h"
29 #include "egldriver.h"
30 #include "eglglobals.h"
31 #include "egllog.h"
32 #include "eglsurface.h"
33 #include "eglimage.h"
34
35 #include "droid.h"
36
37 #ifndef DROID_DEVICE_PATH
38 #define DROID_DEVICE_PATH "/dev/dri/card0"
39 #endif
40
41 struct droid_egl_driver
42 {
43    _EGLDriver base;
44
45    /* EGL_DEFAULT_DISPLAY */
46    struct droid_egl_display *default_display;
47    void (*flush_current)(void);
48    void (*finish_current)(void);
49 };
50
51 struct droid_egl_display
52 {
53    EGLint refcnt;
54
55    EGLint apis;
56    EGLint major;
57    EGLint minor;
58
59    struct droid_backend *backend;
60    struct droid_screen *screen;
61 };
62
63 struct droid_egl_context {
64    _EGLContext base;
65    struct droid_context *context;
66 };
67
68 struct droid_egl_surface {
69    _EGLSurface base;
70    struct droid_drawable *drawable;
71    struct droid_surface *surface;
72 };
73
74 struct droid_egl_image {
75    _EGLImage base;
76    struct droid_drawable *drawable;
77    struct droid_surface *surface;
78 };
79
80 struct droid_egl_config {
81    _EGLConfig base;
82    const __DRIconfig *config;
83 };
84
85 static INLINE struct droid_egl_driver *
86 lookup_driver(_EGLDriver *drv)
87 {
88    return (struct droid_egl_driver *) drv;
89 }
90
91 static INLINE struct droid_egl_display *
92 lookup_display(_EGLDisplay *dpy)
93 {
94    return (struct droid_egl_display *) dpy->DriverData;
95 }
96
97 static INLINE struct droid_egl_context *
98 lookup_context(_EGLContext *context)
99 {
100    return (struct droid_egl_context *) context;
101 }
102
103 static INLINE struct droid_egl_surface *
104 lookup_surface(_EGLSurface *surface)
105 {
106    return (struct droid_egl_surface *) surface;
107 }
108
109 static INLINE struct droid_egl_image *
110 lookup_image(_EGLImage *image)
111 {
112    return (struct droid_egl_image *) image;
113 }
114
115 static INLINE struct droid_egl_config *
116 lookup_config(_EGLConfig *conf)
117 {
118    return (struct droid_egl_config *) conf;
119 }
120
121 static void
122 droid_create_configs(_EGLDisplay *dpy, struct droid_egl_display *droid_dpy,
123                      const __DRIconfig **configs, EGLint num_configs)
124 {
125    EGLint i;
126    EGLint id = 1;
127
128    for (i = 0; i < num_configs; i++) {
129       struct droid_egl_config *droid_conf = calloc(1, sizeof(*droid_conf));
130       EGLint val;
131
132       if (!droid_conf)
133          break;
134
135       _eglInitConfig(&droid_conf->base, id);
136       droid_conf->config = configs[i];
137       droid_screen_convert_config(droid_dpy->screen, droid_conf->config,
138                                   &droid_conf->base);
139
140       val = GET_CONFIG_ATTRIB(&droid_conf->base, EGL_CONFIG_CAVEAT);
141       /* we do not want slow configs */
142       if (val == EGL_SLOW_CONFIG) {
143          free(droid_conf);
144       } else {
145          _eglAddConfig(dpy, &droid_conf->base);
146          id++;
147       }
148    }
149 }
150
151
152 static EGLBoolean
153 droid_initialize_display(struct droid_egl_display *droid_dpy)
154 {
155    const char *path = DROID_DEVICE_PATH;
156
157    droid_dpy->backend = droid_backend_create_intel(path);
158    if (!droid_dpy->backend)
159       return EGL_FALSE;
160
161    droid_dpy->screen = droid_screen_create(droid_dpy->backend);
162    if (!droid_dpy->screen) {
163       free(droid_dpy->backend);
164       droid_dpy->backend = NULL;
165       return EGL_FALSE;
166    }
167
168    droid_dpy->apis = EGL_OPENGL_ES_BIT;
169    droid_dpy->major = 1;
170    droid_dpy->major = 4;
171
172    return EGL_TRUE;
173 }
174
175 static EGLBoolean
176 droid_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,
177                     EGLint *major, EGLint *minor)
178 {
179    struct droid_egl_driver *droid_drv = lookup_driver(drv);
180    struct droid_egl_display *droid_dpy;
181
182    if (dpy->NativeDisplay != EGL_DEFAULT_DISPLAY)
183       return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
184
185    /* the default display */
186    droid_dpy = droid_drv->default_display;
187    if (!droid_dpy) {
188       droid_dpy = calloc(1, sizeof(*droid_dpy));
189       if (!droid_dpy)
190          return _eglError(EGL_BAD_ALLOC, "eglInitialize");
191       if (!droid_initialize_display(droid_dpy))
192          return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
193
194       droid_create_configs(dpy, droid_dpy, droid_dpy->screen->dri_configs,
195                            droid_dpy->screen->num_dri_configs);
196
197 #if EGL_KHR_image_base
198       if (droid_dpy->backend->create_image_surface) {
199          dpy->Extensions.KHR_image = EGL_TRUE;
200          dpy->Extensions.KHR_image_base = EGL_TRUE;
201          dpy->Extensions.KHR_image_pixmap = EGL_TRUE;
202       }
203 #endif
204
205       droid_drv->default_display = droid_dpy;
206    }
207
208    dpy->DriverData = (void *) droid_dpy;
209    droid_dpy->refcnt++;
210
211    *major = droid_dpy->major;
212    *minor = droid_dpy->minor;
213
214    return EGL_TRUE;
215 }
216
217 static EGLBoolean
218 droid_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
219 {
220    struct droid_egl_driver *droid_drv = lookup_driver(drv);
221    struct droid_egl_display *droid_dpy = lookup_display(dpy);
222
223    dpy->DriverData = NULL;
224    droid_dpy->refcnt--;
225    if (!droid_dpy->refcnt) {
226       _eglReleaseDisplayResources(drv, dpy);
227       _eglCleanupDisplay(dpy);
228
229       free(droid_dpy);
230       droid_drv->default_display = NULL;
231    }
232
233    return EGL_TRUE;
234 }
235
236 static _EGLProc
237 droid_eglGetProcAddress(const char *procname)
238 {
239    return (_EGLProc) _glapi_get_proc_address(procname);
240 }
241
242 static _EGLContext *
243 droid_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
244                        _EGLContext *share_list, const EGLint *attrib_list)
245 {
246    struct droid_egl_display *droid_dpy = lookup_display(dpy);
247    struct droid_egl_config *droid_conf = lookup_config(conf);
248    struct droid_egl_context *shared = lookup_context(share_list);
249    struct droid_egl_context *ctx;
250
251    ctx = calloc(1, sizeof(*ctx));
252    if (!ctx) {
253       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
254       return NULL;
255    }
256
257    if (!_eglInitContext(drv, &ctx->base, &droid_conf->base, attrib_list)) {
258       free(ctx);
259       return NULL;
260    }
261
262    ctx->context =
263       droid_screen_create_context(droid_dpy->screen, droid_conf->config,
264                                   (shared) ? shared->context : NULL);
265    if (!ctx->context) {
266       free(ctx);
267       return NULL;
268    }
269
270    return &ctx->base;
271 }
272
273 static EGLBoolean
274 droid_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
275 {
276    struct droid_egl_display *droid_dpy = lookup_display(dpy);
277    struct droid_egl_context *droid_ctx = lookup_context(ctx);
278
279    if (!_eglIsContextBound(ctx))
280       droid_screen_destroy_context(droid_dpy->screen, droid_ctx->context);
281
282    return EGL_TRUE;
283 }
284
285 static EGLBoolean
286 droid_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d,
287                      _EGLSurface *r, _EGLContext *ctx)
288 {
289    struct droid_egl_driver *droid_drv = lookup_driver(drv);
290    struct droid_egl_display *droid_dpy = lookup_display(dpy);
291    struct droid_egl_surface *draw = lookup_surface(d);
292    struct droid_egl_surface *read = lookup_surface(r);
293    struct droid_egl_context *droid_ctx = lookup_context(ctx);
294    _EGLContext *old;
295    struct droid_egl_context *droid_old;
296
297    old = _eglGetCurrentContext();
298    /* an unlinked context will be invalid after context switch */
299    if (!_eglIsContextLinked(old))
300       old = NULL;
301
302    droid_old = lookup_context(old);
303
304    if (!_eglMakeCurrent(drv, dpy, d, r, ctx))
305       return EGL_FALSE;
306
307    if (droid_old && droid_old != droid_ctx && droid_drv->flush_current)
308       droid_drv->flush_current();
309
310    _glapi_check_multithread();
311
312    /* bind new context or unbind old one */
313    if (droid_ctx)
314       droid_screen_bind_context(droid_dpy->screen,
315                                 draw->drawable, read->drawable,
316                                 droid_ctx->context);
317    else if (droid_old)
318       droid_screen_bind_context(droid_dpy->screen,
319                                 NULL, NULL,
320                                 droid_old->context);
321
322    return EGL_TRUE;
323 }
324
325 static _EGLSurface *
326 droid_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
327                              NativeWindowType window, const EGLint *attrib_list)
328 {
329    struct droid_egl_display *droid_dpy = lookup_display(dpy);
330    struct droid_egl_config *droid_conf = lookup_config(conf);
331    struct droid_egl_surface *surf;
332
333    surf = calloc(1, sizeof(*surf));
334    if (!surf) {
335       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
336       return NULL;
337    }
338
339    if (!_eglInitSurface(drv, &surf->base, EGL_WINDOW_BIT, &droid_conf->base, attrib_list)) {
340       free(surf);
341       return NULL;
342    }
343
344    surf->surface =
345       droid_dpy->backend->create_window_surface(droid_dpy->backend,
346                                                 &surf->base, window);
347    if (!surf->surface) {
348       free(surf);
349       return NULL;
350    }
351
352    surf->drawable = droid_screen_create_drawable(droid_dpy->screen,
353                                                  droid_conf->config,
354                                                  surf->surface);
355    if (!surf->drawable) {
356       droid_dpy->backend->destroy_surface(droid_dpy->backend, surf->surface);
357       free(surf);
358       return NULL;
359    }
360
361    return &surf->base;
362 }
363
364 static EGLBoolean
365 droid_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
366 {
367    struct droid_egl_display *droid_dpy = lookup_display(dpy);
368    struct droid_egl_surface *droid_surf = lookup_surface(surf);
369
370    if (_eglIsSurfaceBound(&droid_surf->base))
371       return EGL_TRUE;
372
373    droid_screen_destroy_drawable(droid_dpy->screen, droid_surf->drawable);
374    droid_dpy->backend->destroy_surface(droid_dpy->backend, droid_surf->surface);
375    free(droid_surf);
376
377    return EGL_TRUE;
378 }
379
380 static EGLBoolean
381 droid_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
382 {
383    struct droid_egl_driver *droid_drv = lookup_driver(drv);
384    struct droid_egl_display *droid_dpy = lookup_display(dpy);
385    struct droid_egl_surface *droid_surf = lookup_surface(surf);
386    _EGLContext *ctx = _eglGetCurrentContext();
387    struct droid_egl_context *droid_ctx = lookup_context(ctx);
388
389    if (droid_ctx) {
390       if (droid_drv->flush_current)
391          droid_drv->flush_current();
392
393       droid_screen_swap_buffers(droid_dpy->screen,
394                                 droid_ctx->context,
395                                 droid_surf->drawable);
396    }
397
398    return EGL_TRUE;
399 }
400
401 #if EGL_KHR_image_base
402
403 static _EGLImage *
404 droid_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
405                        EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list)
406 {
407    struct droid_egl_display *droid_dpy = lookup_display(dpy);
408    struct droid_egl_image *droid_img;
409    const __DRIconfig *dri_conf;
410    int depth;
411
412    if (target != EGL_NATIVE_PIXMAP_KHR || ctx) {
413       _eglError(EGL_BAD_PARAMETER, "eglCreateImageKHR");
414       return NULL;
415    }
416
417    droid_img = calloc(1, sizeof(*droid_img));
418    if (!droid_img) {
419       _eglError(EGL_BAD_ALLOC, "eglCreateImageKHR");
420       return NULL;
421    }
422
423    if (!_eglInitImage(drv, &droid_img->base, attr_list)) {
424       free(droid_img);
425       return NULL;
426    }
427
428    droid_img->surface = 
429       droid_dpy->backend->create_image_surface(droid_dpy->backend,
430                                                (NativePixmapType) buffer,
431                                                &depth);
432    if (!droid_img->surface) {
433       free(droid_img);
434       return NULL;
435    }
436
437    dri_conf = droid_dpy->screen->image_configs[depth];
438    if (!dri_conf) {
439       droid_dpy->backend->destroy_surface(droid_dpy->backend,
440                                           droid_img->surface);
441       free(droid_img);
442       return NULL;
443    }
444
445    droid_img->drawable =
446       droid_screen_create_drawable(droid_dpy->screen, dri_conf,
447                                    droid_img->surface);
448
449    if (!droid_img->drawable) {
450       droid_dpy->backend->destroy_surface(droid_dpy->backend,
451                                           droid_img->surface);
452       free(droid_img);
453       return NULL;
454    }
455
456    droid_img->base.ClientData =
457       droid_screen_get_drawable_data(droid_dpy->screen, droid_img->drawable);
458
459    return &droid_img->base;
460 }
461
462
463 static EGLBoolean
464 droid_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img)
465 {
466    struct droid_egl_display *droid_dpy = lookup_display(dpy);
467    struct droid_egl_image *droid_img = lookup_image(img);
468
469    droid_screen_destroy_drawable(droid_dpy->screen, droid_img->drawable);
470    droid_dpy->backend->destroy_surface(droid_dpy->backend, droid_img->surface);
471    free(droid_img);
472
473    return EGL_TRUE;
474 }
475
476 #endif /* EGL_KHR_image_base */
477
478 static EGLBoolean
479 droid_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy)
480 {
481    struct droid_egl_driver *droid_drv = lookup_driver(drv);
482    _EGLContext *ctx = _eglGetCurrentContext();
483
484    if (!ctx || !droid_drv->finish_current)
485       return EGL_TRUE;
486
487    if (!_eglIsSurfaceLinked(ctx->DrawSurface))
488       return _eglError(EGL_BAD_CURRENT_SURFACE, "eglWaitClient");
489
490    droid_drv->finish_current();
491
492    return EGL_TRUE;
493 }
494
495 static EGLBoolean
496 droid_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
497 {
498    struct droid_egl_display *droid_dpy = lookup_display(dpy);
499    _EGLContext *ctx = _eglGetCurrentContext();
500    struct droid_egl_surface *droid_surf;
501
502    if (engine != EGL_CORE_NATIVE_ENGINE)
503       return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
504
505    if (!ctx) 
506       return EGL_TRUE;
507
508    if (!_eglIsSurfaceLinked(ctx->DrawSurface))
509       return _eglError(EGL_BAD_CURRENT_SURFACE, "eglWaitNative");
510
511    droid_surf = lookup_surface(ctx->DrawSurface);
512    droid_dpy->backend->swap_native_buffers(droid_dpy->backend,
513                                            droid_surf->surface);
514
515    return EGL_TRUE;
516 }
517
518 static void
519 droid_Unload(_EGLDriver *drv)
520 {
521    struct droid_egl_driver *droid_drv = lookup_driver(drv);
522    free(droid_drv);
523 }
524
525 _EGLDriver *
526 _eglMain(const char *args)
527 {
528    struct droid_egl_driver *droid_drv = calloc(1, sizeof(*droid_drv));
529    if (!droid_drv)
530       return NULL;
531
532    _eglInitDriverFallbacks(&droid_drv->base);
533    droid_drv->base.API.Initialize = droid_eglInitialize;
534    droid_drv->base.API.Terminate = droid_eglTerminate;
535
536    droid_drv->base.API.GetProcAddress = droid_eglGetProcAddress;
537
538    droid_drv->base.API.CreateContext = droid_eglCreateContext;
539    droid_drv->base.API.DestroyContext = droid_eglDestroyContext;
540    droid_drv->base.API.MakeCurrent = droid_eglMakeCurrent;
541    droid_drv->base.API.CreateWindowSurface = droid_eglCreateWindowSurface;
542    droid_drv->base.API.DestroySurface = droid_eglDestroySurface;
543    droid_drv->base.API.SwapBuffers = droid_eglSwapBuffers;
544 #if EGL_KHR_image_base
545    droid_drv->base.API.CreateImageKHR = droid_eglCreateImageKHR;
546    droid_drv->base.API.DestroyImageKHR = droid_eglDestroyImageKHR;
547 #endif /* EGL_KHR_image_base */
548    droid_drv->base.API.WaitClient = droid_eglWaitClient;
549    droid_drv->base.API.WaitNative = droid_eglWaitNative;
550
551    droid_drv->base.Name = "Android/i915";
552    droid_drv->base.Unload = droid_Unload;
553
554    /* we need a way to flush commands */
555    droid_drv->flush_current =
556       (void (*)(void)) droid_eglGetProcAddress("glFlush");
557    droid_drv->finish_current =
558       (void (*)(void)) droid_eglGetProcAddress("glFinish");
559
560    return &droid_drv->base;
561 }