OSDN Git Service

gralloc_drm_intel: fix i915 issues: failed to exec batch
[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         int exec_blt;
66 };
67
68 struct intel_buffer {
69         struct gralloc_drm_bo_t base;
70         drm_intel_bo *ibo;
71         uint32_t tiling;
72 };
73
74 static int
75 batch_next(struct intel_info *info)
76 {
77         info->cur = info->batch;
78
79         if (info->batch_ibo)
80                 drm_intel_bo_unreference(info->batch_ibo);
81
82         info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
83                         "gralloc-batchbuffer", info->size, 4096);
84
85         return (info->batch_ibo) ? 0 : -ENOMEM;
86 }
87
88 static int
89 batch_count(struct intel_info *info)
90 {
91         return info->cur - info->batch;
92 }
93
94 static void
95 batch_dword(struct intel_info *info, uint32_t dword)
96 {
97         *info->cur++ = dword;
98 }
99
100 static int
101 batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
102                 uint32_t read_domains, uint32_t write_domain)
103 {
104         struct intel_buffer *target = (struct intel_buffer *) bo;
105         uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
106         int ret;
107
108         ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
109                         target->ibo, 0, read_domains, write_domain);
110         if (!ret)
111                 batch_dword(info, target->ibo->offset);
112
113         return ret;
114 }
115
116 static int
117 batch_flush(struct intel_info *info)
118 {
119         int size, ret;
120
121         batch_dword(info, MI_BATCH_BUFFER_END);
122         size = batch_count(info);
123         if (size & 1) {
124                 batch_dword(info, MI_NOOP);
125                 size = batch_count(info);
126         }
127
128         size *= sizeof(info->batch[0]);
129         ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
130         if (ret) {
131                 ALOGE("failed to subdata batch");
132                 goto fail;
133         }
134         ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
135                 NULL, 0, 0, info->exec_blt);
136         if (ret) {
137                 ALOGE("failed to exec batch");
138                 goto fail;
139         }
140
141         return batch_next(info);
142
143 fail:
144         info->cur = info->batch;
145
146         return ret;
147 }
148
149 static int
150 batch_reserve(struct intel_info *info, int count)
151 {
152         int ret = 0;
153
154         if (batch_count(info) + count > info->capacity)
155                 ret = batch_flush(info);
156
157         return ret;
158 }
159
160 static void
161 batch_destroy(struct intel_info *info)
162 {
163         if (info->batch_ibo) {
164                 drm_intel_bo_unreference(info->batch_ibo);
165                 info->batch_ibo = NULL;
166         }
167
168         if (info->batch) {
169                 free(info->batch);
170                 info->batch = NULL;
171         }
172 }
173
174 static int
175 batch_init(struct intel_info *info)
176 {
177         int ret;
178
179         info->capacity = 512;
180         info->size = (info->capacity + 16) * sizeof(info->batch[0]);
181
182         info->batch = malloc(info->size);
183         if (!info->batch)
184                 return -ENOMEM;
185
186         ret = batch_next(info);
187         if (ret) {
188                 free(info->batch);
189                 info->batch = NULL;
190         }
191
192         return ret;
193 }
194
195 static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
196                 struct gralloc_drm_bo_t *bo,
197                 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
198 {
199         /*
200          * TODO - should take account hw specific padding, alignment
201          * for camera, video decoder etc.
202          */
203
204         struct intel_buffer *ib = (struct intel_buffer *) bo;
205
206         memset(pitches, 0, 4 * sizeof(uint32_t));
207         memset(offsets, 0, 4 * sizeof(uint32_t));
208         memset(handles, 0, 4 * sizeof(uint32_t));
209
210         pitches[0] = ib->base.handle->stride;
211         handles[0] = ib->base.fb_handle;
212
213         switch(ib->base.handle->format) {
214                 case HAL_PIXEL_FORMAT_YV12:
215
216                         // U and V stride are half of Y plane
217                         pitches[2] = pitches[0]/2;
218                         pitches[1] = pitches[0]/2;
219
220                         // like I420 but U and V are in reverse order
221                         offsets[2] = offsets[0] +
222                                 pitches[0] * ib->base.handle->height;
223                         offsets[1] = offsets[2] +
224                                 pitches[2] * ib->base.handle->height/2;
225
226                         handles[1] = handles[2] = handles[0];
227                         break;
228
229                 case HAL_PIXEL_FORMAT_DRM_NV12:
230
231                         // U and V are interleaved in 2nd plane
232                         pitches[1] = pitches[0];
233                         offsets[1] = offsets[0] +
234                                 pitches[0] * ib->base.handle->height;
235
236                         handles[1] = handles[0];
237                         break;
238         }
239 }
240
241
242 static void intel_blit(struct gralloc_drm_drv_t *drv,
243                 struct gralloc_drm_bo_t *dst,
244                 struct gralloc_drm_bo_t *src,
245                 uint16_t dst_x1, uint16_t dst_y1,
246                 uint16_t dst_x2, uint16_t dst_y2,
247                 uint16_t src_x1, uint16_t src_y1,
248                 uint16_t src_x2, uint16_t src_y2)
249 {
250         struct intel_info *info = (struct intel_info *) drv;
251         struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
252         struct intel_buffer *src_ib = (struct intel_buffer *) src;
253         drm_intel_bo *bo_table[3];
254         uint32_t cmd, br13, dst_pitch, src_pitch;
255
256         /*
257          * XY_SRC_COPY_BLT_CMD does not support scaling,
258          * rectangle dimensions much match
259          */
260         if (src_x2 - src_x1 != dst_x2 - dst_x1 ||
261                 src_y2 - src_y1 != dst_y2 - dst_y1) {
262                 ALOGE("%s, src and dst rect must match", __func__);
263                 return;
264         }
265
266         if (dst->handle->format != src->handle->format) {
267                 ALOGE("%s, src and dst format must match", __func__);
268                 return;
269         }
270
271         /* nothing to blit */
272         if (src_x2 <= src_x1 || src_y2 <= src_y1)
273                 return;
274
275         /* clamp x2, y2 to surface size */
276         if (src_x2 > src->handle->width)
277                 src_x2 = src->handle->width;
278         if (src_y2 > src->handle->height)
279                 src_y2 = src->handle->height;
280
281         if (dst_x2 > dst->handle->width)
282                 dst_x2 = dst->handle->width;
283         if (dst_y2 > dst->handle->height)
284                 dst_y2 = dst->handle->height;
285
286         bo_table[0] = info->batch_ibo;
287         bo_table[1] = src_ib->ibo;
288         bo_table[2] = dst_ib->ibo;
289         if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
290                 if (batch_flush(info))
291                         return;
292                 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
293         }
294
295         cmd = XY_SRC_COPY_BLT_CMD;
296         br13 = 0xcc << 16; /* ROP_S/GXcopy */
297         dst_pitch = dst->handle->stride;
298         src_pitch = src->handle->stride;
299
300         /* Blit pitch must be dword-aligned.  Otherwise, the hardware appears to
301          * drop the low bits.
302          */
303         if (src_pitch % 4 != 0 || dst_pitch % 4 != 0) {
304                 ALOGE("%s, src and dst pitch must be dword aligned", __func__);
305                 return;
306         }
307
308         switch (gralloc_drm_get_bpp(dst->handle->format)) {
309         case 1:
310                 break;
311         case 2:
312                 br13 |= (1 << 24);
313                 break;
314         case 4:
315                 br13 |= (1 << 24) | (1 << 25);
316                 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
317                 break;
318         default:
319                 ALOGE("%s, copy with unsupported format", __func__);
320                 return;
321         }
322
323         if (info->gen >= 40) {
324                 if (dst_ib->tiling != I915_TILING_NONE) {
325                         assert(dst_pitch % 512 == 0);
326                         dst_pitch >>= 2;
327                         cmd |= XY_SRC_COPY_BLT_DST_TILED;
328                 }
329                 if (src_ib->tiling != I915_TILING_NONE) {
330                         assert(src_pitch % 512 == 0);
331                         src_pitch >>= 2;
332                         cmd |= XY_SRC_COPY_BLT_SRC_TILED;
333                 }
334         }
335
336         if (batch_reserve(info, 8))
337                 return;
338
339         batch_dword(info, cmd);
340         batch_dword(info, br13 | (uint16_t)dst_pitch);
341         batch_dword(info, (dst_y1 << 16) | dst_x1);
342         batch_dword(info, (dst_y2 << 16) | dst_x2);
343         batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
344         batch_dword(info, (src_y1 << 16) | src_x1);
345         batch_dword(info, (uint16_t)src_pitch);
346         batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
347
348         if (info->gen >= 60) {
349                 batch_reserve(info, 4);
350                 batch_dword(info, MI_FLUSH_DW | 2);
351                 batch_dword(info, 0);
352                 batch_dword(info, 0);
353                 batch_dword(info, 0);
354         }
355         else {
356                 int flags = (info->gen >= 40) ? 0 :
357                         MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
358
359                 batch_reserve(info, 1);
360                 batch_dword(info, MI_FLUSH | flags);
361         }
362
363         batch_flush(info);
364 }
365
366 static drm_intel_bo *alloc_ibo(struct intel_info *info,
367                 const struct gralloc_drm_handle_t *handle,
368                 uint32_t *tiling, unsigned long *stride)
369 {
370         drm_intel_bo *ibo;
371         const char *name;
372         int aligned_width, aligned_height, bpp;
373         unsigned long flags;
374
375         flags = 0;
376         bpp = gralloc_drm_get_bpp(handle->format);
377         if (!bpp) {
378                 ALOGE("unrecognized format 0x%x", handle->format);
379                 return NULL;
380         }
381
382         aligned_width = handle->width;
383         aligned_height = handle->height;
384         gralloc_drm_align_geometry(handle->format,
385                         &aligned_width, &aligned_height);
386
387         if (handle->usage & GRALLOC_USAGE_HW_FB) {
388                 unsigned long max_stride;
389
390                 max_stride = 32 * 1024;
391                 if (info->gen < 50)
392                         max_stride /= 2;
393                 if (info->gen < 40)
394                         max_stride /= 2;
395
396                 name = "gralloc-fb";
397                 aligned_width = ALIGN(aligned_width, 64);
398                 flags = BO_ALLOC_FOR_RENDER;
399
400                 *tiling = I915_TILING_X;
401                 *stride = aligned_width * bpp;
402                 if (*stride > max_stride) {
403                         *tiling = I915_TILING_NONE;
404                         max_stride = 32 * 1024;
405                         if (*stride > max_stride)
406                                 return NULL;
407                 }
408
409                 while (1) {
410                         ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
411                                         aligned_width, aligned_height,
412                                         bpp, tiling, stride, flags);
413                         if (!ibo || *stride > max_stride) {
414                                 if (ibo) {
415                                         drm_intel_bo_unreference(ibo);
416                                         ibo = NULL;
417                                 }
418
419                                 if (*tiling != I915_TILING_NONE) {
420                                         /* retry */
421                                         *tiling = I915_TILING_NONE;
422                                         max_stride = 32 * 1024;
423                                         continue;
424                                 }
425                         }
426                         if (ibo)
427                                 drm_intel_bo_disable_reuse(ibo);
428                         break;
429                 }
430         }
431         else {
432                 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
433                                      GRALLOC_USAGE_SW_WRITE_OFTEN))
434                         *tiling = I915_TILING_NONE;
435                 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
436                          ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
437                           handle->width >= 64))
438                         *tiling = I915_TILING_X;
439                 else
440                         *tiling = I915_TILING_NONE;
441
442                 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
443                         name = "gralloc-texture";
444                         /* see 2D texture layout of DRI drivers */
445                         aligned_width = ALIGN(aligned_width, 4);
446                         aligned_height = ALIGN(aligned_height, 2);
447                 }
448                 else {
449                         name = "gralloc-buffer";
450                 }
451
452                 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
453                         flags = BO_ALLOC_FOR_RENDER;
454
455                 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
456                                 aligned_width, aligned_height,
457                                 bpp, tiling, stride, flags);
458         }
459
460         return ibo;
461 }
462
463 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
464                 struct gralloc_drm_handle_t *handle)
465 {
466         struct intel_info *info = (struct intel_info *) drv;
467         struct intel_buffer *ib;
468
469         ib = calloc(1, sizeof(*ib));
470         if (!ib)
471                 return NULL;
472
473         if (handle->name) {
474                 uint32_t dummy;
475
476                 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
477                                 "gralloc-r", handle->name);
478                 if (!ib->ibo) {
479                         ALOGE("failed to create ibo from name %u",
480                                         handle->name);
481                         free(ib);
482                         return NULL;
483                 }
484
485                 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
486                         ALOGE("failed to get ibo tiling");
487                         drm_intel_bo_unreference(ib->ibo);
488                         free(ib);
489                         return NULL;
490                 }
491         }
492         else {
493                 unsigned long stride;
494
495                 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
496                 if (!ib->ibo) {
497                         ALOGE("failed to allocate ibo %dx%d (format %d)",
498                                         handle->width,
499                                         handle->height,
500                                         handle->format);
501                         free(ib);
502                         return NULL;
503                 }
504
505                 handle->stride = stride;
506
507                 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
508                         ALOGE("failed to flink ibo");
509                         drm_intel_bo_unreference(ib->ibo);
510                         free(ib);
511                         return NULL;
512                 }
513         }
514
515         ib->base.fb_handle = ib->ibo->handle;
516
517         ib->base.handle = handle;
518
519         return &ib->base;
520 }
521
522 static void intel_free(struct gralloc_drm_drv_t *drv,
523                 struct gralloc_drm_bo_t *bo)
524 {
525         struct intel_buffer *ib = (struct intel_buffer *) bo;
526
527         drm_intel_bo_unreference(ib->ibo);
528         free(ib);
529 }
530
531 static int intel_map(struct gralloc_drm_drv_t *drv,
532                 struct gralloc_drm_bo_t *bo,
533                 int x, int y, int w, int h,
534                 int enable_write, void **addr)
535 {
536         struct intel_buffer *ib = (struct intel_buffer *) bo;
537         int err;
538
539         if (ib->tiling != I915_TILING_NONE ||
540             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
541                 err = drm_intel_gem_bo_map_gtt(ib->ibo);
542         else
543                 err = drm_intel_bo_map(ib->ibo, enable_write);
544         if (!err)
545                 *addr = ib->ibo->virtual;
546
547         return err;
548 }
549
550 static void intel_unmap(struct gralloc_drm_drv_t *drv,
551                 struct gralloc_drm_bo_t *bo)
552 {
553         struct intel_buffer *ib = (struct intel_buffer *) bo;
554
555         if (ib->tiling != I915_TILING_NONE ||
556             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
557                 drm_intel_gem_bo_unmap_gtt(ib->ibo);
558         else
559                 drm_intel_bo_unmap(ib->ibo);
560 }
561
562 #include "intel_chipset.h" /* for platform detection macros */
563 static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
564                 struct gralloc_drm_t *drm)
565 {
566         struct intel_info *info = (struct intel_info *) drv;
567         struct drm_i915_getparam gp;
568         int pageflipping, id, has_blt;
569
570         switch (drm->primary.fb_format) {
571         case HAL_PIXEL_FORMAT_BGRA_8888:
572         case HAL_PIXEL_FORMAT_RGB_565:
573                 break;
574         default:
575                 drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
576                 break;
577         }
578
579         drm->mode_quirk_vmwgfx = 0;
580         /* why? */
581         drm->mode_sync_flip = 1;
582
583         memset(&gp, 0, sizeof(gp));
584         gp.param = I915_PARAM_HAS_PAGEFLIPPING;
585         gp.value = &pageflipping;
586         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
587                 pageflipping = 0;
588
589         memset(&gp, 0, sizeof(gp));
590         gp.param = I915_PARAM_CHIPSET_ID;
591         gp.value = &id;
592         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
593                 id = 0;
594
595         memset(&gp, 0, sizeof(gp));
596         gp.param = I915_PARAM_HAS_BLT;
597         gp.value = &has_blt;
598         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
599                 has_blt = 0;
600         info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
601
602         /* GEN4, G4X, GEN5, GEN6, GEN7 */
603         if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
604                 if (IS_GEN7(id))
605                         info->gen = 70;
606                 else if (IS_GEN6(id))
607                         info->gen = 60;
608                 else if (IS_GEN5(id))
609                         info->gen = 50;
610                 else
611                         info->gen = 40;
612         }
613         else {
614                 info->gen = 30;
615         }
616
617         if (pageflipping && info->gen > 30)
618                 drm->swap_mode = DRM_SWAP_FLIP;
619         else if (info->batch && info->gen == 30)
620                 drm->swap_mode = DRM_SWAP_COPY;
621         else
622                 drm->swap_mode = DRM_SWAP_SETCRTC;
623
624         if (drm->resources) {
625                 int pipe;
626
627                 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
628                                 drm->primary.crtc_id);
629                 drm->swap_interval = (pipe >= 0) ? 1 : 0;
630                 drm->vblank_secondary = (pipe > 0);
631         }
632         else {
633                 drm->swap_interval = 0;
634         }
635 }
636
637 static void intel_destroy(struct gralloc_drm_drv_t *drv)
638 {
639         struct intel_info *info = (struct intel_info *) drv;
640
641         batch_destroy(info);
642         drm_intel_bufmgr_destroy(info->bufmgr);
643         free(info);
644 }
645
646 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
647 {
648         struct intel_info *info;
649
650         info = calloc(1, sizeof(*info));
651         if (!info) {
652                 ALOGE("failed to allocate driver info");
653                 return NULL;
654         }
655
656         info->fd = fd;
657         info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
658         if (!info->bufmgr) {
659                 ALOGE("failed to create buffer manager");
660                 free(info);
661                 return NULL;
662         }
663
664         batch_init(info);
665
666         info->base.destroy = intel_destroy;
667         info->base.init_kms_features = intel_init_kms_features;
668         info->base.alloc = intel_alloc;
669         info->base.free = intel_free;
670         info->base.map = intel_map;
671         info->base.unmap = intel_unmap;
672         info->base.blit = intel_blit;
673         info->base.resolve_format = intel_resolve_format;
674
675         return &info->base;
676 }