OSDN Git Service

egl_android: Initialize __DRIbuffer properly.
[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_STRIDE_ALIGNMENT 64
46
47 enum {
48    INTEL_SURFACE_TYPE_WINDOW,
49 };
50
51 struct droid_backend_intel {
52    struct droid_backend base;
53    int fd;
54    int screen_number;
55 };
56
57 struct droid_surface_intel {
58    int type;
59    union {
60       NativeWindowType win;
61    } native;
62    __DRIbuffer native_buffer;
63    unsigned int native_width, native_height;
64    int native_changed;
65
66    unsigned int attachments[20];
67    __DRIbuffer buffers[10];
68    uint32_t handles[10];
69    int num_buffers;
70    int depth_idx;
71
72    _EGLSurface *surf;
73 };
74
75 static INLINE struct droid_backend_intel *
76 lookup_backend(struct droid_backend *backend)
77 {
78    return (struct droid_backend_intel *) backend;
79 }
80
81 static INLINE struct droid_surface_intel *
82 lookup_surface(struct droid_surface *surface)
83 {
84    return (struct droid_surface_intel *) surface;
85 }
86
87 static __DRIbuffer *
88 intel_get_native_buffer(struct droid_backend *backend,
89                         struct droid_surface *surf,
90                         int *width, int *height)
91 {
92    struct droid_surface_intel *isurf = lookup_surface(surf);
93
94    if (!isurf->native_buffer.name)
95       return NULL;
96
97    if (width)
98       *width = isurf->native_width;
99    if (height)
100       *height = isurf->native_height;
101
102    return &isurf->native_buffer;
103 }
104
105 static inline uint32_t
106 align_to(uint32_t value, uint32_t align)
107 {
108    return (value + align - 1) & ~(align - 1);
109 }
110
111 static int
112 create_buffer(int fd, GLint width, GLint height, GLint cpp, __DRIbuffer *buffer)
113 {
114    struct drm_i915_gem_create create;
115    struct drm_gem_flink flink;
116    uint32_t size;
117
118    buffer->pitch = align_to(width * cpp, INTEL_STRIDE_ALIGNMENT);
119    size = buffer->pitch * height;
120    create.size = size;
121    if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create)) {
122       LOGE("failed to create buffer");
123       return 0;
124    }
125
126    flink.handle = create.handle;
127    if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
128       LOGE("failed to flink buffer");
129       return 0;
130    }
131
132    buffer->name = flink.name;
133    buffer->cpp = cpp;
134    buffer->flags = 0;
135
136    return create.handle;
137 }
138
139 static void
140 delete_buffers(struct droid_backend *backend, struct droid_surface *surf)
141 {
142    struct droid_backend_intel *intel = lookup_backend(backend);
143    struct droid_surface_intel *isurf = lookup_surface(surf);
144    int i;
145
146    for (i = 0; i < isurf->num_buffers; i++) {
147       if (isurf->handles[i]) {
148          struct drm_gem_close close;
149
150          close.handle = isurf->handles[i];
151          if (ioctl(intel->fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
152             LOGE("failed to close bo %d", close.handle);
153          isurf->handles[i] = 0;
154       }
155    }
156
157    isurf->num_buffers = 0;
158 }
159
160 static __DRIbuffer *
161 intel_get_surface_buffers(struct droid_backend *backend,
162                           struct droid_surface *surf,
163                           int *width, int *height,
164                           unsigned int *attachments, int count,
165                           int *out_count, int has_format)
166 {
167    struct droid_backend_intel *intel = lookup_backend(backend);
168    struct droid_surface_intel *isurf = lookup_surface(surf);
169    unsigned int att_size;
170    __DRIbuffer buffers[10];
171    uint32_t handles[10];
172    int num = 0;
173
174    if (count > 10) {
175       LOGW("too many buffers requested");
176       count = 10;
177    }
178
179    att_size = sizeof(attachments[0]) * count * ((has_format) ? 2 : 1);
180
181    if (isurf->native_changed) {
182       delete_buffers(backend, surf);
183       isurf->native_changed = 0;
184    }
185
186    /* same buffers requested */
187    if (isurf->num_buffers == count &&
188        memcmp(isurf->attachments, attachments, att_size) == 0) {
189       num = isurf->num_buffers;
190       goto end;
191    }
192    memcpy(isurf->attachments, attachments, att_size);
193
194    while (count-- > 0) {
195       unsigned int att = *attachments++;
196       unsigned int format = (has_format) ? *attachments++ : 0;
197       unsigned int cpp = (format) ? format / 8 : isurf->native_buffer.cpp;
198       __DRIbuffer *buf = NULL;
199       int reuse;
200
201       /* re-use buffer */
202       for (reuse = 0; reuse < isurf->num_buffers; reuse++) {
203          if (isurf->buffers[reuse].attachment == att) {
204             if (isurf->buffers[reuse].cpp == cpp &&
205                 isurf->handles[reuse])
206                buf = &isurf->buffers[reuse];
207             break;
208          }
209       }
210
211       if (0)
212          LOGD("%s buffer %d: att %d cpp %d",
213                (buf) ? "reuse" : "create", num, att, cpp);
214
215       if (buf) {
216          buffers[num] = isurf->buffers[reuse];
217          handles[num] = isurf->handles[reuse];
218          isurf->handles[reuse] = 0;
219       }
220       else {
221          buffers[num].attachment = att;
222          handles[num] = create_buffer(intel->fd,
223                                           isurf->native_width,
224                                           isurf->native_height,
225                                           cpp,
226                                           &buffers[num]);
227       }
228       num++;
229    }
230
231    /* delete buffers that are not re-used */
232    delete_buffers(backend, surf);
233
234    memcpy(isurf->buffers, buffers, sizeof(buffers[0]) * num);
235    memcpy(isurf->handles, handles, sizeof(handles[0]) * num);
236    isurf->num_buffers = num;
237
238 end:
239    *out_count = num;
240    *width = isurf->native_width;
241    *height = isurf->native_height;
242
243    return isurf->buffers;
244 }
245
246 static void
247 update_native_buffer(struct droid_surface *surf)
248 {
249    struct droid_surface_intel *isurf = lookup_surface(surf);
250    unsigned int name, cpp, pitch, width, height;
251
252    switch (isurf->type) {
253    case INTEL_SURFACE_TYPE_WINDOW:
254       /* oem[0] always point to the buffer that a client is drawing to */
255       name = isurf->native.win->oem[0];
256       cpp = ui_bytes_per_pixel(isurf->native.win->format);
257       pitch = isurf->native.win->stride * cpp;
258       width = isurf->native.win->width;
259       height = isurf->native.win->height;
260       break;
261    default:
262       name = cpp = pitch = width = height = 0;
263       break;
264    }
265
266    isurf->native_buffer.attachment = __DRI_BUFFER_FRONT_LEFT;
267    isurf->native_buffer.name = name;
268    isurf->native_buffer.cpp = cpp;
269    isurf->native_buffer.pitch = pitch;
270    isurf->native_buffer.flags = 0;
271
272    isurf->native_width = width;
273    isurf->native_height = height;
274
275    isurf->native_changed = 1;
276 }
277
278 static struct droid_surface *
279 intel_create_window_surface(struct droid_backend *backend,
280                             _EGLSurface *surf,
281                             NativeWindowType win)
282 {
283    struct droid_surface_intel *isurf;
284
285    if (!win) {
286       LOGE("invalid native window");
287       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
288       return NULL;
289    }
290
291    /* TODO lift this limitation */
292    if (!win->oem[0]) {
293       LOGE("TODO support for non-gem based window");
294       _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
295       return NULL;
296    }
297
298    isurf = calloc(1, sizeof(*isurf));
299    if (!isurf) {
300       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
301       return NULL;
302    }
303
304    isurf->type = INTEL_SURFACE_TYPE_WINDOW;
305    isurf->native.win = win;
306
307    surf->Width = win->width;
308    surf->Height = win->height;
309    /* always back buffer */
310    surf->RenderBuffer = EGL_BACK_BUFFER;
311
312    isurf->surf = surf;
313
314    update_native_buffer((struct droid_surface *) isurf);
315
316    return (struct droid_surface *) isurf;
317 }
318
319 static void
320 intel_destroy_surface(struct droid_backend *backend, struct droid_surface *surf)
321 {
322    struct droid_surface_intel *isurf = lookup_surface(surf);
323    delete_buffers(backend, surf);
324    free(isurf);
325 }
326
327 static void
328 intel_swap_native_buffers(struct droid_backend *backend,
329                           struct droid_surface *surf)
330 {
331    struct droid_surface_intel *isurf = lookup_surface(surf);
332
333    if (isurf->type == INTEL_SURFACE_TYPE_WINDOW) {
334       uint32_t flags;
335
336       flags = isurf->native.win->swapBuffers(isurf->native.win);
337       if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
338          update_native_buffer(surf);
339       } else {
340          /* oem[0] is changed after buffer swap */
341          isurf->native_buffer.name = isurf->native.win->oem[0];
342       }
343    }
344 }
345
346 static int
347 intel_initialize(struct droid_backend *backend, int *fd, int *screen_number)
348 {
349    struct droid_backend_intel *intel = lookup_backend(backend);
350    drm_auth_t auth;
351    int err;
352
353    err = ioctl(intel->fd, DRM_IOCTL_GET_MAGIC, &auth);
354    if (!err)
355       err = ui_auth_gpu(auth.magic);
356
357    if (err) {
358       LOGE("failed to authenticate");
359       return 0;
360    }
361
362    if (fd)
363       *fd = intel->fd;
364    if (screen_number)
365       *screen_number = intel->screen_number;
366
367    return 1;
368 }
369
370 static void
371 intel_destroy(struct droid_backend *backend)
372 {
373    struct droid_backend_intel *intel = lookup_backend(backend);
374    close(intel->fd);
375    free(intel);
376 }
377
378 struct droid_backend *
379 droid_backend_create_intel(const char *dev)
380 {
381    struct droid_backend_intel *intel;
382
383    intel = calloc(1, sizeof(*intel));
384    if (!intel)
385       return NULL;
386
387    intel->fd = open(dev, O_RDWR);
388    if (intel->fd < 0) {
389       LOGE("failed to open %s", dev);
390       free(intel);
391       return NULL;
392    }
393
394    intel->screen_number = 0;
395    intel->base.driver_name = "i915";
396    intel->base.initialize = intel_initialize;
397    intel->base.destroy = intel_destroy;
398
399    intel->base.get_native_buffer = intel_get_native_buffer;
400    intel->base.get_surface_buffers = intel_get_surface_buffers;
401
402    intel->base.create_window_surface = intel_create_window_surface;
403    intel->base.destroy_surface = intel_destroy_surface;
404    intel->base.swap_native_buffers = intel_swap_native_buffers;
405
406    return &intel->base;
407 }