1 #include "frontend/drm_driver.h"
2 #include "i915_drm_winsys.h"
3 #include "util/u_memory.h"
4 
5 #include "drm-uapi/i915_drm.h"
6 
i915_drm_type_to_name(enum i915_winsys_buffer_type type)7 static char *i915_drm_type_to_name(enum i915_winsys_buffer_type type)
8 {
9    char *name;
10 
11    if (type == I915_NEW_TEXTURE) {
12       name = "gallium3d_texture";
13    } else if (type == I915_NEW_VERTEX) {
14       name = "gallium3d_vertex";
15    } else if (type == I915_NEW_SCANOUT) {
16       name = "gallium3d_scanout";
17    } else {
18       assert(0);
19       name = "gallium3d_unknown";
20    }
21 
22    return name;
23 }
24 
25 static struct i915_winsys_buffer *
i915_drm_buffer_create(struct i915_winsys * iws,unsigned size,enum i915_winsys_buffer_type type)26 i915_drm_buffer_create(struct i915_winsys *iws,
27                         unsigned size,
28                         enum i915_winsys_buffer_type type)
29 {
30    struct i915_drm_buffer *buf = CALLOC_STRUCT(i915_drm_buffer);
31    struct i915_drm_winsys *idws = i915_drm_winsys(iws);
32 
33    if (!buf)
34       return NULL;
35 
36    buf->magic = 0xDEAD1337;
37    buf->flinked = false;
38    buf->flink = 0;
39 
40    buf->bo = drm_intel_bo_alloc(idws->gem_manager,
41                                 i915_drm_type_to_name(type), size, 0);
42 
43    if (!buf->bo)
44       goto err;
45 
46    return (struct i915_winsys_buffer *)buf;
47 
48 err:
49    assert(0);
50    FREE(buf);
51    return NULL;
52 }
53 
54 static struct i915_winsys_buffer *
i915_drm_buffer_create_tiled(struct i915_winsys * iws,unsigned * stride,unsigned height,enum i915_winsys_buffer_tile * tiling,enum i915_winsys_buffer_type type)55 i915_drm_buffer_create_tiled(struct i915_winsys *iws,
56                              unsigned *stride, unsigned height,
57                              enum i915_winsys_buffer_tile *tiling,
58                              enum i915_winsys_buffer_type type)
59 {
60    struct i915_drm_buffer *buf = CALLOC_STRUCT(i915_drm_buffer);
61    struct i915_drm_winsys *idws = i915_drm_winsys(iws);
62    unsigned long pitch = 0;
63    uint32_t tiling_mode = *tiling;
64 
65    if (!buf)
66       return NULL;
67 
68    buf->magic = 0xDEAD1337;
69    buf->flinked = false;
70    buf->flink = 0;
71 
72    buf->bo = drm_intel_bo_alloc_tiled(idws->gem_manager,
73                                       i915_drm_type_to_name(type),
74                                       *stride, height, 1,
75                                       &tiling_mode, &pitch, 0);
76 
77    if (!buf->bo)
78       goto err;
79 
80    *stride = pitch;
81    *tiling = tiling_mode;
82    return (struct i915_winsys_buffer *)buf;
83 
84 err:
85    assert(0);
86    FREE(buf);
87    return NULL;
88 }
89 
90 static struct i915_winsys_buffer *
i915_drm_buffer_from_handle(struct i915_winsys * iws,struct winsys_handle * whandle,unsigned height,enum i915_winsys_buffer_tile * tiling,unsigned * stride)91 i915_drm_buffer_from_handle(struct i915_winsys *iws,
92                             struct winsys_handle *whandle,
93                             unsigned height,
94                             enum i915_winsys_buffer_tile *tiling,
95                             unsigned *stride)
96 {
97    struct i915_drm_winsys *idws = i915_drm_winsys(iws);
98    struct i915_drm_buffer *buf;
99    uint32_t tile = 0, swizzle = 0;
100 
101    if ((whandle->type != WINSYS_HANDLE_TYPE_SHARED) && (whandle->type != WINSYS_HANDLE_TYPE_FD))
102       return NULL;
103 
104    if (whandle->offset != 0)
105       return NULL;
106 
107    buf = CALLOC_STRUCT(i915_drm_buffer);
108    if (!buf)
109       return NULL;
110 
111    buf->magic = 0xDEAD1337;
112 
113    if (whandle->type == WINSYS_HANDLE_TYPE_SHARED)
114        buf->bo = drm_intel_bo_gem_create_from_name(idws->gem_manager, "gallium3d_from_handle", whandle->handle);
115    else if (whandle->type == WINSYS_HANDLE_TYPE_FD) {
116        int fd = (int) whandle->handle;
117        buf->bo = drm_intel_bo_gem_create_from_prime(idws->gem_manager, fd, height * whandle->stride);
118    }
119 
120    buf->flinked = true;
121    buf->flink = whandle->handle;
122 
123    if (!buf->bo)
124       goto err;
125 
126    drm_intel_bo_get_tiling(buf->bo, &tile, &swizzle);
127 
128    *stride = whandle->stride;
129    *tiling = tile;
130 
131    return (struct i915_winsys_buffer *)buf;
132 
133 err:
134    FREE(buf);
135    return NULL;
136 }
137 
138 static bool
i915_drm_buffer_get_handle(struct i915_winsys * iws,struct i915_winsys_buffer * buffer,struct winsys_handle * whandle,unsigned stride)139 i915_drm_buffer_get_handle(struct i915_winsys *iws,
140                             struct i915_winsys_buffer *buffer,
141                             struct winsys_handle *whandle,
142                             unsigned stride)
143 {
144    struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
145 
146    if (whandle->type == WINSYS_HANDLE_TYPE_SHARED) {
147       if (!buf->flinked) {
148          if (drm_intel_bo_flink(buf->bo, &buf->flink))
149             return false;
150          buf->flinked = true;
151       }
152 
153       whandle->handle = buf->flink;
154    } else if (whandle->type == WINSYS_HANDLE_TYPE_KMS) {
155       whandle->handle = buf->bo->handle;
156    } else if (whandle->type == WINSYS_HANDLE_TYPE_FD) {
157       int fd;
158 
159       if (drm_intel_bo_gem_export_to_prime(buf->bo, &fd))
160          return false;
161       whandle->handle = fd;
162    } else {
163       assert(!"unknown usage");
164       return false;
165    }
166 
167    whandle->stride = stride;
168    return true;
169 }
170 
171 static void *
i915_drm_buffer_map(struct i915_winsys * iws,struct i915_winsys_buffer * buffer,bool write)172 i915_drm_buffer_map(struct i915_winsys *iws,
173                      struct i915_winsys_buffer *buffer,
174                      bool write)
175 {
176    struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
177    drm_intel_bo *bo = intel_bo(buffer);
178    int ret = 0;
179 
180    assert(bo);
181 
182    if (buf->map_count)
183       goto out;
184 
185    ret = drm_intel_gem_bo_map_gtt(bo);
186 
187    buf->ptr = bo->virtual;
188 
189    assert(ret == 0);
190 out:
191    if (ret)
192       return NULL;
193 
194    buf->map_count++;
195    return buf->ptr;
196 }
197 
198 static void
i915_drm_buffer_unmap(struct i915_winsys * iws,struct i915_winsys_buffer * buffer)199 i915_drm_buffer_unmap(struct i915_winsys *iws,
200                        struct i915_winsys_buffer *buffer)
201 {
202    struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
203 
204    if (--buf->map_count)
205       return;
206 
207    drm_intel_gem_bo_unmap_gtt(intel_bo(buffer));
208 }
209 
210 static int
i915_drm_buffer_write(struct i915_winsys * iws,struct i915_winsys_buffer * buffer,size_t offset,size_t size,const void * data)211 i915_drm_buffer_write(struct i915_winsys *iws,
212                        struct i915_winsys_buffer *buffer,
213                        size_t offset,
214                        size_t size,
215                        const void *data)
216 {
217    struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
218 
219    return drm_intel_bo_subdata(buf->bo, offset, size, (void*)data);
220 }
221 
222 static void
i915_drm_buffer_destroy(struct i915_winsys * iws,struct i915_winsys_buffer * buffer)223 i915_drm_buffer_destroy(struct i915_winsys *iws,
224                          struct i915_winsys_buffer *buffer)
225 {
226    drm_intel_bo_unreference(intel_bo(buffer));
227 
228 #ifdef DEBUG
229    i915_drm_buffer(buffer)->magic = 0;
230    i915_drm_buffer(buffer)->bo = NULL;
231 #endif
232 
233    FREE(buffer);
234 }
235 
236 static bool
i915_drm_buffer_is_busy(struct i915_winsys * iws,struct i915_winsys_buffer * buffer)237 i915_drm_buffer_is_busy(struct i915_winsys *iws,
238                         struct i915_winsys_buffer *buffer)
239 {
240    struct i915_drm_buffer* i915_buffer = i915_drm_buffer(buffer);
241    if (!i915_buffer)
242       return false;
243    return drm_intel_bo_busy(i915_buffer->bo);
244 }
245 
246 
247 void
i915_drm_winsys_init_buffer_functions(struct i915_drm_winsys * idws)248 i915_drm_winsys_init_buffer_functions(struct i915_drm_winsys *idws)
249 {
250    idws->base.buffer_create = i915_drm_buffer_create;
251    idws->base.buffer_create_tiled = i915_drm_buffer_create_tiled;
252    idws->base.buffer_from_handle = i915_drm_buffer_from_handle;
253    idws->base.buffer_get_handle = i915_drm_buffer_get_handle;
254    idws->base.buffer_map = i915_drm_buffer_map;
255    idws->base.buffer_unmap = i915_drm_buffer_unmap;
256    idws->base.buffer_write = i915_drm_buffer_write;
257    idws->base.buffer_destroy = i915_drm_buffer_destroy;
258    idws->base.buffer_is_busy = i915_drm_buffer_is_busy;
259 }
260