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_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))
50 #define INTEL_HAS_128_BYTE_Y_TILING(x) \
51 (((x) & (INTEL_GEN_3 | INTEL_GEN_4 | INTEL_GEN_MINOR_MASK)) > INTEL_GEN_3)
54 INTEL_SURFACE_TYPE_WINDOW,
55 INTEL_SURFACE_TYPE_IMAGE,
58 /* Look at xf86-video-intel/src/common.h for the full horror of device
68 INTEL_GEN_MAJOR_MASK = 0xf0,
69 INTEL_GEN_MINOR_MASK = 0x0f,
72 struct droid_backend_intel {
73 struct droid_backend base;
82 struct droid_surface_intel {
88 __DRIbuffer native_buffer;
89 unsigned int native_width, native_height;
92 unsigned int attachments[20];
93 __DRIbuffer buffers[10];
101 static INLINE struct droid_backend_intel *
102 lookup_backend(struct droid_backend *backend)
104 return (struct droid_backend_intel *) backend;
107 static INLINE struct droid_surface_intel *
108 lookup_surface(struct droid_surface *surface)
110 return (struct droid_surface_intel *) surface;
114 intel_get_native_buffer(struct droid_backend *backend,
115 struct droid_surface *surf,
116 int *width, int *height)
118 struct droid_surface_intel *isurf = lookup_surface(surf);
120 /* non-window surface is single-buffered */
121 if (isurf->type != INTEL_SURFACE_TYPE_WINDOW)
124 if (!isurf->native_buffer.name)
128 *width = isurf->native_width;
130 *height = isurf->native_height;
132 return &isurf->native_buffer;
135 static INLINE uint32_t
136 align_to(uint32_t value, uint32_t align)
138 return (value + align - 1) & ~(align - 1);
142 fence_pitch(struct droid_backend *backend, int pitch, int tiling)
144 struct droid_backend_intel *intel = lookup_backend(backend);
145 int pitch_align, tile_width;
148 case I915_TILING_NONE:
150 pitch_align = intel->pitch_align;
151 tile_width = 1; /* not used */
160 (INTEL_HAS_128_BYTE_Y_TILING(intel->generation)) ? 128 : 512;
164 pitch = align_to(pitch, pitch_align);
165 if (tiling == I915_TILING_NONE)
168 /* 965+ just needs multiples of tile width */
169 if (INTEL_IS_I965(intel->generation)) {
170 pitch = align_to(pitch, tile_width);
173 /* Pre-965 needs power of two tile widths */
174 while (tile_width < pitch)
182 static INLINE uint32_t
183 fence_size(struct droid_backend *backend, int height, int pitch, int tiling)
185 struct droid_backend_intel *intel = lookup_backend(backend);
190 case I915_TILING_NONE:
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
206 height = align_to(height, height_align);
207 size = pitch * height;
208 if (tiling == I915_TILING_NONE)
211 /* The 965 can have fences at any page boundary. */
212 if (INTEL_IS_I965(intel->generation)) {
213 size = align_to(size, 4096);
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 */
222 fence = 1 << 19; /* 512 KiB */
234 create_buffer(struct droid_backend *backend, __DRIbuffer *buffer,
235 int width, int height, int cpp, int tiling)
237 struct droid_backend_intel *intel = lookup_backend(backend);
238 struct drm_i915_gem_create create;
239 struct drm_gem_flink flink;
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");
248 if (tiling != I915_TILING_NONE) {
249 struct drm_i915_gem_set_tiling set_tiling;
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;
256 if (ioctl(intel->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling))
257 LOGW("failed to enable tiling");
260 flink.handle = create.handle;
261 if (ioctl(intel->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
262 LOGE("failed to flink buffer");
266 buffer->name = flink.name;
270 return create.handle;
274 delete_buffers(struct droid_backend *backend, struct droid_surface *surf)
276 struct droid_backend_intel *intel = lookup_backend(backend);
277 struct droid_surface_intel *isurf = lookup_surface(surf);
280 for (i = 0; i < isurf->num_buffers; i++) {
281 if (isurf->handles[i]) {
282 struct drm_gem_close close;
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;
291 isurf->num_buffers = 0;
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)
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];
309 LOGW("too many buffers requested");
313 att_size = sizeof(attachments[0]) * count * ((has_format) ? 2 : 1);
315 if (isurf->native_changed) {
316 delete_buffers(backend, surf);
317 isurf->native_changed = 0;
320 /* same buffers requested */
321 if (isurf->num_buffers == count &&
322 memcmp(isurf->attachments, attachments, att_size) == 0) {
323 num = isurf->num_buffers;
326 memcpy(isurf->attachments, attachments, att_size);
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;
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];
346 LOGD("%s buffer %d: att %d cpp %d",
347 (buf) ? "reuse" : "create", num, att, cpp);
350 buffers[num] = isurf->buffers[reuse];
351 handles[num] = isurf->handles[reuse];
352 isurf->handles[reuse] = 0;
356 (intel->enable_tiling) ? I915_TILING_X : I915_TILING_NONE;
358 buffers[num].attachment = att;
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;
367 buffers[num].attachment = att;
368 handles[num] = create_buffer(backend, &buffers[num],
370 isurf->native_height,
378 /* delete old buffers that are not re-used */
379 delete_buffers(backend, surf);
381 memcpy(isurf->buffers, buffers, sizeof(buffers[0]) * num);
382 memcpy(isurf->handles, handles, sizeof(handles[0]) * num);
383 isurf->num_buffers = num;
387 *width = isurf->native_width;
388 *height = isurf->native_height;
390 return isurf->buffers;
394 update_native_buffer(struct droid_surface *surf)
396 struct droid_surface_intel *isurf = lookup_surface(surf);
397 __DRIbuffer *buf = &isurf->native_buffer;
398 unsigned int name, cpp, pitch, width, height;
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;
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;
417 name = cpp = pitch = width = height = 0;
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;
429 isurf->native_width = width;
430 isurf->native_height = height;
432 isurf->native_changed = 1;
436 static struct droid_surface *
437 intel_create_window_surface(struct droid_backend *backend,
439 NativeWindowType win)
441 struct droid_surface_intel *isurf;
444 LOGE("invalid native window");
445 _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
449 /* TODO lift this limitation */
451 LOGE("TODO support for non-gem based window");
452 _eglError(EGL_BAD_NATIVE_WINDOW, "eglCreateWindowSurface");
456 isurf = calloc(1, sizeof(*isurf));
458 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
462 isurf->type = INTEL_SURFACE_TYPE_WINDOW;
463 isurf->native.win = win;
465 surf->Width = win->width;
466 surf->Height = win->height;
467 /* always back buffer */
468 surf->RenderBuffer = EGL_BACK_BUFFER;
472 update_native_buffer((struct droid_surface *) isurf);
474 return (struct droid_surface *) isurf;
477 static struct droid_surface *
478 intel_create_image_surface(struct droid_backend *backend,
479 NativePixmapType pix)
481 struct droid_surface_intel *isurf;
485 LOGE("invalid native pixmap");
486 _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCreateImage");
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");
497 isurf = calloc(1, sizeof(*isurf));
499 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
503 isurf->type = INTEL_SURFACE_TYPE_IMAGE;
504 isurf->native.pix = pix;
506 update_native_buffer((struct droid_surface *) isurf);
508 return (struct droid_surface *) isurf;
512 intel_destroy_surface(struct droid_backend *backend, struct droid_surface *surf)
514 struct droid_surface_intel *isurf = lookup_surface(surf);
515 delete_buffers(backend, surf);
520 intel_swap_native_buffers(struct droid_backend *backend,
521 struct droid_surface *surf)
523 struct droid_surface_intel *isurf = lookup_surface(surf);
525 if (isurf->type == INTEL_SURFACE_TYPE_WINDOW) {
528 flags = isurf->native.win->swapBuffers(isurf->native.win);
529 if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
530 update_native_buffer(surf);
532 /* oem[0] is changed after buffer swap */
533 isurf->native_buffer.name = isurf->native.win->oem[0];
539 intel_match_pixmap(struct droid_backend *backend, _EGLConfig *conf,
540 NativePixmapType pix)
543 val = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE);
544 /* match the visual type */
545 return (pix->format == val);
549 intel_initialize(struct droid_backend *backend, int *fd, int *screen_number)
551 struct droid_backend_intel *intel = lookup_backend(backend);
555 err = ioctl(intel->fd, DRM_IOCTL_GET_MAGIC, &auth);
557 err = ui_auth_gpu(auth.magic);
560 LOGE("failed to authenticate");
567 *screen_number = intel->screen_number;
574 intel_process_config(struct droid_backend *backend, _EGLConfig *conf)
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);
587 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, format);
588 SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE,
594 SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT);
601 intel_destroy(struct droid_backend *backend)
603 struct droid_backend_intel *intel = lookup_backend(backend);
608 struct droid_backend *
609 droid_backend_create_intel(const char *dev)
611 struct droid_backend_intel *intel;
613 intel = calloc(1, sizeof(*intel));
617 intel->fd = open(dev, O_RDWR);
619 LOGE("failed to open %s", dev);
624 intel->screen_number = 0;
626 /* XXX query using I915_GETPARAM + PARAM_CHIPSET_ID */
627 intel->generation = INTEL_GEN_3;
629 intel->pitch_align = 64;
630 intel->enable_tiling = 1;
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;
637 intel->base.get_native_buffer = intel_get_native_buffer;
638 intel->base.get_surface_buffers = intel_get_surface_buffers;
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;
645 intel->base.match_pixmap = intel_match_pixmap;