OSDN Git Service

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