OSDN Git Service

0955aaa67e6e868fa77532c54d37a5706a00e7af
[android-x86/external-mesa.git] / src / egl / drivers / android / droid_intel.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 to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that copyright
10  * notice and this permission notice appear in supporting documentation, and
11  * that the name of the copyright holders not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  The copyright holders make no representations
14  * about the suitability of this software for any purpose.  It is provided "as
15  * is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23  * OF THIS SOFTWARE.
24  */
25
26 #define LOG_TAG "DROID-INTEL"
27 #include <utils/Log.h>
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdint.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <i915_drm.h>
38 #include <GL/gl.h> /* dri_interface.h uses some GL integer types... */
39 #include <GL/internal/dri_interface.h>
40 #include <EGL/egl.h>
41
42 #include "droid.h"
43 #include "droid_ui.h"
44
45 #define INTEL_IS_I965(x) ((x) & INTEL_GEN_4)
46 #define INTEL_IS_I915(x) ((x) & INTEL_GEN_3)
47 #define INTEL_IS_I9xx(x) ((x) & (INTEL_GEN_3 | INTEL_GEN_4))
48 #define INTEL_IS_I8xx(x) ((x) & (INTEL_GEN_1 | INTEL_GEN_2))
49
50 #define INTEL_HAS_128_BYTE_Y_TILING(x) \
51    (((x) & (INTEL_GEN_3 | INTEL_GEN_4 | INTEL_GEN_MINOR_MASK)) > INTEL_GEN_3)
52
53 enum {
54    INTEL_SURFACE_TYPE_WINDOW,
55    INTEL_SURFACE_TYPE_IMAGE,
56 };
57
58 /* Look at xf86-video-intel/src/common.h for the full horror of device
59  * identification.
60  */
61 enum {
62         INTEL_GEN_1  = 0x10,
63         INTEL_GEN_2  = 0x20,
64         INTEL_GEN_3  = 0x40,
65         INTEL_GEN_31 = 0x41,
66         INTEL_GEN_4  = 0x80,
67
68         INTEL_GEN_MAJOR_MASK = 0xf0,
69         INTEL_GEN_MINOR_MASK = 0x0f,
70 };
71
72 struct droid_backend_intel {
73    struct droid_backend base;
74    int fd;
75    int screen_number;
76
77    uint32_t generation;
78    int pitch_align;
79    int enable_tiling;
80 };
81
82 struct droid_surface_intel {
83    int type;
84    union {
85       NativeWindowType win;
86       NativePixmapType pix;
87    } native;
88    __DRIbuffer native_buffer;
89    unsigned int native_width, native_height;
90    int native_changed;
91
92    unsigned int attachments[20];
93    __DRIbuffer buffers[10];
94    uint32_t handles[10];
95    int num_buffers;
96    int depth_idx;
97
98    _EGLSurface *surf;
99 };
100
101 static INLINE struct droid_backend_intel *
102 lookup_backend(struct droid_backend *backend)
103 {
104    return (struct droid_backend_intel *) backend;
105 }
106
107 static INLINE struct droid_surface_intel *
108 lookup_surface(struct droid_surface *surface)
109 {
110    return (struct droid_surface_intel *) surface;
111 }
112
113 static __DRIbuffer *
114 intel_get_native_buffer(struct droid_backend *backend,
115                         struct droid_surface *surf,
116                         int *width, int *height)
117 {
118    struct droid_surface_intel *isurf = lookup_surface(surf);
119
120    /* non-window surface is single-buffered */
121    if (isurf->type != INTEL_SURFACE_TYPE_WINDOW)
122       return NULL;
123
124    if (!isurf->native_buffer.name)
125       return NULL;
126
127    if (width)
128       *width = isurf->native_width;
129    if (height)
130       *height = isurf->native_height;
131
132    return &isurf->native_buffer;
133 }
134
135 static INLINE uint32_t
136 align_to(uint32_t value, uint32_t align)
137 {
138    return (value + align - 1) & ~(align - 1);
139 }
140
141 static INLINE int
142 fence_pitch(struct droid_backend *backend, int pitch, int tiling)
143 {
144    struct droid_backend_intel *intel = lookup_backend(backend);
145    int pitch_align, tile_width;
146
147    switch (tiling) {
148    case I915_TILING_NONE:
149    default:
150       pitch_align = intel->pitch_align;
151       tile_width = 1; /* not used */
152       break;
153    case I915_TILING_X:
154       pitch_align = 512;
155       tile_width = 512;
156       break;
157    case I915_TILING_Y:
158       pitch_align = 512;
159       tile_width =
160          (INTEL_HAS_128_BYTE_Y_TILING(intel->generation)) ? 128 : 512;
161       break;
162    }
163
164    pitch = align_to(pitch, pitch_align);
165    if (tiling == I915_TILING_NONE)
166       return pitch;
167
168    /* 965+ just needs multiples of tile width */
169    if (INTEL_IS_I965(intel->generation)) {
170       pitch = align_to(pitch,  tile_width);
171    }
172    else {
173       /* Pre-965 needs power of two tile widths */
174       while (tile_width < pitch)
175          tile_width <<= 1;
176       pitch = tile_width;
177    }
178
179    return pitch;
180 }
181
182 static INLINE uint32_t
183 fence_size(struct droid_backend *backend, int height, int pitch, int tiling)
184 {
185    struct droid_backend_intel *intel = lookup_backend(backend);
186    int height_align;
187    uint32_t size;
188
189    switch (tiling) {
190    case I915_TILING_NONE:
191    default:
192       /* Round the height up so that the GPU's access to a 2x2 aligned
193        * subspan doesn't address an invalid page offset beyond the
194        * end of the GTT.
195        */
196       height_align = 2;
197       break;
198    case I915_TILING_X:
199       height_align = 8;
200       break;
201    case I915_TILING_Y:
202       height_align = 32;
203       break;
204    }
205
206    height = align_to(height, height_align);
207    size = pitch * height;
208    if (tiling == I915_TILING_NONE)
209       return size;
210
211    /* The 965 can have fences at any page boundary. */
212    if (INTEL_IS_I965(intel->generation)) {
213       size = align_to(size, 4096);
214    }
215    else {
216       uint32_t fence;
217
218       /* Align the size to a power of two greater than the smallest fence. */
219       if (INTEL_IS_I9xx(intel->generation))
220          fence = 1 << 20; /* 1 MiB */
221       else
222          fence = 1 << 19; /* 512 KiB */
223
224       while (fence < size)
225          fence <<= 1;
226
227       size = fence;
228    }
229
230    return size;
231 }
232
233 static int
234 create_buffer(struct droid_backend *backend, __DRIbuffer *buffer,
235               int width, int height, int cpp, int tiling)
236 {
237    struct droid_backend_intel *intel = lookup_backend(backend);
238    struct drm_i915_gem_create create;
239    struct drm_gem_flink flink;
240
241    buffer->pitch = fence_pitch(backend, width * cpp, tiling);
242    create.size = fence_size(backend, height, buffer->pitch, tiling);
243    if (ioctl(intel->fd, DRM_IOCTL_I915_GEM_CREATE, &create)) {
244       LOGE("failed to create buffer");
245       return 0;
246    }
247
248    if (tiling != I915_TILING_NONE) {
249       struct drm_i915_gem_set_tiling set_tiling;
250
251       memset(&set_tiling, 0, sizeof(set_tiling));
252       set_tiling.handle = create.handle;
253       set_tiling.tiling_mode = tiling;
254       set_tiling.stride = buffer->pitch;
255
256       if (ioctl(intel->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling))
257          LOGW("failed to enable tiling");
258    }
259
260    flink.handle = create.handle;
261    if (ioctl(intel->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
262       LOGE("failed to flink buffer");
263       return 0;
264    }
265
266    buffer->name = flink.name;
267    buffer->cpp = cpp;
268    buffer->flags = 0;
269
270    return create.handle;
271 }
272
273 static void
274 delete_buffers(struct droid_backend *backend, struct droid_surface *surf)
275 {
276    struct droid_backend_intel *intel = lookup_backend(backend);
277    struct droid_surface_intel *isurf = lookup_surface(surf);
278    int i;
279
280    for (i = 0; i < isurf->num_buffers; i++) {
281       if (isurf->handles[i]) {
282          struct drm_gem_close close;
283
284          close.handle = isurf->handles[i];
285          if (ioctl(intel->fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
286             LOGE("failed to close bo %d", close.handle);
287          isurf->handles[i] = 0;
288       }
289    }
290
291    isurf->num_buffers = 0;
292 }
293
294 static __DRIbuffer *
295 intel_get_surface_buffers(struct droid_backend *backend,
296                           struct droid_surface *surf,
297                           int *width, int *height,
298                           unsigned int *attachments, int count,
299                           int *out_count, int has_format)
300 {
301    struct droid_backend_intel *intel = lookup_backend(backend);
302    struct droid_surface_intel *isurf = lookup_surface(surf);
303    unsigned int att_size;
304    __DRIbuffer buffers[10];
305    uint32_t handles[10];
306    int num = 0;
307
308    if (count > 10) {
309       LOGW("too many buffers requested");
310       count = 10;
311    }
312
313    att_size = sizeof(attachments[0]) * count * ((has_format) ? 2 : 1);
314
315    if (isurf->native_changed) {
316       delete_buffers(backend, surf);
317       isurf->native_changed = 0;
318    }
319
320    /* same buffers requested */
321    if (isurf->num_buffers == count &&
322        memcmp(isurf->attachments, attachments, att_size) == 0) {
323       num = isurf->num_buffers;
324       goto end;
325    }
326    memcpy(isurf->attachments, attachments, att_size);
327
328    while (count-- > 0) {
329       unsigned int att = *attachments++;
330       unsigned int format = (has_format) ? *attachments++ : 0;
331       unsigned int cpp = (format) ? format / 8 : isurf->native_buffer.cpp;
332       __DRIbuffer *buf = NULL;
333       int reuse;
334
335       /* re-use buffer */
336       for (reuse = 0; reuse < isurf->num_buffers; reuse++) {
337          if (isurf->buffers[reuse].attachment == att) {
338             if (isurf->buffers[reuse].cpp == cpp &&
339                 isurf->handles[reuse])
340                buf = &isurf->buffers[reuse];
341             break;
342          }
343       }
344
345       if (0)
346          LOGD("%s buffer %d: att %d cpp %d",
347                (buf) ? "reuse" : "create", num, att, cpp);
348
349       if (buf) {
350          buffers[num] = isurf->buffers[reuse];
351          handles[num] = isurf->handles[reuse];
352          isurf->handles[reuse] = 0;
353       }
354       else {
355          int tiling =
356             (intel->enable_tiling) ? I915_TILING_X : I915_TILING_NONE;
357
358          buffers[num].attachment = att;
359
360          if (isurf->type == INTEL_SURFACE_TYPE_IMAGE &&
361              att == __DRI_BUFFER_FRONT_LEFT) {
362             /* return native buffer */
363             buffers[num] = isurf->native_buffer;
364             buffers[num].attachment = att;
365             handles[num] = 0;
366          } else {
367             buffers[num].attachment = att;
368             handles[num] = create_buffer(backend, &buffers[num],
369                                          isurf->native_width,
370                                          isurf->native_height,
371                                          cpp,
372                                          tiling);
373          }
374       }
375       num++;
376    }
377
378    /* delete old buffers that are not re-used */
379    delete_buffers(backend, surf);
380
381    memcpy(isurf->buffers, buffers, sizeof(buffers[0]) * num);
382    memcpy(isurf->handles, handles, sizeof(handles[0]) * num);
383    isurf->num_buffers = num;
384
385 end:
386    *out_count = num;
387    *width = isurf->native_width;
388    *height = isurf->native_height;
389
390    return isurf->buffers;
391 }
392
393 static void
394 update_native_buffer(struct droid_surface *surf)
395 {
396    struct droid_surface_intel *isurf = lookup_surface(surf);
397    __DRIbuffer *buf = &isurf->native_buffer;
398    unsigned int name, cpp, pitch, width, height;
399
400    switch (isurf->type) {
401    case INTEL_SURFACE_TYPE_WINDOW:
402       /* oem[0] always point to the buffer that a client is drawing to */
403       name = isurf->native.win->oem[0];
404       cpp = ui_bytes_per_pixel(isurf->native.win->format);
405       pitch = isurf->native.win->stride * cpp;
406       width = isurf->native.win->width;
407       height = isurf->native.win->height;
408       break;
409    case INTEL_SURFACE_TYPE_IMAGE:
410       name = isurf->native.pix->reserved;
411       cpp = ui_bytes_per_pixel(isurf->native.pix->format);
412       pitch = isurf->native.pix->stride * cpp;
413       width = isurf->native.pix->width;
414       height = isurf->native.pix->height;
415       break;
416    default:
417       name = cpp = pitch = width = height = 0;
418       break;
419    }
420
421    if (buf->name != name || buf->cpp != cpp || buf->pitch != pitch ||
422        isurf->native_width != width || isurf->native_height != height) {
423       buf->attachment = __DRI_BUFFER_FRONT_LEFT;
424       buf->name = name;
425       buf->cpp = cpp;
426       buf->pitch = pitch;
427       buf->flags = 0;
428
429       isurf->native_width = width;
430       isurf->native_height = height;
431
432       isurf->native_changed = 1;
433    }
434 }
435
436 static struct droid_surface *
437 intel_create_window_surface(struct droid_backend *backend,
438                             _EGLSurface *surf,
439                             NativeWindowType win)
440 {
441    struct droid_surface_intel *isurf;
442
443    if (!win) {
444       LOGE("invalid native window");
445       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
446       return NULL;
447    }
448
449    /* TODO lift this limitation */
450    if (!win->oem[0]) {
451       LOGE("TODO support for non-gem based window");
452       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
453       return NULL;
454    }
455
456    isurf = calloc(1, sizeof(*isurf));
457    if (!isurf) {
458       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
459       return NULL;
460    }
461
462    isurf->type = INTEL_SURFACE_TYPE_WINDOW;
463    isurf->native.win = win;
464
465    surf->Width = win->width;
466    surf->Height = win->height;
467    /* always back buffer */
468    surf->RenderBuffer = EGL_BACK_BUFFER;
469
470    isurf->surf = surf;
471
472    update_native_buffer((struct droid_surface *) isurf);
473
474    return (struct droid_surface *) isurf;
475 }
476
477 static struct droid_surface *
478 intel_create_image_surface(struct droid_backend *backend,
479                            NativePixmapType pix)
480 {
481    struct droid_surface_intel *isurf;
482    int cpp;
483
484    if (!pix) {
485       LOGE("invalid native pixmap");
486       _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
487       return NULL;
488    }
489
490    /* TODO lift this limitation */
491    if (!pix->reserved) {
492       LOGE("TODO support for non-gem based pixmap");
493       _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
494       return NULL;
495    }
496
497    isurf = calloc(1, sizeof(*isurf));
498    if (!isurf) {
499       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
500       return NULL;
501    }
502
503    isurf->type = INTEL_SURFACE_TYPE_IMAGE;
504    isurf->native.pix = pix;
505
506    update_native_buffer((struct droid_surface *) isurf);
507
508    return (struct droid_surface *) isurf;
509 }
510
511 static void
512 intel_destroy_surface(struct droid_backend *backend, struct droid_surface *surf)
513 {
514    struct droid_surface_intel *isurf = lookup_surface(surf);
515    delete_buffers(backend, surf);
516    free(isurf);
517 }
518
519 static void
520 intel_swap_native_buffers(struct droid_backend *backend,
521                           struct droid_surface *surf)
522 {
523    struct droid_surface_intel *isurf = lookup_surface(surf);
524
525    if (isurf->type == INTEL_SURFACE_TYPE_WINDOW) {
526       uint32_t flags;
527
528       flags = isurf->native.win->swapBuffers(isurf->native.win);
529       if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
530          update_native_buffer(surf);
531       } else {
532          /* oem[0] is changed after buffer swap */
533          isurf->native_buffer.name = isurf->native.win->oem[0];
534       }
535    }
536 }
537
538 static int
539 intel_match_pixmap(struct droid_backend *backend, _EGLConfig *conf,
540                    NativePixmapType pix)
541 {
542    int val;
543    val = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE);
544    /* match the visual type */
545    return (pix->format == val);
546 }
547
548 static int
549 intel_initialize(struct droid_backend *backend, int *fd, int *screen_number)
550 {
551    struct droid_backend_intel *intel = lookup_backend(backend);
552    drm_auth_t auth;
553    int err;
554
555    err = ioctl(intel->fd, DRM_IOCTL_GET_MAGIC, &auth);
556    if (!err)
557       err = ui_auth_gpu(auth.magic);
558
559    if (err) {
560       LOGE("failed to authenticate");
561       return 0;
562    }
563
564    if (fd)
565       *fd = intel->fd;
566    if (screen_number)
567       *screen_number = intel->screen_number;
568
569    return 1;
570 }
571
572 #include <assert.h>
573 static int
574 intel_process_config(struct droid_backend *backend, _EGLConfig *conf)
575 {
576    int r, g, b, a;
577    int surface_type;
578    int format;
579
580    r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
581    g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
582    b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
583    a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
584    format = ui_get_rgb_format(r, g, b, a);
585
586    if (format) {
587       SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, format);
588       SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE,
589                         EGL_WINDOW_BIT |
590                         EGL_PIXMAP_BIT |
591                         EGL_PBUFFER_BIT);
592    }
593    else {
594       SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT);
595    }
596
597    return 1;
598 }
599
600 static void
601 intel_destroy(struct droid_backend *backend)
602 {
603    struct droid_backend_intel *intel = lookup_backend(backend);
604    close(intel->fd);
605    free(intel);
606 }
607
608 struct droid_backend *
609 droid_backend_create_intel(const char *dev)
610 {
611    struct droid_backend_intel *intel;
612
613    intel = calloc(1, sizeof(*intel));
614    if (!intel)
615       return NULL;
616
617    intel->fd = open(dev, O_RDWR);
618    if (intel->fd < 0) {
619       LOGE("failed to open %s", dev);
620       free(intel);
621       return NULL;
622    }
623
624    intel->screen_number = 0;
625
626    /* XXX query using I915_GETPARAM + PARAM_CHIPSET_ID */
627    intel->generation = INTEL_GEN_3;
628
629    intel->pitch_align = 64;
630    intel->enable_tiling = 1;
631
632    intel->base.driver_name = "i915";
633    intel->base.initialize = intel_initialize;
634    intel->base.process_config = intel_process_config;
635    intel->base.destroy = intel_destroy;
636
637    intel->base.get_native_buffer = intel_get_native_buffer;
638    intel->base.get_surface_buffers = intel_get_surface_buffers;
639
640    intel->base.create_window_surface = intel_create_window_surface;
641    intel->base.create_image_surface = intel_create_image_surface;
642    intel->base.destroy_surface = intel_destroy_surface;
643    intel->base.swap_native_buffers = intel_swap_native_buffers;
644
645    intel->base.match_pixmap = intel_match_pixmap;
646
647    return &intel->base;
648 }