Merge remote branch 'origin/7.8'
[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_BUFFER_USAGE_DONTBLOCK) {
76 if ((_buf->base.usage & PIPE_BUFFER_USAGE_VERTEX) ||
77 (_buf->base.usage & PIPE_BUFFER_USAGE_INDEX))
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_BUFFER_USAGE_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_BUFFER_USAGE_CPU_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_BUFFER_USAGE_GPU_WRITE) {
152 domain |= RADEON_GEM_DOMAIN_VRAM;
153 }
154 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
155 domain |= RADEON_GEM_DOMAIN_VRAM;
156 }
157 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
158 domain |= RADEON_GEM_DOMAIN_GTT;
159 }
160 if (usage & PIPE_BUFFER_USAGE_INDEX) {
161 domain |= RADEON_GEM_DOMAIN_GTT;
162 }
163
164 return domain;
165 }
166
167 struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr,
168 uint32_t handle)
169 {
170 struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
171 struct radeon_libdrm_winsys *rws = mgr->rws;
172 struct radeon_drm_buffer *buf;
173 struct radeon_bo *bo;
174
175 bo = radeon_bo_open(rws->bom, handle, 0,
176 0, 0, 0);
177 if (bo == NULL)
178 return NULL;
179
180 buf = CALLOC_STRUCT(radeon_drm_buffer);
181 if (!buf) {
182 radeon_bo_unref(bo);
183 return NULL;
184 }
185
186 make_empty_list(buf);
187
188 pipe_reference_init(&buf->base.base.reference, 1);
189 buf->base.base.alignment = 0;
190 buf->base.base.usage = PIPE_BUFFER_USAGE_PIXEL;
191 buf->base.base.size = 0;
192 buf->base.vtbl = &radeon_drm_buffer_vtbl;
193 buf->mgr = mgr;
194
195 buf->bo = bo;
196
197 return &buf->base;
198 }
199
200 static struct pb_buffer *
201 radeon_drm_bufmgr_create_buffer(struct pb_manager *_mgr,
202 pb_size size,
203 const struct pb_desc *desc)
204 {
205 struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
206 struct radeon_libdrm_winsys *rws = mgr->rws;
207 struct radeon_drm_buffer *buf;
208 uint32_t domain;
209
210 buf = CALLOC_STRUCT(radeon_drm_buffer);
211 if (!buf)
212 goto error1;
213
214 pipe_reference_init(&buf->base.base.reference, 1);
215 buf->base.base.alignment = desc->alignment;
216 buf->base.base.usage = desc->usage;
217 buf->base.base.size = size;
218 buf->base.vtbl = &radeon_drm_buffer_vtbl;
219 buf->mgr = mgr;
220
221 make_empty_list(buf);
222 domain = radeon_domain_from_usage(desc->usage);
223 buf->bo = radeon_bo_open(rws->bom, 0, size,
224 desc->alignment, domain, 0);
225 if (buf->bo == NULL)
226 goto error2;
227
228 return &buf->base;
229
230 error2:
231 FREE(buf);
232 error1:
233 return NULL;
234 }
235
236 static void
237 radeon_drm_bufmgr_flush(struct pb_manager *mgr)
238 {
239 /* NOP */
240 }
241
242 static void
243 radeon_drm_bufmgr_destroy(struct pb_manager *_mgr)
244 {
245 struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
246 FREE(mgr);
247 }
248
249 struct pb_manager *
250 radeon_drm_bufmgr_create(struct radeon_libdrm_winsys *rws)
251 {
252 struct radeon_drm_bufmgr *mgr;
253
254 mgr = CALLOC_STRUCT(radeon_drm_bufmgr);
255 if (!mgr)
256 return NULL;
257
258 mgr->base.destroy = radeon_drm_bufmgr_destroy;
259 mgr->base.create_buffer = radeon_drm_bufmgr_create_buffer;
260 mgr->base.flush = radeon_drm_bufmgr_flush;
261
262 mgr->rws = rws;
263 make_empty_list(&mgr->buffer_map_list);
264 return &mgr->base;
265 }
266
267 static struct radeon_drm_buffer *get_drm_buffer(struct pb_buffer *_buf)
268 {
269 struct radeon_drm_buffer *buf;
270 if (_buf->vtbl == &radeon_drm_buffer_vtbl) {
271 buf = radeon_drm_buffer(_buf);
272 } else {
273 struct pb_buffer *base_buf;
274 pb_size offset;
275 pb_get_base_buffer(_buf, &base_buf, &offset);
276
277 buf = radeon_drm_buffer(base_buf);
278 }
279 return buf;
280 }
281
282 boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf,
283 struct winsys_handle *whandle)
284 {
285 int retval, fd;
286 struct drm_gem_flink flink;
287 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
288 if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
289 if (!buf->flinked) {
290 fd = buf->mgr->rws->fd;
291 flink.handle = buf->bo->handle;
292
293 retval = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
294 if (retval) {
295 return FALSE;
296 }
297
298 buf->flinked = TRUE;
299 buf->flink = flink.name;
300 }
301 whandle->handle = buf->flink;
302 } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
303 whandle->handle = buf->bo->handle;
304 }
305 return TRUE;
306 }
307
308 void radeon_drm_bufmgr_get_tiling(struct pb_buffer *_buf,
309 enum r300_buffer_tiling *microtiled,
310 enum r300_buffer_tiling *macrotiled)
311 {
312 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
313 uint32_t flags = 0, pitch;
314
315 radeon_bo_get_tiling(buf->bo, &flags, &pitch);
316
317 *microtiled = R300_BUFFER_LINEAR;
318 *macrotiled = R300_BUFFER_LINEAR;
319 if (flags & RADEON_BO_FLAGS_MICRO_TILE)
320 *microtiled = R300_BUFFER_TILED;
321
322 if (flags & RADEON_BO_FLAGS_MACRO_TILE)
323 *macrotiled = R300_BUFFER_TILED;
324 }
325
326 void radeon_drm_bufmgr_set_tiling(struct pb_buffer *_buf,
327 enum r300_buffer_tiling microtiled,
328 enum r300_buffer_tiling macrotiled,
329 uint32_t pitch)
330 {
331 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
332 uint32_t flags = 0, old_flags, old_pitch;
333 if (microtiled == R300_BUFFER_TILED)
334 flags |= RADEON_BO_FLAGS_MICRO_TILE;
335 /* XXX Remove this ifdef when libdrm version 2.4.19 becomes mandatory. */
336 #ifdef RADEON_BO_FLAGS_MICRO_TILE_SQUARE
337 else if (microtiled == R300_BUFFER_SQUARETILED)
338 flags |= RADEON_BO_FLAGS_MICRO_TILE_SQUARE;
339 #endif
340 if (macrotiled == R300_BUFFER_TILED)
341 flags |= RADEON_BO_FLAGS_MACRO_TILE;
342
343 radeon_bo_get_tiling(buf->bo, &old_flags, &old_pitch);
344
345 if (flags != old_flags || pitch != old_pitch) {
346 /* Tiling determines how DRM treats the buffer data.
347 * We must flush CS when changing it if the buffer is referenced. */
348 if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs)) {
349 buf->mgr->rws->flush_cb(buf->mgr->rws->flush_data);
350 }
351 }
352 radeon_bo_set_tiling(buf->bo, flags, pitch);
353
354 }
355
356 boolean radeon_drm_bufmgr_add_buffer(struct pb_buffer *_buf,
357 uint32_t rd, uint32_t wd)
358 {
359 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
360 radeon_cs_space_add_persistent_bo(buf->mgr->rws->cs, buf->bo,
361 rd, wd);
362 return TRUE;
363 }
364
365 void radeon_drm_bufmgr_write_reloc(struct pb_buffer *_buf,
366 uint32_t rd, uint32_t wd,
367 uint32_t flags)
368 {
369 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
370 int retval;
371
372 retval = radeon_cs_write_reloc(buf->mgr->rws->cs,
373 buf->bo, rd, wd, flags);
374 if (retval) {
375 debug_printf("radeon: Relocation of %p (%d, %d, %d) failed!\n",
376 buf, rd, wd, flags);
377 }
378 }
379
380 boolean radeon_drm_bufmgr_is_buffer_referenced(struct pb_buffer *_buf)
381 {
382 struct radeon_drm_buffer *buf = get_drm_buffer(_buf);
383 uint32_t domain;
384
385 return (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs) ||
386 radeon_bo_is_busy(buf->bo, &domain));
387 }
388
389
390 void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr)
391 {
392 struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
393 struct radeon_drm_buffer *rpb, *t_rpb;
394
395 foreach_s(rpb, t_rpb, &mgr->buffer_map_list) {
396 radeon_bo_unmap(rpb->bo);
397 rpb->bo->ptr = NULL;
398 remove_from_list(rpb);
399 }
400
401 make_empty_list(&mgr->buffer_map_list);
402 }