Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / winsys / radeon / drm / radeon_drm_buffer.c
1
2 #include <sys/ioctl.h>
3 #include "radeon_drm.h"
4 #include "radeon_bo_gem.h"
5 #include "radeon_cs_gem.h"
6 #include "radeon_buffer.h"
7
8 #include "util/u_inlines.h"
9 #include "util/u_memory.h"
10 #include "util/u_simple_list.h"
11 #include "pipebuffer/pb_buffer.h"
12 #include "pipebuffer/pb_bufmgr.h"
13
14 #include "radeon_winsys.h"
15 struct radeon_drm_bufmgr;
16
17 struct radeon_drm_buffer {
18     struct pb_buffer base;
19     struct radeon_drm_bufmgr *mgr;
20
21     struct radeon_bo *bo;
22
23     boolean flinked;
24     uint32_t flink;
25
26     struct radeon_drm_buffer *next, *prev;
27 };
28
29 extern const struct pb_vtbl radeon_drm_buffer_vtbl;
30
31
32 static INLINE struct radeon_drm_buffer *
33 radeon_drm_buffer(struct pb_buffer *buf)
34 {
35     assert(buf);
36     assert(buf->vtbl == &radeon_drm_buffer_vtbl);
37     return (struct radeon_drm_buffer *)buf;
38 }
39
40 struct radeon_drm_bufmgr {
41     struct pb_manager base;
42     struct radeon_libdrm_winsys *rws;
43     struct radeon_drm_buffer buffer_map_list;
44 };
45
46 static INLINE struct radeon_drm_bufmgr *
47 radeon_drm_bufmgr(struct pb_manager *mgr)
48 {
49     assert(mgr);
50     return (struct radeon_drm_bufmgr *)mgr;
51 }
52
53 static void
54 radeon_drm_buffer_destroy(struct pb_buffer *_buf)
55 {
56     struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf);
57
58     if (buf->bo->ptr != NULL) {
59         remove_from_list(buf);
60         radeon_bo_unmap(buf->bo);
61         buf->bo->ptr = NULL;
62     }
63     radeon_bo_unref(buf->bo);
64
65     FREE(buf);
66 }
67
68 static void *
69 radeon_drm_buffer_map(struct pb_buffer *_buf,
70                       unsigned flags)
71 {
72     struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf);
73     int write = 0;
74
75     if (flags & PIPE_TRANSFER_DONTBLOCK) {
76         if ((_buf->base.usage & PIPE_BIND_VERTEX_BUFFER) ||
77             (_buf->base.usage & PIPE_BIND_INDEX_BUFFER))
78             if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs))
79                 return NULL;
80     }
81
82     if (buf->bo->ptr != NULL)
83         return buf->bo->ptr;
84
85     if (flags & PIPE_TRANSFER_DONTBLOCK) {
86         uint32_t domain;
87         if (radeon_bo_is_busy(buf->bo, &domain))
88             return NULL;
89     }
90
91     if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs)) {
92         buf->mgr->rws->flush_cb(buf->mgr->rws->flush_data);
93     }
94
95     if (flags & PIPE_TRANSFER_WRITE) {
96         write = 1;
97     }
98
99     if (radeon_bo_map(buf->bo, write)) {
100         return NULL;
101     }
102     insert_at_tail(&buf->mgr->buffer_map_list, buf);
103     return buf->bo->ptr;
104 }
105
106 static void
107 radeon_drm_buffer_unmap(struct pb_buffer *_buf)
108 {
109     (void)_buf;
110 }
111
112 static void
113 radeon_drm_buffer_get_base_buffer(struct pb_buffer *buf,
114                                   struct pb_buffer **base_buf,
115                                   unsigned *offset)
116 {
117     *base_buf = buf;
118     *offset = 0;
119 }
120
121
122 static enum pipe_error
123 radeon_drm_buffer_validate(struct pb_buffer *_buf, 
124                            struct pb_validate *vl,
125                            unsigned flags)
126 {
127    /* Always pinned */
128    return PIPE_OK;
129 }
130
131 static void
132 radeon_drm_buffer_fence(struct pb_buffer *buf,
133                         struct pipe_fence_handle *fence)
134 {
135 }
136
137 const struct pb_vtbl radeon_drm_buffer_vtbl = {
138     radeon_drm_buffer_destroy,
139     radeon_drm_buffer_map,
140     radeon_drm_buffer_unmap,
141     radeon_drm_buffer_validate,
142     radeon_drm_buffer_fence,
143     radeon_drm_buffer_get_base_buffer,
144 };
145
146
147 static uint32_t radeon_domain_from_usage(unsigned usage)
148 {
149     uint32_t domain = 0;
150
151     if (usage & PIPE_BIND_RENDER_TARGET) {
152         domain |= RADEON_GEM_DOMAIN_VRAM;
153     }
154     if (usage & PIPE_BIND_DEPTH_STENCIL) {
155         domain |= RADEON_GEM_DOMAIN_VRAM;
156     }
157     if (usage & PIPE_BIND_SAMPLER_VIEW) {
158         domain |= RADEON_GEM_DOMAIN_VRAM;
159     }
160     /* also need BIND_BLIT_SOURCE/DESTINATION ? */
161     if (usage & PIPE_BIND_VERTEX_BUFFER) {
162         domain |= RADEON_GEM_DOMAIN_GTT;
163     }
164     if (usage & PIPE_BIND_INDEX_BUFFER) {
165         domain |= RADEON_GEM_DOMAIN_GTT;
166     }
167
168     return domain;
169 }
170
171 struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr,
172                                                               uint32_t handle)
173 {
174     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
175     struct radeon_libdrm_winsys *rws = mgr->rws;
176     struct radeon_drm_buffer *buf;
177     struct radeon_bo *bo;
178
179     bo = radeon_bo_open(rws->bom, handle, 0,
180                         0, 0, 0);
181     if (bo == NULL)
182         return NULL;
183
184     buf = CALLOC_STRUCT(radeon_drm_buffer);
185     if (!buf) {
186         radeon_bo_unref(bo);
187         return NULL;
188     }
189
190     make_empty_list(buf);
191
192     pipe_reference_init(&buf->base.base.reference, 1);
193     buf->base.base.alignment = 0;
194     buf->base.base.usage = PIPE_BIND_SAMPLER_VIEW;
195     buf->base.base.size = 0;
196     buf->base.vtbl = &radeon_drm_buffer_vtbl;
197     buf->mgr = mgr;
198
199     buf->bo = bo;
200
201     return &buf->base;
202 }
203
204 static struct pb_buffer *
205 radeon_drm_bufmgr_create_buffer(struct pb_manager *_mgr,
206                                 pb_size size,
207                                 const struct pb_desc *desc)
208 {
209     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
210     struct radeon_libdrm_winsys *rws = mgr->rws;
211     struct radeon_drm_buffer *buf;
212     uint32_t domain;
213
214     buf = CALLOC_STRUCT(radeon_drm_buffer);
215     if (!buf)
216         goto error1;
217
218     pipe_reference_init(&buf->base.base.reference, 1);
219     buf->base.base.alignment = desc->alignment;
220     buf->base.base.usage = desc->usage;
221     buf->base.base.size = size;
222     buf->base.vtbl = &radeon_drm_buffer_vtbl;
223     buf->mgr = mgr;
224
225     make_empty_list(buf);
226     domain = radeon_domain_from_usage(desc->usage);
227     buf->bo = radeon_bo_open(rws->bom, 0, size,
228                              desc->alignment, domain, 0);
229     if (buf->bo == NULL)
230         goto error2;
231
232     return &buf->base;
233
234  error2:
235     FREE(buf);
236  error1:
237     return NULL; 
238 }
239
240 static void
241 radeon_drm_bufmgr_flush(struct pb_manager *mgr)
242 {
243     /* NOP */
244 }
245
246 static void
247 radeon_drm_bufmgr_destroy(struct pb_manager *_mgr)
248 {
249     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
250     FREE(mgr);
251 }
252
253 struct pb_manager *
254 radeon_drm_bufmgr_create(struct radeon_libdrm_winsys *rws)
255 {
256     struct radeon_drm_bufmgr *mgr;
257
258     mgr = CALLOC_STRUCT(radeon_drm_bufmgr);
259     if (!mgr)
260         return NULL;
261
262     mgr->base.destroy = radeon_drm_bufmgr_destroy;
263     mgr->base.create_buffer = radeon_drm_bufmgr_create_buffer;
264     mgr->base.flush = radeon_drm_bufmgr_flush;
265
266     mgr->rws = rws;
267     make_empty_list(&mgr->buffer_map_list);
268     return &mgr->base;
269 }
270
271 static struct radeon_drm_buffer *get_drm_buffer(struct pb_buffer *_buf)
272 {
273     struct radeon_drm_buffer *buf;
274     if (_buf->vtbl == &radeon_drm_buffer_vtbl) {
275         buf = radeon_drm_buffer(_buf);
276     } else {
277         struct pb_buffer *base_buf;
278         pb_size offset;
279         pb_get_base_buffer(_buf, &base_buf, &offset);
280
281         buf = radeon_drm_buffer(base_buf);
282     }
283     return buf;
284 }
285
286 boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf,
287                                      struct winsys_handle *whandle)
288 {
289     int retval, fd;
290     struct drm_gem_flink flink;
291     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
292     if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
293         if (!buf->flinked) {
294             fd = buf->mgr->rws->fd;
295             flink.handle = buf->bo->handle;
296
297             retval = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
298             if (retval) {
299                 return FALSE;
300             }
301
302             buf->flinked = TRUE;
303             buf->flink = flink.name;
304         }
305         whandle->handle = buf->flink;
306     } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
307         whandle->handle = buf->bo->handle;
308     }
309     return TRUE;
310 }
311
312 void radeon_drm_bufmgr_get_tiling(struct pb_buffer *_buf,
313                                   enum r300_buffer_tiling *microtiled,
314                                   enum r300_buffer_tiling *macrotiled)
315 {
316     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
317     uint32_t flags = 0, pitch;
318
319     radeon_bo_get_tiling(buf->bo, &flags, &pitch);
320
321     *microtiled = R300_BUFFER_LINEAR;
322     *macrotiled = R300_BUFFER_LINEAR;
323     if (flags & RADEON_BO_FLAGS_MICRO_TILE)
324         *microtiled = R300_BUFFER_TILED;
325
326     if (flags & RADEON_BO_FLAGS_MACRO_TILE)
327         *macrotiled = R300_BUFFER_TILED;
328 }
329
330 void radeon_drm_bufmgr_set_tiling(struct pb_buffer *_buf,
331                                   enum r300_buffer_tiling microtiled,
332                                   enum r300_buffer_tiling macrotiled,
333                                   uint32_t pitch)
334 {
335     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
336     uint32_t flags = 0, old_flags, old_pitch;
337     if (microtiled == R300_BUFFER_TILED)
338         flags |= RADEON_BO_FLAGS_MICRO_TILE;
339 /* XXX Remove this ifdef when libdrm version 2.4.19 becomes mandatory. */
340 #ifdef RADEON_BO_FLAGS_MICRO_TILE_SQUARE
341     else if (microtiled == R300_BUFFER_SQUARETILED)
342         flags |= RADEON_BO_FLAGS_MICRO_TILE_SQUARE;
343 #endif
344     if (macrotiled == R300_BUFFER_TILED)
345         flags |= RADEON_BO_FLAGS_MACRO_TILE;
346
347     radeon_bo_get_tiling(buf->bo, &old_flags, &old_pitch);
348
349     if (flags != old_flags || pitch != old_pitch) {
350         /* Tiling determines how DRM treats the buffer data.
351          * We must flush CS when changing it if the buffer is referenced. */
352         if (radeon_bo_is_referenced_by_cs(buf->bo,  buf->mgr->rws->cs)) {
353             buf->mgr->rws->flush_cb(buf->mgr->rws->flush_data);
354         }
355     }
356     radeon_bo_set_tiling(buf->bo, flags, pitch);
357
358 }
359
360 boolean radeon_drm_bufmgr_add_buffer(struct pb_buffer *_buf,
361                                      uint32_t rd, uint32_t wd)
362 {
363     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
364     radeon_cs_space_add_persistent_bo(buf->mgr->rws->cs, buf->bo,
365                                           rd, wd);
366     return TRUE;
367 }
368
369 void radeon_drm_bufmgr_write_reloc(struct pb_buffer *_buf,
370                                    uint32_t rd, uint32_t wd,
371                                    uint32_t flags)
372 {
373     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
374     int retval;
375
376     retval = radeon_cs_write_reloc(buf->mgr->rws->cs,
377                                    buf->bo, rd, wd, flags);
378     if (retval) {
379         debug_printf("radeon: Relocation of %p (%d, %d, %d) failed!\n",
380                      buf, rd, wd, flags);
381     }
382 }
383
384 boolean radeon_drm_bufmgr_is_buffer_referenced(struct pb_buffer *_buf)
385 {
386     struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
387     uint32_t domain;
388
389     return (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs) ||
390             radeon_bo_is_busy(buf->bo, &domain));
391 }
392
393
394 void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr)
395 {
396     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
397     struct radeon_drm_buffer *rpb, *t_rpb;
398
399     foreach_s(rpb, t_rpb, &mgr->buffer_map_list) {
400         radeon_bo_unmap(rpb->bo);
401         rpb->bo->ptr = NULL;
402         remove_from_list(rpb);
403     }
404
405     make_empty_list(&mgr->buffer_map_list);
406 }