Merge commit '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_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 }