OSDN Git Service

3b1afba2ea954a5a4cc18352e7a8f1a4faa9b12c
[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    if (!isurf->native_buffer.name)
121       return NULL;
122
123    if (width)
124       *width = isurf->native_width;
125    if (height)
126       *height = isurf->native_height;
127
128    return &isurf->native_buffer;
129 }
130
131 static INLINE uint32_t
132 align_to(uint32_t value, uint32_t align)
133 {
134    return (value + align - 1) & ~(align - 1);
135 }
136
137 static INLINE int
138 fence_pitch(struct droid_backend *backend, int pitch, int tiling)
139 {
140    struct droid_backend_intel *intel = lookup_backend(backend);
141    int pitch_align, tile_width;
142
143    switch (tiling) {
144    case I915_TILING_NONE:
145    default:
146       pitch_align = intel->pitch_align;
147       tile_width = 1; /* not used */
148       break;
149    case I915_TILING_X:
150       pitch_align = 512;
151       tile_width = 512;
152       break;
153    case I915_TILING_Y:
154       pitch_align = 512;
155       tile_width =
156          (INTEL_HAS_128_BYTE_Y_TILING(intel->generation)) ? 128 : 512;
157       break;
158    }
159
160    pitch = align_to(pitch, pitch_align);
161    if (tiling == I915_TILING_NONE)
162       return pitch;
163
164    /* 965+ just needs multiples of tile width */
165    if (INTEL_IS_I965(intel->generation)) {
166       pitch = align_to(pitch,  tile_width);
167    }
168    else {
169       /* Pre-965 needs power of two tile widths */
170       while (tile_width < pitch)
171          tile_width <<= 1;
172       pitch = tile_width;
173    }
174
175    return pitch;
176 }
177
178 static INLINE uint32_t
179 fence_size(struct droid_backend *backend, int height, int pitch, int tiling)
180 {
181    struct droid_backend_intel *intel = lookup_backend(backend);
182    int height_align;
183    uint32_t size;
184
185    switch (tiling) {
186    case I915_TILING_NONE:
187    default:
188       /* Round the height up so that the GPU's access to a 2x2 aligned
189        * subspan doesn't address an invalid page offset beyond the
190        * end of the GTT.
191        */
192       height_align = 2;
193       break;
194    case I915_TILING_X:
195       height_align = 8;
196       break;
197    case I915_TILING_Y:
198       height_align = 32;
199       break;
200    }
201
202    height = align_to(height, height_align);
203    size = pitch * height;
204    if (tiling == I915_TILING_NONE)
205       return size;
206
207    /* The 965 can have fences at any page boundary. */
208    if (INTEL_IS_I965(intel->generation)) {
209       size = align_to(size, 4096);
210    }
211    else {
212       uint32_t fence;
213
214       /* Align the size to a power of two greater than the smallest fence. */
215       if (INTEL_IS_I9xx(intel->generation))
216          fence = 1 << 20; /* 1 MiB */
217       else
218          fence = 1 << 19; /* 512 KiB */
219
220       while (fence < size)
221          fence <<= 1;
222
223       size = fence;
224    }
225
226    return size;
227 }
228
229 static int
230 create_buffer(struct droid_backend *backend, __DRIbuffer *buffer,
231               int width, int height, int cpp, int tiling)
232 {
233    struct droid_backend_intel *intel = lookup_backend(backend);
234    struct drm_i915_gem_create create;
235    struct drm_gem_flink flink;
236
237    buffer->pitch = fence_pitch(backend, width * cpp, tiling);
238    create.size = fence_size(backend, height, buffer->pitch, tiling);
239    if (ioctl(intel->fd, DRM_IOCTL_I915_GEM_CREATE, &create)) {
240       LOGE("failed to create buffer");
241       return 0;
242    }
243
244    if (tiling != I915_TILING_NONE) {
245       struct drm_i915_gem_set_tiling set_tiling;
246
247       memset(&set_tiling, 0, sizeof(set_tiling));
248       set_tiling.handle = create.handle;
249       set_tiling.tiling_mode = tiling;
250       set_tiling.stride = buffer->pitch;
251
252       if (ioctl(intel->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling))
253          LOGW("failed to enable tiling");
254    }
255
256    flink.handle = create.handle;
257    if (ioctl(intel->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
258       LOGE("failed to flink buffer");
259       return 0;
260    }
261
262    buffer->name = flink.name;
263    buffer->cpp = cpp;
264    buffer->flags = 0;
265
266    return create.handle;
267 }
268
269 static void
270 delete_buffers(struct droid_backend *backend, struct droid_surface *surf)
271 {
272    struct droid_backend_intel *intel = lookup_backend(backend);
273    struct droid_surface_intel *isurf = lookup_surface(surf);
274    int i;
275
276    for (i = 0; i < isurf->num_buffers; i++) {
277       if (isurf->handles[i]) {
278          struct drm_gem_close close;
279
280          close.handle = isurf->handles[i];
281          if (ioctl(intel->fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
282             LOGE("failed to close bo %d", close.handle);
283          isurf->handles[i] = 0;
284       }
285    }
286
287    isurf->num_buffers = 0;
288 }
289
290 static __DRIbuffer *
291 intel_get_surface_buffers(struct droid_backend *backend,
292                           struct droid_surface *surf,
293                           int *width, int *height,
294                           unsigned int *attachments, int count,
295                           int *out_count, int has_format)
296 {
297    struct droid_backend_intel *intel = lookup_backend(backend);
298    struct droid_surface_intel *isurf = lookup_surface(surf);
299    unsigned int att_size;
300    __DRIbuffer buffers[10];
301    uint32_t handles[10];
302    int num = 0;
303
304    if (count > 10) {
305       LOGW("too many buffers requested");
306       count = 10;
307    }
308
309    att_size = sizeof(attachments[0]) * count * ((has_format) ? 2 : 1);
310
311    if (isurf->native_changed) {
312       delete_buffers(backend, surf);
313       isurf->native_changed = 0;
314    }
315
316    /* same buffers requested */
317    if (isurf->num_buffers == count &&
318        memcmp(isurf->attachments, attachments, att_size) == 0) {
319       num = isurf->num_buffers;
320       goto end;
321    }
322    memcpy(isurf->attachments, attachments, att_size);
323
324    while (count-- > 0) {
325       unsigned int att = *attachments++;
326       unsigned int format = (has_format) ? *attachments++ : 0;
327       unsigned int cpp = (format) ? format / 8 : isurf->native_buffer.cpp;
328       __DRIbuffer *buf = NULL;
329       int reuse;
330
331       /* re-use buffer */
332       for (reuse = 0; reuse < isurf->num_buffers; reuse++) {
333          if (isurf->buffers[reuse].attachment == att) {
334             if (isurf->buffers[reuse].cpp == cpp &&
335                 isurf->handles[reuse])
336                buf = &isurf->buffers[reuse];
337             break;
338          }
339       }
340
341       if (0)
342          LOGD("%s buffer %d: att %d cpp %d",
343                (buf) ? "reuse" : "create", num, att, cpp);
344
345       if (buf) {
346          buffers[num] = isurf->buffers[reuse];
347          handles[num] = isurf->handles[reuse];
348          isurf->handles[reuse] = 0;
349       }
350       else {
351          int tiling =
352             (intel->enable_tiling) ? I915_TILING_X : I915_TILING_NONE;
353
354          buffers[num].attachment = att;
355
356          if (isurf->type == INTEL_SURFACE_TYPE_IMAGE &&
357              att == __DRI_BUFFER_FRONT_LEFT) {
358             buffers[num] = isurf->native_buffer;
359             buffers[num].attachment = att;
360             handles[num] = 0;
361          } else {
362             buffers[num].attachment = att;
363             handles[num] = create_buffer(backend, &buffers[num],
364                                          isurf->native_width,
365                                          isurf->native_height,
366                                          cpp,
367                                          tiling);
368          }
369       }
370       num++;
371    }
372
373    /* delete old buffers that are not re-used */
374    delete_buffers(backend, surf);
375
376    memcpy(isurf->buffers, buffers, sizeof(buffers[0]) * num);
377    memcpy(isurf->handles, handles, sizeof(handles[0]) * num);
378    isurf->num_buffers = num;
379
380 end:
381    *out_count = num;
382    *width = isurf->native_width;
383    *height = isurf->native_height;
384
385    return isurf->buffers;
386 }
387
388 static void
389 update_native_buffer(struct droid_surface *surf)
390 {
391    struct droid_surface_intel *isurf = lookup_surface(surf);
392    unsigned int name, cpp, pitch, width, height;
393
394    switch (isurf->type) {
395    case INTEL_SURFACE_TYPE_WINDOW:
396       /* oem[0] always point to the buffer that a client is drawing to */
397       name = isurf->native.win->oem[0];
398       cpp = ui_bytes_per_pixel(isurf->native.win->format);
399       pitch = isurf->native.win->stride * cpp;
400       width = isurf->native.win->width;
401       height = isurf->native.win->height;
402       break;
403    case INTEL_SURFACE_TYPE_IMAGE:
404       name = isurf->native.pix->reserved;
405       cpp = ui_bytes_per_pixel(isurf->native.pix->format);
406       pitch = isurf->native.pix->stride * cpp;
407       width = isurf->native.pix->width;
408       height = isurf->native.pix->height;
409       break;
410    default:
411       name = cpp = pitch = width = height = 0;
412       break;
413    }
414
415    isurf->native_buffer.attachment = __DRI_BUFFER_FRONT_LEFT;
416    isurf->native_buffer.name = name;
417    isurf->native_buffer.cpp = cpp;
418    isurf->native_buffer.pitch = pitch;
419    isurf->native_buffer.flags = 0;
420
421    isurf->native_width = width;
422    isurf->native_height = height;
423
424    isurf->native_changed = 1;
425 }
426
427 static struct droid_surface *
428 intel_create_window_surface(struct droid_backend *backend,
429                             _EGLSurface *surf,
430                             NativeWindowType win)
431 {
432    struct droid_surface_intel *isurf;
433
434    if (!win) {
435       LOGE("invalid native window");
436       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
437       return NULL;
438    }
439
440    /* TODO lift this limitation */
441    if (!win->oem[0]) {
442       LOGE("TODO support for non-gem based window");
443       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
444       return NULL;
445    }
446
447    isurf = calloc(1, sizeof(*isurf));
448    if (!isurf) {
449       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
450       return NULL;
451    }
452
453    isurf->type = INTEL_SURFACE_TYPE_WINDOW;
454    isurf->native.win = win;
455
456    surf->Width = win->width;
457    surf->Height = win->height;
458    /* always back buffer */
459    surf->RenderBuffer = EGL_BACK_BUFFER;
460
461    isurf->surf = surf;
462
463    update_native_buffer((struct droid_surface *) isurf);
464
465    return (struct droid_surface *) isurf;
466 }
467
468 static struct droid_surface *
469 intel_create_image_surface(struct droid_backend *backend,
470                            NativePixmapType pix, int *depth)
471 {
472    struct droid_surface_intel *isurf;
473    int cpp;
474
475    if (!pix) {
476       LOGE("invalid native pixmap");
477       _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
478       return NULL;
479    }
480
481    /* TODO lift this limitation */
482    if (!pix->reserved) {
483       LOGE("TODO support for non-gem based pixmap");
484       _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
485       return NULL;
486    }
487
488    cpp = ui_bytes_per_pixel(pix->format);
489    if (cpp * 8 > DROID_MAX_IMAGE_DEPTH) {
490       LOGE("pixmap of depth %d is not supported", cpp * 8);
491       _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
492       return NULL;
493    }
494
495    isurf = calloc(1, sizeof(*isurf));
496    if (!isurf) {
497       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
498       return NULL;
499    }
500
501    isurf->type = INTEL_SURFACE_TYPE_IMAGE;
502    isurf->native.pix = pix;
503
504    update_native_buffer((struct droid_surface *) isurf);
505
506    if (depth)
507       *depth = cpp * 8;
508
509    return (struct droid_surface *) isurf;
510 }
511
512 static void
513 intel_destroy_surface(struct droid_backend *backend, struct droid_surface *surf)
514 {
515    struct droid_surface_intel *isurf = lookup_surface(surf);
516    delete_buffers(backend, surf);
517    free(isurf);
518 }
519
520 static void
521 intel_swap_native_buffers(struct droid_backend *backend,
522                           struct droid_surface *surf)
523 {
524    struct droid_surface_intel *isurf = lookup_surface(surf);
525
526    if (isurf->type == INTEL_SURFACE_TYPE_WINDOW) {
527       uint32_t flags;
528
529       flags = isurf->native.win->swapBuffers(isurf->native.win);
530       if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
531          update_native_buffer(surf);
532       } else {
533          /* oem[0] is changed after buffer swap */
534          isurf->native_buffer.name = isurf->native.win->oem[0];
535       }
536    }
537 }
538
539 static int
540 intel_initialize(struct droid_backend *backend, int *fd, int *screen_number)
541 {
542    struct droid_backend_intel *intel = lookup_backend(backend);
543    drm_auth_t auth;
544    int err;
545
546    err = ioctl(intel->fd, DRM_IOCTL_GET_MAGIC, &auth);
547    if (!err)
548       err = ui_auth_gpu(auth.magic);
549
550    if (err) {
551       LOGE("failed to authenticate");
552       return 0;
553    }
554
555    if (fd)
556       *fd = intel->fd;
557    if (screen_number)
558       *screen_number = intel->screen_number;
559
560    return 1;
561 }
562
563 static void
564 intel_destroy(struct droid_backend *backend)
565 {
566    struct droid_backend_intel *intel = lookup_backend(backend);
567    close(intel->fd);
568    free(intel);
569 }
570
571 struct droid_backend *
572 droid_backend_create_intel(const char *dev)
573 {
574    struct droid_backend_intel *intel;
575
576    intel = calloc(1, sizeof(*intel));
577    if (!intel)
578       return NULL;
579
580    intel->fd = open(dev, O_RDWR);
581    if (intel->fd < 0) {
582       LOGE("failed to open %s", dev);
583       free(intel);
584       return NULL;
585    }
586
587    intel->screen_number = 0;
588
589    /* XXX query using I915_GETPARAM + PARAM_CHIPSET_ID */
590    intel->generation = INTEL_GEN_3;
591
592    intel->pitch_align = 64;
593    intel->enable_tiling = 1;
594
595    intel->base.driver_name = "i915";
596    intel->base.initialize = intel_initialize;
597    intel->base.destroy = intel_destroy;
598
599    intel->base.get_native_buffer = intel_get_native_buffer;
600    intel->base.get_surface_buffers = intel_get_surface_buffers;
601
602    intel->base.create_window_surface = intel_create_window_surface;
603    intel->base.create_image_surface = intel_create_image_surface;
604    intel->base.destroy_surface = intel_destroy_surface;
605    intel->base.swap_native_buffers = intel_swap_native_buffers;
606
607    return &intel->base;
608 }