OSDN Git Service

add support for debug.drm.mode
[android-x86/external-drm_gralloc.git] / gralloc_drm_intel.c
1 /*
2  * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3  * Copyright (C) 2010-2011 LunarG Inc.
4  *
5  * drm_gem_intel_copy is based on xorg-driver-intel, which has
6  *
7  * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
8  * All Rights Reserved.
9  * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  */
29
30 #define LOG_TAG "GRALLOC-I915"
31
32 #include <cutils/log.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <drm.h>
37 #include <intel_bufmgr.h>
38 #include <i915_drm.h>
39
40 #include "gralloc_drm.h"
41 #include "gralloc_drm_priv.h"
42
43 #define MI_NOOP                     (0)
44 #define MI_BATCH_BUFFER_END         (0x0a << 23)
45 #define MI_FLUSH                    (0x04 << 23)
46 #define MI_FLUSH_DW                 (0x26 << 23)
47 #define MI_WRITE_DIRTY_STATE        (1 << 4) 
48 #define MI_INVALIDATE_MAP_CACHE     (1 << 0)
49 #define XY_SRC_COPY_BLT_CMD         ((2 << 29) | (0x53 << 22) | 6)
50 #define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21)
51 #define XY_SRC_COPY_BLT_WRITE_RGB   (1 << 20)
52 #define XY_SRC_COPY_BLT_SRC_TILED   (1 << 15)
53 #define XY_SRC_COPY_BLT_DST_TILED   (1 << 11)
54
55 struct intel_info {
56         struct gralloc_drm_drv_t base;
57
58         int fd;
59         drm_intel_bufmgr *bufmgr;
60         int gen;
61
62         drm_intel_bo *batch_ibo;
63         uint32_t *batch, *cur;
64         int capacity, size;
65 };
66
67 struct intel_buffer {
68         struct gralloc_drm_bo_t base;
69         drm_intel_bo *ibo;
70         uint32_t tiling;
71 };
72
73 static int
74 batch_next(struct intel_info *info)
75 {
76         info->cur = info->batch;
77
78         if (info->batch_ibo)
79                 drm_intel_bo_unreference(info->batch_ibo);
80
81         info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
82                         "gralloc-batchbuffer", info->size, 4096);
83
84         return (info->batch_ibo) ? 0 : -ENOMEM;
85 }
86
87 static int
88 batch_count(struct intel_info *info)
89 {
90         return info->cur - info->batch;
91 }
92
93 static void
94 batch_dword(struct intel_info *info, uint32_t dword)
95 {
96         *info->cur++ = dword;
97 }
98
99 static int
100 batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
101                 uint32_t read_domains, uint32_t write_domain)
102 {
103         struct intel_buffer *target = (struct intel_buffer *) bo;
104         uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
105         int ret;
106
107         ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
108                         target->ibo, 0, read_domains, write_domain);
109         if (!ret)
110                 batch_dword(info, target->ibo->offset);
111
112         return ret;
113 }
114
115 static int
116 batch_flush(struct intel_info *info)
117 {
118         int size, ret;
119
120         batch_dword(info, MI_BATCH_BUFFER_END);
121         size = batch_count(info);
122         if (size & 1) {
123                 batch_dword(info, MI_NOOP);
124                 size = batch_count(info);
125         }
126
127         size *= sizeof(info->batch[0]);
128         ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
129         if (ret) {
130                 LOGE("failed to subdata batch");
131                 goto fail;
132         }
133         ret = drm_intel_bo_exec(info->batch_ibo, size, NULL, 0, 0);
134         if (ret) {
135                 LOGE("failed to exec batch");
136                 goto fail;
137         }
138
139         return batch_next(info);
140
141 fail:
142         info->cur = info->batch;
143
144         return ret;
145 }
146
147 static int
148 batch_reserve(struct intel_info *info, int count)
149 {
150         int ret = 0;
151
152         if (batch_count(info) + count > info->capacity)
153                 ret = batch_flush(info);
154
155         return ret;
156 }
157
158 static void
159 batch_destroy(struct intel_info *info)
160 {
161         if (info->batch_ibo) {
162                 drm_intel_bo_unreference(info->batch_ibo);
163                 info->batch_ibo = NULL;
164         }
165
166         if (info->batch) {
167                 free(info->batch);
168                 info->batch = NULL;
169         }
170 }
171
172 static int
173 batch_init(struct intel_info *info)
174 {
175         int ret;
176
177         info->capacity = 512;
178         info->size = (info->capacity + 16) * sizeof(info->batch[0]);
179
180         info->batch = malloc(info->size);
181         if (!info->batch)
182                 return -ENOMEM;
183
184         ret = batch_next(info);
185         if (ret) {
186                 free(info->batch);
187                 info->batch = NULL;
188         }
189
190         return ret;
191 }
192
193 static void intel_copy(struct gralloc_drm_drv_t *drv,
194                 struct gralloc_drm_bo_t *dst,
195                 struct gralloc_drm_bo_t *src,
196                 short x1, short y1, short x2, short y2)
197 {
198         struct intel_info *info = (struct intel_info *) drv;
199         struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
200         struct intel_buffer *src_ib = (struct intel_buffer *) src;
201         drm_intel_bo *bo_table[3];
202         uint32_t cmd, br13, dst_pitch, src_pitch;
203
204         if (dst->handle->width != src->handle->width ||
205             dst->handle->height != src->handle->height ||
206             dst->handle->stride != src->handle->stride ||
207             dst->handle->format != src->handle->format) {
208                 LOGE("copy between incompatible buffers");
209                 return;
210         }
211
212         if (x1 < 0)
213                 x1 = 0;
214         if (y1 < 0)
215                 y1 = 0;
216         if (x2 > dst->handle->width)
217                 x2 = dst->handle->width;
218         if (y2 > dst->handle->height)
219                 y2 = dst->handle->height;
220
221         if (x2 <= x1 || y2 <= y1)
222                 return;
223
224         bo_table[0] = info->batch_ibo;
225         bo_table[1] = src_ib->ibo;
226         bo_table[2] = dst_ib->ibo;
227         if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
228                 if (batch_flush(info))
229                         return;
230                 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
231         }
232
233         cmd = XY_SRC_COPY_BLT_CMD;
234         br13 = 0xcc << 16; /* ROP_S/GXcopy */
235         dst_pitch = dst->handle->stride;
236         src_pitch = src->handle->stride;
237
238         switch (gralloc_drm_get_bpp(dst->handle->format)) {
239         case 1:
240                 break;
241         case 2:
242                 br13 |= (1 << 24);
243                 break;
244         case 4:
245                 br13 |= (1 << 24) | (1 << 25);
246                 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
247                 break;
248         default:
249                 LOGE("copy with unsupported format");
250                 return;
251         }
252
253         if (info->gen >= 40) {
254                 if (dst_ib->tiling != I915_TILING_NONE) {
255                         assert(dst_pitch % 512 == 0);
256                         dst_pitch >>= 2;
257                         cmd |= XY_SRC_COPY_BLT_DST_TILED;
258                 }
259                 if (src_ib->tiling != I915_TILING_NONE) {
260                         assert(src_pitch % 512 == 0);
261                         src_pitch >>= 2;
262                         cmd |= XY_SRC_COPY_BLT_SRC_TILED;
263                 }
264         }
265
266         if (batch_reserve(info, 8))
267                 return;
268
269         batch_dword(info, cmd);
270         batch_dword(info, br13 | dst_pitch);
271         batch_dword(info, (y1 << 16) | x1);
272         batch_dword(info, (y2 << 16) | x2);
273         batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
274         batch_dword(info, (y1 << 16) | x1);
275         batch_dword(info, src_pitch);
276         batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
277
278         if (info->gen >= 60) {
279                 batch_reserve(info, 4);
280                 batch_dword(info, MI_FLUSH_DW | 2);
281                 batch_dword(info, 0);
282                 batch_dword(info, 0);
283                 batch_dword(info, 0);
284         }
285         else {
286                 int flags = (info->gen >= 40) ? 0 :
287                         MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
288
289                 batch_reserve(info, 1);
290                 batch_dword(info, MI_FLUSH | flags);
291         }
292
293         batch_flush(info);
294 }
295
296 static drm_intel_bo *alloc_ibo(struct intel_info *info,
297                 const struct gralloc_drm_handle_t *handle,
298                 uint32_t *tiling, unsigned long *stride)
299 {
300         drm_intel_bo *ibo;
301         const char *name;
302         int aligned_width, aligned_height, bpp;
303         unsigned long flags;
304
305         flags = 0;
306         bpp = gralloc_drm_get_bpp(handle->format);
307         if (!bpp) {
308                 LOGE("unrecognized format 0x%x", handle->format);
309                 return NULL;
310         }
311
312         if (handle->usage & GRALLOC_USAGE_HW_FB) {
313                 unsigned long max_stride;
314
315                 max_stride = 32 * 1024;
316                 if (info->gen < 50)
317                         max_stride /= 2;
318                 if (info->gen < 40)
319                         max_stride /= 2;
320
321                 name = "gralloc-fb";
322                 aligned_width = (handle->width + 63) & ~63;
323                 aligned_height = handle->height;
324                 flags = BO_ALLOC_FOR_RENDER;
325
326                 *tiling = I915_TILING_X;
327                 *stride = aligned_width * bpp;
328                 if (*stride > max_stride) {
329                         *tiling = I915_TILING_NONE;
330                         max_stride = 32 * 1024;
331                         if (*stride > max_stride)
332                                 return NULL;
333                 }
334
335                 while (1) {
336                         ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
337                                         aligned_width, aligned_height,
338                                         bpp, tiling, stride, flags);
339                         if (!ibo || *stride > max_stride) {
340                                 if (ibo) {
341                                         drm_intel_bo_unreference(ibo);
342                                         ibo = NULL;
343                                 }
344
345                                 if (*tiling != I915_TILING_NONE) {
346                                         /* retry */
347                                         *tiling = I915_TILING_NONE;
348                                         max_stride = 32 * 1024;
349                                         continue;
350                                 }
351                         }
352                         if (ibo)
353                                 drm_intel_bo_disable_reuse(ibo);
354                         break;
355                 }
356         }
357         else {
358                 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
359                                      GRALLOC_USAGE_SW_WRITE_OFTEN))
360                         *tiling = I915_TILING_NONE;
361                 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
362                          ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
363                           handle->width >= 64))
364                         *tiling = I915_TILING_X;
365                 else
366                         *tiling = I915_TILING_NONE;
367
368                 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
369                         name = "gralloc-texture";
370                         /* see 2D texture layout of DRI drivers */
371                         aligned_width = (handle->width + 3) & ~3;
372                         aligned_height = (handle->height + 1) & ~1;
373                 }
374                 else {
375                         name = "gralloc-buffer";
376                         aligned_width = handle->width;
377                         aligned_height = handle->height;
378                 }
379
380                 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
381                         flags = BO_ALLOC_FOR_RENDER;
382
383                 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
384                                 aligned_width, aligned_height,
385                                 bpp, tiling, stride, flags);
386         }
387
388         return ibo;
389 }
390
391 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
392                 struct gralloc_drm_handle_t *handle)
393 {
394         struct intel_info *info = (struct intel_info *) drv;
395         struct intel_buffer *ib;
396
397         ib = calloc(1, sizeof(*ib));
398         if (!ib)
399                 return NULL;
400
401         if (handle->name) {
402                 uint32_t dummy;
403
404                 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
405                                 "gralloc-r", handle->name);
406                 if (!ib->ibo) {
407                         LOGE("failed to create ibo from name %u",
408                                         handle->name);
409                         free(ib);
410                         return NULL;
411                 }
412
413                 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
414                         LOGE("failed to get ibo tiling");
415                         drm_intel_bo_unreference(ib->ibo);
416                         free(ib);
417                         return NULL;
418                 }
419         }
420         else {
421                 unsigned long stride;
422
423                 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
424                 if (!ib->ibo) {
425                         LOGE("failed to allocate ibo %dx%d (format %d)",
426                                         handle->width,
427                                         handle->height,
428                                         handle->format);
429                         free(ib);
430                         return NULL;
431                 }
432
433                 handle->stride = stride;
434
435                 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
436                         LOGE("failed to flink ibo");
437                         drm_intel_bo_unreference(ib->ibo);
438                         free(ib);
439                         return NULL;
440                 }
441         }
442
443         if (handle->usage & GRALLOC_USAGE_HW_FB)
444                 ib->base.fb_handle = ib->ibo->handle;
445
446         ib->base.handle = handle;
447
448         return &ib->base;
449 }
450
451 static void intel_free(struct gralloc_drm_drv_t *drv,
452                 struct gralloc_drm_bo_t *bo)
453 {
454         struct intel_buffer *ib = (struct intel_buffer *) bo;
455
456         drm_intel_bo_unreference(ib->ibo);
457         free(ib);
458 }
459
460 static int intel_map(struct gralloc_drm_drv_t *drv,
461                 struct gralloc_drm_bo_t *bo,
462                 int x, int y, int w, int h,
463                 int enable_write, void **addr)
464 {
465         struct intel_buffer *ib = (struct intel_buffer *) bo;
466         int err;
467
468         if (ib->tiling != I915_TILING_NONE ||
469             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
470                 err = drm_intel_gem_bo_map_gtt(ib->ibo);
471         else
472                 err = drm_intel_bo_map(ib->ibo, enable_write);
473         if (!err)
474                 *addr = ib->ibo->virtual;
475
476         return err;
477 }
478
479 static void intel_unmap(struct gralloc_drm_drv_t *drv,
480                 struct gralloc_drm_bo_t *bo)
481 {
482         struct intel_buffer *ib = (struct intel_buffer *) bo;
483
484         if (ib->tiling != I915_TILING_NONE ||
485             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
486                 drm_intel_gem_bo_unmap_gtt(ib->ibo);
487         else
488                 drm_intel_bo_unmap(ib->ibo);
489 }
490
491 #include "dri/intel_chipset.h" /* for IS_965() */
492 static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
493                 struct gralloc_drm_t *drm)
494 {
495         struct intel_info *info = (struct intel_info *) drv;
496         struct drm_i915_getparam gp;
497         int pageflipping, id;
498
499         switch (drm->fb_format) {
500         case HAL_PIXEL_FORMAT_BGRA_8888:
501         case HAL_PIXEL_FORMAT_RGB_565:
502                 break;
503         default:
504                 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
505                 break;
506         }
507
508         drm->mode_dirty_fb = 0;
509         /* why? */
510         drm->mode_sync_flip = 1;
511
512         memset(&gp, 0, sizeof(gp));
513         gp.param = I915_PARAM_HAS_PAGEFLIPPING;
514         gp.value = &pageflipping;
515         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
516                 pageflipping = 0;
517
518         memset(&gp, 0, sizeof(gp));
519         gp.param = I915_PARAM_CHIPSET_ID;
520         gp.value = &id;
521         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
522                 id = 0;
523
524         if (IS_965(id)) {
525                 if (IS_GEN6(id))
526                         info->gen = 60;
527                 else if (IS_GEN5(id))
528                         info->gen = 50;
529                 else
530                         info->gen = 40;
531         }
532         else {
533                 info->gen = 30;
534         }
535
536         if (pageflipping && info->gen > 30)
537                 drm->swap_mode = DRM_SWAP_FLIP;
538         else if (info->batch && info->gen == 30)
539                 drm->swap_mode = DRM_SWAP_COPY;
540         else
541                 drm->swap_mode = DRM_SWAP_SETCRTC;
542
543         if (drm->resources) {
544                 int pipe;
545
546                 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
547                                 drm->crtc_id);
548                 drm->swap_interval = (pipe >= 0) ? 1 : 0;
549                 drm->vblank_secondary = (pipe > 0);
550         }
551         else {
552                 drm->swap_interval = 0;
553         }
554 }
555
556 static void intel_destroy(struct gralloc_drm_drv_t *drv)
557 {
558         struct intel_info *info = (struct intel_info *) drv;
559
560         batch_destroy(info);
561         drm_intel_bufmgr_destroy(info->bufmgr);
562         free(info);
563 }
564
565 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
566 {
567         struct intel_info *info;
568
569         info = calloc(1, sizeof(*info));
570         if (!info) {
571                 LOGE("failed to allocate driver info");
572                 return NULL;
573         }
574
575         info->fd = fd;
576         info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
577         if (!info->bufmgr) {
578                 LOGE("failed to create buffer manager");
579                 free(info);
580                 return NULL;
581         }
582
583         batch_init(info);
584
585         info->base.destroy = intel_destroy;
586         info->base.init_kms_features = intel_init_kms_features;
587         info->base.alloc = intel_alloc;
588         info->base.free = intel_free;
589         info->base.map = intel_map;
590         info->base.unmap = intel_unmap;
591         info->base.copy = intel_copy;
592
593         return &info->base;
594 }