OSDN Git Service

minigbm: add spew on IOCTL failures.
[android-x86/external-minigbm.git] / i915.c
1 /*
2  * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #ifdef GBM_I915
8
9 #include <stdio.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <xf86drm.h>
14 #include <i915_drm.h>
15
16 #include "gbm_priv.h"
17 #include "helpers.h"
18 #include "util.h"
19
20 struct gbm_i915_device
21 {
22         int gen;
23 };
24
25
26 static int get_gen(int device_id)
27 {
28         const uint16_t gen3_ids[] = {0x2582, 0x2592, 0x2772, 0x27A2, 0x27AE, 0x29C2, 0x29B2, 0x29D2, 0xA001, 0xA011};
29         unsigned i;
30         for(i = 0; i < ARRAY_SIZE(gen3_ids); i++)
31                 if (gen3_ids[i] == device_id)
32                         return 3;
33
34         return 4;
35 }
36
37 int gbm_i915_init(struct gbm_device *gbm)
38 {
39         struct gbm_i915_device *i915_gbm;
40         drm_i915_getparam_t get_param;
41         int device_id;
42         int ret;
43
44         i915_gbm = (struct gbm_i915_device*)malloc(sizeof(*i915_gbm));
45         if (!i915_gbm)
46                 return -1;
47
48         memset(&get_param, 0, sizeof(get_param));
49         get_param.param = I915_PARAM_CHIPSET_ID;
50         get_param.value = &device_id;
51         ret = drmIoctl(gbm->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
52         if (ret) {
53                 fprintf(stderr, "minigbm: DRM_IOCTL_I915_GETPARAM failed\n");
54                 free(i915_gbm);
55                 return -1;
56         }
57
58         i915_gbm->gen = get_gen(device_id);
59
60         gbm->priv = i915_gbm;
61
62         return 0;
63 }
64
65 void gbm_i915_close(struct gbm_device *gbm)
66 {
67         free(gbm->priv);
68         gbm->priv = NULL;
69 }
70
71 static void i915_align_dimensions(struct gbm_device *gbm, uint32_t tiling_mode, uint32_t *width, uint32_t *height, int bpp)
72 {
73         struct gbm_i915_device *i915_gbm = (struct gbm_i915_device *)gbm->priv;
74         uint32_t width_alignment = 4, height_alignment = 4;
75
76         switch(tiling_mode) {
77                 default:
78                 case I915_TILING_NONE:
79                         width_alignment = 64 / bpp;
80                         break;
81
82                 case I915_TILING_X:
83                         width_alignment = 512 / bpp;
84                         height_alignment = 8;
85                         break;
86
87                 case I915_TILING_Y:
88                         if (i915_gbm->gen == 3) {
89                                 width_alignment = 512 / bpp;
90                                 height_alignment = 8;
91                         } else  {
92                                 width_alignment = 128 / bpp;
93                                 height_alignment = 32;
94                         }
95                         break;
96         }
97
98         if (i915_gbm->gen > 3) {
99                 *width = ALIGN(*width, width_alignment);
100                 *height = ALIGN(*height, height_alignment);
101         } else {
102                 uint32_t w;
103                 for (w = width_alignment; w < *width;  w <<= 1)
104                         ;
105                 *width = w;
106                 *height = ALIGN(*height, height_alignment);
107         }
108 }
109
110 static int i915_verify_dimensions(struct gbm_device *gbm, uint32_t stride, uint32_t height)
111 {
112         struct gbm_i915_device *i915_gbm = (struct gbm_i915_device *)gbm->priv;
113         if (i915_gbm->gen <= 3 && stride > 8192)
114                 return 0;
115
116         return 1;
117 }
118
119 int gbm_i915_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)
120 {
121         struct gbm_device *gbm = bo->gbm;
122         int bpp = gbm_bytes_from_format(format);
123         struct drm_i915_gem_create gem_create;
124         struct drm_i915_gem_set_tiling gem_set_tiling;
125         uint32_t tiling_mode = I915_TILING_NONE;
126         size_t size;
127         int ret;
128
129         if (flags & GBM_BO_USE_CURSOR)
130                 tiling_mode = I915_TILING_NONE;
131         else if (flags & GBM_BO_USE_SCANOUT)
132                 tiling_mode = I915_TILING_X;
133         else if (flags & GBM_BO_USE_RENDERING)
134                 tiling_mode = I915_TILING_Y;
135
136         i915_align_dimensions(gbm, tiling_mode, &width, &height, bpp);
137
138         bo->stride = width * bpp;
139
140         if (!i915_verify_dimensions(gbm, bo->stride, height))
141                 return EINVAL;
142
143         memset(&gem_create, 0, sizeof(gem_create));
144         size = width * height * bpp;
145         gem_create.size = size;
146
147         ret = drmIoctl(gbm->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
148         if (ret) {
149                 fprintf(stderr, "minigbm: DRM_IOCTL_I915_GEM_CREATE failed "
150                                 "(size=%zu)\n", size);
151                 return ret;
152         }
153         bo->handle.u32 = gem_create.handle;
154         bo->size = size;
155
156         memset(&gem_set_tiling, 0, sizeof(gem_set_tiling));
157         do {
158                 gem_set_tiling.handle = bo->handle.u32;
159                 gem_set_tiling.tiling_mode = tiling_mode;
160                 gem_set_tiling.stride = bo->stride;
161                 ret = drmIoctl(gbm->fd, DRM_IOCTL_I915_GEM_SET_TILING, &gem_set_tiling);
162         } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
163
164         if (ret == -1) {
165                 struct drm_gem_close gem_close;
166                 gem_close.handle = bo->handle.u32;
167                 fprintf(stderr, "minigbm: DRM_IOCTL_I915_GEM_SET_TILING failed "
168                                 "errno=%x (handle=%x, tiling=%x, stride=%x)\n",
169                                 errno,
170                                 gem_set_tiling.handle,
171                                 gem_set_tiling.tiling_mode,
172                                 gem_set_tiling.stride);
173                 drmIoctl(gbm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
174                 return -errno;
175         }
176
177         return 0;
178 }
179
180 const struct gbm_driver gbm_driver_i915 =
181 {
182         .name = "i915",
183         .init = gbm_i915_init,
184         .close = gbm_i915_close,
185         .bo_create = gbm_i915_bo_create,
186         .bo_destroy = gbm_gem_bo_destroy,
187         .format_list = {
188                 {GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
189                 {GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
190                 {GBM_FORMAT_XBGR8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
191                 {GBM_FORMAT_ABGR8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
192                 {GBM_FORMAT_XRGB1555, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
193                 {GBM_FORMAT_ARGB1555, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
194                 {GBM_FORMAT_RGB565,   GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
195         }
196 };
197
198 #endif