OSDN Git Service

Revert "gralloc: hdmi cloned mode support"
[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_exec(info->batch_ibo, size, NULL, 0, 0);
134         if (ret) {
135                 ALOGE("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                 ALOGE("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                 ALOGE("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                 ALOGE("unrecognized format 0x%x", handle->format);
309                 return NULL;
310         }
311
312         aligned_width = handle->width;
313         aligned_height = handle->height;
314         gralloc_drm_align_geometry(handle->format,
315                         &aligned_width, &aligned_height);
316
317         if (handle->usage & GRALLOC_USAGE_HW_FB) {
318                 unsigned long max_stride;
319
320                 max_stride = 32 * 1024;
321                 if (info->gen < 50)
322                         max_stride /= 2;
323                 if (info->gen < 40)
324                         max_stride /= 2;
325
326                 name = "gralloc-fb";
327                 aligned_width = (aligned_width + 63) & ~63;
328                 flags = BO_ALLOC_FOR_RENDER;
329
330                 *tiling = I915_TILING_X;
331                 *stride = aligned_width * bpp;
332                 if (*stride > max_stride) {
333                         *tiling = I915_TILING_NONE;
334                         max_stride = 32 * 1024;
335                         if (*stride > max_stride)
336                                 return NULL;
337                 }
338
339                 while (1) {
340                         ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
341                                         aligned_width, aligned_height,
342                                         bpp, tiling, stride, flags);
343                         if (!ibo || *stride > max_stride) {
344                                 if (ibo) {
345                                         drm_intel_bo_unreference(ibo);
346                                         ibo = NULL;
347                                 }
348
349                                 if (*tiling != I915_TILING_NONE) {
350                                         /* retry */
351                                         *tiling = I915_TILING_NONE;
352                                         max_stride = 32 * 1024;
353                                         continue;
354                                 }
355                         }
356                         if (ibo)
357                                 drm_intel_bo_disable_reuse(ibo);
358                         break;
359                 }
360         }
361         else {
362                 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
363                                      GRALLOC_USAGE_SW_WRITE_OFTEN))
364                         *tiling = I915_TILING_NONE;
365                 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
366                          ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
367                           handle->width >= 64))
368                         *tiling = I915_TILING_X;
369                 else
370                         *tiling = I915_TILING_NONE;
371
372                 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
373                         name = "gralloc-texture";
374                         /* see 2D texture layout of DRI drivers */
375                         aligned_width = (aligned_width + 3) & ~3;
376                         aligned_height = (aligned_height + 1) & ~1;
377                 }
378                 else {
379                         name = "gralloc-buffer";
380                 }
381
382                 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
383                         flags = BO_ALLOC_FOR_RENDER;
384
385                 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
386                                 aligned_width, aligned_height,
387                                 bpp, tiling, stride, flags);
388         }
389
390         return ibo;
391 }
392
393 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
394                 struct gralloc_drm_handle_t *handle)
395 {
396         struct intel_info *info = (struct intel_info *) drv;
397         struct intel_buffer *ib;
398
399         ib = calloc(1, sizeof(*ib));
400         if (!ib)
401                 return NULL;
402
403         if (handle->name) {
404                 uint32_t dummy;
405
406                 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
407                                 "gralloc-r", handle->name);
408                 if (!ib->ibo) {
409                         ALOGE("failed to create ibo from name %u",
410                                         handle->name);
411                         free(ib);
412                         return NULL;
413                 }
414
415                 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
416                         ALOGE("failed to get ibo tiling");
417                         drm_intel_bo_unreference(ib->ibo);
418                         free(ib);
419                         return NULL;
420                 }
421         }
422         else {
423                 unsigned long stride;
424
425                 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
426                 if (!ib->ibo) {
427                         ALOGE("failed to allocate ibo %dx%d (format %d)",
428                                         handle->width,
429                                         handle->height,
430                                         handle->format);
431                         free(ib);
432                         return NULL;
433                 }
434
435                 handle->stride = stride;
436
437                 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
438                         ALOGE("failed to flink ibo");
439                         drm_intel_bo_unreference(ib->ibo);
440                         free(ib);
441                         return NULL;
442                 }
443         }
444
445         ib->base.fb_handle = ib->ibo->handle;
446
447         ib->base.handle = handle;
448
449         return &ib->base;
450 }
451
452 static void intel_free(struct gralloc_drm_drv_t *drv,
453                 struct gralloc_drm_bo_t *bo)
454 {
455         struct intel_buffer *ib = (struct intel_buffer *) bo;
456
457         drm_intel_bo_unreference(ib->ibo);
458         free(ib);
459 }
460
461 static int intel_map(struct gralloc_drm_drv_t *drv,
462                 struct gralloc_drm_bo_t *bo,
463                 int x, int y, int w, int h,
464                 int enable_write, void **addr)
465 {
466         struct intel_buffer *ib = (struct intel_buffer *) bo;
467         int err;
468
469         if (ib->tiling != I915_TILING_NONE ||
470             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
471                 err = drm_intel_gem_bo_map_gtt(ib->ibo);
472         else
473                 err = drm_intel_bo_map(ib->ibo, enable_write);
474         if (!err)
475                 *addr = ib->ibo->virtual;
476
477         return err;
478 }
479
480 static void intel_unmap(struct gralloc_drm_drv_t *drv,
481                 struct gralloc_drm_bo_t *bo)
482 {
483         struct intel_buffer *ib = (struct intel_buffer *) bo;
484
485         if (ib->tiling != I915_TILING_NONE ||
486             (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
487                 drm_intel_gem_bo_unmap_gtt(ib->ibo);
488         else
489                 drm_intel_bo_unmap(ib->ibo);
490 }
491
492 #include "dri/intel_chipset.h" /* for IS_965() */
493 static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
494                 struct gralloc_drm_t *drm)
495 {
496         struct intel_info *info = (struct intel_info *) drv;
497         struct drm_i915_getparam gp;
498         int pageflipping, id;
499
500         switch (drm->fb_format) {
501         case HAL_PIXEL_FORMAT_BGRA_8888:
502         case HAL_PIXEL_FORMAT_RGB_565:
503                 break;
504         default:
505                 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
506                 break;
507         }
508
509         drm->mode_quirk_vmwgfx = 0;
510         /* why? */
511         drm->mode_sync_flip = 1;
512
513         memset(&gp, 0, sizeof(gp));
514         gp.param = I915_PARAM_HAS_PAGEFLIPPING;
515         gp.value = &pageflipping;
516         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
517                 pageflipping = 0;
518
519         memset(&gp, 0, sizeof(gp));
520         gp.param = I915_PARAM_CHIPSET_ID;
521         gp.value = &id;
522         if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
523                 id = 0;
524
525         if (IS_965(id)) {
526                 if (IS_GEN6(id))
527                         info->gen = 60;
528                 else if (IS_GEN5(id))
529                         info->gen = 50;
530                 else
531                         info->gen = 40;
532         }
533         else {
534                 info->gen = 30;
535         }
536
537         if (pageflipping && info->gen > 30)
538                 drm->swap_mode = DRM_SWAP_FLIP;
539         else if (info->batch && info->gen == 30)
540                 drm->swap_mode = DRM_SWAP_COPY;
541         else
542                 drm->swap_mode = DRM_SWAP_SETCRTC;
543
544         if (drm->resources) {
545                 int pipe;
546
547                 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
548                                 drm->crtc_id);
549                 drm->swap_interval = (pipe >= 0) ? 1 : 0;
550                 drm->vblank_secondary = (pipe > 0);
551         }
552         else {
553                 drm->swap_interval = 0;
554         }
555 }
556
557 static void intel_destroy(struct gralloc_drm_drv_t *drv)
558 {
559         struct intel_info *info = (struct intel_info *) drv;
560
561         batch_destroy(info);
562         drm_intel_bufmgr_destroy(info->bufmgr);
563         free(info);
564 }
565
566 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
567 {
568         struct intel_info *info;
569
570         info = calloc(1, sizeof(*info));
571         if (!info) {
572                 ALOGE("failed to allocate driver info");
573                 return NULL;
574         }
575
576         info->fd = fd;
577         info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
578         if (!info->bufmgr) {
579                 ALOGE("failed to create buffer manager");
580                 free(info);
581                 return NULL;
582         }
583
584         batch_init(info);
585
586         info->base.destroy = intel_destroy;
587         info->base.init_kms_features = intel_init_kms_features;
588         info->base.alloc = intel_alloc;
589         info->base.free = intel_free;
590         info->base.map = intel_map;
591         info->base.unmap = intel_unmap;
592         info->base.copy = intel_copy;
593
594         return &info->base;
595 }