2 * Copyright (C) 2009 Chia-I Wu <olvaffe@gmail.com>
4 * This is based on the work of eagle, by
5 * Copyright © 2008, 2009 Kristian Høgsberg
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.
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
26 #define LOG_TAG "DROID-INTEL"
27 #include <utils/Log.h>
33 #include <sys/ioctl.h>
38 #include <GL/gl.h> /* dri_interface.h uses some GL integer types... */
39 #include <GL/internal/dri_interface.h>
45 #define INTEL_STRIDE_ALIGNMENT 64
48 INTEL_SURFACE_TYPE_WINDOW,
51 struct droid_backend_intel {
52 struct droid_backend base;
57 struct droid_surface_intel {
62 __DRIbuffer native_buffer;
63 unsigned int native_width, native_height;
66 unsigned int attachments[20];
67 __DRIbuffer buffers[10];
75 static INLINE struct droid_backend_intel *
76 lookup_backend(struct droid_backend *backend)
78 return (struct droid_backend_intel *) backend;
81 static INLINE struct droid_surface_intel *
82 lookup_surface(struct droid_surface *surface)
84 return (struct droid_surface_intel *) surface;
88 intel_get_native_buffer(struct droid_backend *backend,
89 struct droid_surface *surf,
90 int *width, int *height)
92 struct droid_surface_intel *isurf = lookup_surface(surf);
94 if (!isurf->native_buffer.name)
98 *width = isurf->native_width;
100 *height = isurf->native_height;
102 return &isurf->native_buffer;
105 static inline uint32_t
106 align_to(uint32_t value, uint32_t align)
108 return (value + align - 1) & ~(align - 1);
112 create_buffer(int fd, GLint width, GLint height, GLint cpp, __DRIbuffer *buffer)
114 struct drm_i915_gem_create create;
115 struct drm_gem_flink flink;
118 buffer->pitch = align_to(width * cpp, INTEL_STRIDE_ALIGNMENT);
119 size = buffer->pitch * height;
121 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create)) {
122 LOGE("failed to create buffer");
126 flink.handle = create.handle;
127 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
128 LOGE("failed to flink buffer");
132 buffer->name = flink.name;
136 return create.handle;
140 delete_buffers(struct droid_backend *backend, struct droid_surface *surf)
142 struct droid_backend_intel *intel = lookup_backend(backend);
143 struct droid_surface_intel *isurf = lookup_surface(surf);
146 for (i = 0; i < isurf->num_buffers; i++) {
147 if (isurf->handles[i]) {
148 struct drm_gem_close close;
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;
157 isurf->num_buffers = 0;
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)
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];
175 LOGW("too many buffers requested");
179 att_size = sizeof(attachments[0]) * count * ((has_format) ? 2 : 1);
181 if (isurf->native_changed) {
182 delete_buffers(backend, surf);
183 isurf->native_changed = 0;
186 /* same buffers requested */
187 if (isurf->num_buffers == count &&
188 memcmp(isurf->attachments, attachments, att_size) == 0) {
189 num = isurf->num_buffers;
192 memcpy(isurf->attachments, attachments, att_size);
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;
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];
212 LOGD("%s buffer %d: att %d cpp %d",
213 (buf) ? "reuse" : "create", num, att, cpp);
216 buffers[num] = isurf->buffers[reuse];
217 handles[num] = isurf->handles[reuse];
218 isurf->handles[reuse] = 0;
221 buffers[num].attachment = att;
222 handles[num] = create_buffer(intel->fd,
224 isurf->native_height,
231 /* delete buffers that are not re-used */
232 delete_buffers(backend, surf);
234 memcpy(isurf->buffers, buffers, sizeof(buffers[0]) * num);
235 memcpy(isurf->handles, handles, sizeof(handles[0]) * num);
236 isurf->num_buffers = num;
240 *width = isurf->native_width;
241 *height = isurf->native_height;
243 return isurf->buffers;
247 update_native_buffer(struct droid_surface *surf)
249 struct droid_surface_intel *isurf = lookup_surface(surf);
250 unsigned int name, cpp, pitch, width, height;
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;
262 name = cpp = pitch = width = height = 0;
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;
272 isurf->native_width = width;
273 isurf->native_height = height;
275 isurf->native_changed = 1;
278 static struct droid_surface *
279 intel_create_window_surface(struct droid_backend *backend,
281 NativeWindowType win)
283 struct droid_surface_intel *isurf;
286 LOGE("invalid native window");
287 _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
291 /* TODO lift this limitation */
293 LOGE("TODO support for non-gem based window");
294 _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
298 isurf = calloc(1, sizeof(*isurf));
300 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
304 isurf->type = INTEL_SURFACE_TYPE_WINDOW;
305 isurf->native.win = win;
307 surf->Width = win->width;
308 surf->Height = win->height;
309 /* always back buffer */
310 surf->RenderBuffer = EGL_BACK_BUFFER;
314 update_native_buffer((struct droid_surface *) isurf);
316 return (struct droid_surface *) isurf;
320 intel_destroy_surface(struct droid_backend *backend, struct droid_surface *surf)
322 struct droid_surface_intel *isurf = lookup_surface(surf);
323 delete_buffers(backend, surf);
328 intel_swap_native_buffers(struct droid_backend *backend,
329 struct droid_surface *surf)
331 struct droid_surface_intel *isurf = lookup_surface(surf);
333 if (isurf->type == INTEL_SURFACE_TYPE_WINDOW) {
336 flags = isurf->native.win->swapBuffers(isurf->native.win);
337 if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
338 update_native_buffer(surf);
340 /* oem[0] is changed after buffer swap */
341 isurf->native_buffer.name = isurf->native.win->oem[0];
347 intel_initialize(struct droid_backend *backend, int *fd, int *screen_number)
349 struct droid_backend_intel *intel = lookup_backend(backend);
353 err = ioctl(intel->fd, DRM_IOCTL_GET_MAGIC, &auth);
355 err = ui_auth_gpu(auth.magic);
358 LOGE("failed to authenticate");
365 *screen_number = intel->screen_number;
371 intel_destroy(struct droid_backend *backend)
373 struct droid_backend_intel *intel = lookup_backend(backend);
378 struct droid_backend *
379 droid_backend_create_intel(const char *dev)
381 struct droid_backend_intel *intel;
383 intel = calloc(1, sizeof(*intel));
387 intel->fd = open(dev, O_RDWR);
389 LOGE("failed to open %s", dev);
394 intel->screen_number = 0;
395 intel->base.driver_name = "i915";
396 intel->base.initialize = intel_initialize;
397 intel->base.destroy = intel_destroy;
399 intel->base.get_native_buffer = intel_get_native_buffer;
400 intel->base.get_surface_buffers = intel_get_surface_buffers;
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;