r300g: typecast void* to unsigned correctly
[mesa.git] / src / gallium / winsys / radeon / drm / radeon_drm_bo.c
1 /*
2 * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 */
26
27 #define _FILE_OFFSET_BITS 64
28 #include "radeon_drm_cs.h"
29
30 #include "util/u_hash_table.h"
31 #include "util/u_memory.h"
32 #include "util/u_simple_list.h"
33 #include "os/os_thread.h"
34
35 #include "state_tracker/drm_driver.h"
36
37 #include <sys/ioctl.h>
38 #include <sys/mman.h>
39 #include <xf86drm.h>
40 #include <errno.h>
41
42 #define RADEON_BO_FLAGS_MACRO_TILE 1
43 #define RADEON_BO_FLAGS_MICRO_TILE 2
44 #define RADEON_BO_FLAGS_MICRO_TILE_SQUARE 0x20
45
46 extern const struct pb_vtbl radeon_bo_vtbl;
47
48
49 static INLINE struct radeon_bo *radeon_bo(struct pb_buffer *bo)
50 {
51 assert(bo->vtbl == &radeon_bo_vtbl);
52 return (struct radeon_bo *)bo;
53 }
54
55 struct radeon_bomgr {
56 /* Base class. */
57 struct pb_manager base;
58
59 /* Winsys. */
60 struct radeon_drm_winsys *rws;
61
62 /* List of buffer handles and its mutex. */
63 struct util_hash_table *bo_handles;
64 pipe_mutex bo_handles_mutex;
65 };
66
67 static INLINE struct radeon_bomgr *radeon_bomgr(struct pb_manager *mgr)
68 {
69 return (struct radeon_bomgr *)mgr;
70 }
71
72 static struct radeon_bo *get_radeon_bo(struct pb_buffer *_buf)
73 {
74 struct radeon_bo *bo = NULL;
75
76 if (_buf->vtbl == &radeon_bo_vtbl) {
77 bo = radeon_bo(_buf);
78 } else {
79 struct pb_buffer *base_buf;
80 pb_size offset;
81 pb_get_base_buffer(_buf, &base_buf, &offset);
82
83 if (base_buf->vtbl == &radeon_bo_vtbl)
84 bo = radeon_bo(base_buf);
85 }
86
87 return bo;
88 }
89
90 void radeon_bo_unref(struct radeon_bo *bo)
91 {
92 struct drm_gem_close args = {};
93
94 if (!p_atomic_dec_zero(&bo->ref_count))
95 return;
96
97 if (bo->name) {
98 pipe_mutex_lock(bo->mgr->bo_handles_mutex);
99 util_hash_table_remove(bo->mgr->bo_handles,
100 (void*)(uintptr_t)bo->name);
101 pipe_mutex_unlock(bo->mgr->bo_handles_mutex);
102 }
103
104 if (bo->ptr)
105 munmap(bo->ptr, bo->size);
106
107 /* Close object. */
108 args.handle = bo->handle;
109 drmIoctl(bo->rws->fd, DRM_IOCTL_GEM_CLOSE, &args);
110 FREE(bo);
111 }
112
113 static void radeon_bo_wait(struct r300_winsys_bo *_buf)
114 {
115 struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
116 struct drm_radeon_gem_wait_idle args = {};
117
118 args.handle = bo->handle;
119 while (drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_WAIT_IDLE,
120 &args, sizeof(args)) == -EBUSY);
121 }
122
123 static boolean radeon_bo_is_busy(struct r300_winsys_bo *_buf)
124 {
125 struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
126 struct drm_radeon_gem_busy args = {};
127
128 args.handle = bo->handle;
129 return drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_BUSY,
130 &args, sizeof(args)) != 0;
131 }
132
133 static void radeon_bo_destroy(struct pb_buffer *_buf)
134 {
135 struct radeon_bo *bo = radeon_bo(_buf);
136
137 radeon_bo_unref(bo);
138 }
139
140 static unsigned get_pb_usage_from_transfer_flags(enum pipe_transfer_usage usage)
141 {
142 unsigned res = 0;
143
144 if (usage & PIPE_TRANSFER_DONTBLOCK)
145 res |= PB_USAGE_DONTBLOCK;
146
147 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
148 res |= PB_USAGE_UNSYNCHRONIZED;
149
150 return res;
151 }
152
153 static void *radeon_bo_map_internal(struct pb_buffer *_buf,
154 unsigned flags, void *flush_ctx)
155 {
156 struct radeon_bo *bo = radeon_bo(_buf);
157 struct radeon_drm_cs *cs = flush_ctx;
158 struct drm_radeon_gem_mmap args = {};
159
160 if (flags & PB_USAGE_DONTBLOCK) {
161 /* Note how we use radeon_bo_is_referenced_by_cs here. There are
162 * basically two places this map function can be called from:
163 * - pb_map
164 * - create_buffer (in the buffer reuse case)
165 *
166 * Since pb managers are per-winsys managers, not per-context managers,
167 * and we shouldn't reuse buffers if they are in-use in any context,
168 * we simply ask: is this buffer referenced by *any* CS?
169 *
170 * The problem with buffer_create is that it comes from pipe_screen,
171 * so we have no CS to look at, though luckily the following code
172 * is sufficient to tell whether the buffer is in use. */
173 if (_buf->base.usage & RADEON_PB_USAGE_CACHE) {
174 if (radeon_bo_is_referenced_by_any_cs(bo))
175 return NULL;
176 }
177
178 if (cs && radeon_bo_is_referenced_by_cs(cs, bo)) {
179 cs->flush_cs(cs->flush_data);
180 return NULL; /* It's very unlikely that the buffer is not busy. */
181 }
182
183 if (radeon_bo_is_busy((struct r300_winsys_bo*)bo)) {
184 return NULL;
185 }
186 }
187
188 /* If it's not unsynchronized bo_map, flush CS if needed and then wait. */
189 if (!(flags & PB_USAGE_UNSYNCHRONIZED)) {
190 if (cs && radeon_bo_is_referenced_by_cs(cs, bo)) {
191 cs->flush_cs(cs->flush_data);
192 }
193
194 radeon_bo_wait((struct r300_winsys_bo*)bo);
195 }
196
197 /* Map buffer if it's not already mapped. */
198 /* XXX We may get a race in bo->ptr. */
199 if (!bo->ptr) {
200 void *ptr;
201
202 args.handle = bo->handle;
203 args.offset = 0;
204 args.size = (uint64_t)bo->size;
205 if (drmCommandWriteRead(bo->rws->fd,
206 DRM_RADEON_GEM_MMAP,
207 &args,
208 sizeof(args))) {
209 fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
210 bo, bo->handle);
211 return NULL;
212 }
213 ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
214 bo->rws->fd, args.addr_ptr);
215 if (ptr == MAP_FAILED) {
216 fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
217 return NULL;
218 }
219 bo->ptr = ptr;
220 }
221
222 return bo->ptr;
223 }
224
225 static void radeon_bo_unmap_internal(struct pb_buffer *_buf)
226 {
227 /* NOP */
228 }
229
230 static void radeon_bo_get_base_buffer(struct pb_buffer *buf,
231 struct pb_buffer **base_buf,
232 unsigned *offset)
233 {
234 *base_buf = buf;
235 *offset = 0;
236 }
237
238 static enum pipe_error radeon_bo_validate(struct pb_buffer *_buf,
239 struct pb_validate *vl,
240 unsigned flags)
241 {
242 /* Always pinned */
243 return PIPE_OK;
244 }
245
246 static void radeon_bo_fence(struct pb_buffer *buf,
247 struct pipe_fence_handle *fence)
248 {
249 }
250
251 const struct pb_vtbl radeon_bo_vtbl = {
252 radeon_bo_destroy,
253 radeon_bo_map_internal,
254 radeon_bo_unmap_internal,
255 radeon_bo_validate,
256 radeon_bo_fence,
257 radeon_bo_get_base_buffer,
258 };
259
260 static struct pb_buffer *radeon_bomgr_create_bo(struct pb_manager *_mgr,
261 pb_size size,
262 const struct pb_desc *desc)
263 {
264 struct radeon_bomgr *mgr = radeon_bomgr(_mgr);
265 struct radeon_drm_winsys *rws = mgr->rws;
266 struct radeon_bo *bo;
267 struct drm_radeon_gem_create args = {};
268
269 args.size = size;
270 args.alignment = desc->alignment;
271 args.initial_domain =
272 (desc->usage & RADEON_PB_USAGE_DOMAIN_GTT ?
273 RADEON_GEM_DOMAIN_GTT : 0) |
274 (desc->usage & RADEON_PB_USAGE_DOMAIN_VRAM ?
275 RADEON_GEM_DOMAIN_VRAM : 0);
276
277 if (drmCommandWriteRead(rws->fd, DRM_RADEON_GEM_CREATE,
278 &args, sizeof(args))) {
279 fprintf(stderr, "Failed to allocate :\n");
280 fprintf(stderr, " size : %d bytes\n", size);
281 fprintf(stderr, " alignment : %d bytes\n", desc->alignment);
282 fprintf(stderr, " domains : %d\n", args.initial_domain);
283 return NULL;
284 }
285
286 bo = CALLOC_STRUCT(radeon_bo);
287 if (!bo)
288 return NULL;
289
290 pipe_reference_init(&bo->base.base.reference, 1);
291 bo->base.base.alignment = desc->alignment;
292 bo->base.base.usage = desc->usage;
293 bo->base.base.size = size;
294 bo->base.vtbl = &radeon_bo_vtbl;
295 bo->mgr = mgr;
296 bo->rws = mgr->rws;
297 bo->handle = args.handle;
298 bo->size = size;
299
300 radeon_bo_ref(bo);
301 return &bo->base;
302 }
303
304 static void radeon_bomgr_flush(struct pb_manager *mgr)
305 {
306 /* NOP */
307 }
308
309 static void radeon_bomgr_destroy(struct pb_manager *_mgr)
310 {
311 struct radeon_bomgr *mgr = radeon_bomgr(_mgr);
312 util_hash_table_destroy(mgr->bo_handles);
313 pipe_mutex_destroy(mgr->bo_handles_mutex);
314 FREE(mgr);
315 }
316
317 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x) & 0xffffffff))
318
319 static unsigned handle_hash(void *key)
320 {
321 return PTR_TO_UINT(key);
322 }
323
324 static int handle_compare(void *key1, void *key2)
325 {
326 return PTR_TO_UINT(key1) == PTR_TO_UINT(key2);
327 }
328
329 struct pb_manager *radeon_bomgr_create(struct radeon_drm_winsys *rws)
330 {
331 struct radeon_bomgr *mgr;
332
333 mgr = CALLOC_STRUCT(radeon_bomgr);
334 if (!mgr)
335 return NULL;
336
337 mgr->base.destroy = radeon_bomgr_destroy;
338 mgr->base.create_buffer = radeon_bomgr_create_bo;
339 mgr->base.flush = radeon_bomgr_flush;
340
341 mgr->rws = rws;
342 mgr->bo_handles = util_hash_table_create(handle_hash, handle_compare);
343 pipe_mutex_init(mgr->bo_handles_mutex);
344 return &mgr->base;
345 }
346
347 static void *radeon_bo_map(struct r300_winsys_bo *buf,
348 struct r300_winsys_cs *cs,
349 enum pipe_transfer_usage usage)
350 {
351 struct pb_buffer *_buf = pb_buffer(buf);
352
353 return pb_map(_buf, get_pb_usage_from_transfer_flags(usage), cs);
354 }
355
356 static void radeon_bo_get_tiling(struct r300_winsys_bo *_buf,
357 enum r300_buffer_tiling *microtiled,
358 enum r300_buffer_tiling *macrotiled)
359 {
360 struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
361 struct drm_radeon_gem_set_tiling args = {};
362
363 args.handle = bo->handle;
364
365 drmCommandWriteRead(bo->rws->fd,
366 DRM_RADEON_GEM_GET_TILING,
367 &args,
368 sizeof(args));
369
370 *microtiled = R300_BUFFER_LINEAR;
371 *macrotiled = R300_BUFFER_LINEAR;
372 if (args.tiling_flags & RADEON_BO_FLAGS_MICRO_TILE)
373 *microtiled = R300_BUFFER_TILED;
374
375 if (args.tiling_flags & RADEON_BO_FLAGS_MACRO_TILE)
376 *macrotiled = R300_BUFFER_TILED;
377 }
378
379 static void radeon_bo_set_tiling(struct r300_winsys_bo *_buf,
380 enum r300_buffer_tiling microtiled,
381 enum r300_buffer_tiling macrotiled,
382 uint32_t pitch)
383 {
384 struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
385 struct drm_radeon_gem_set_tiling args = {};
386
387 if (microtiled == R300_BUFFER_TILED)
388 args.tiling_flags |= RADEON_BO_FLAGS_MICRO_TILE;
389 else if (microtiled == R300_BUFFER_SQUARETILED)
390 args.tiling_flags |= RADEON_BO_FLAGS_MICRO_TILE_SQUARE;
391
392 if (macrotiled == R300_BUFFER_TILED)
393 args.tiling_flags |= RADEON_BO_FLAGS_MACRO_TILE;
394
395 args.handle = bo->handle;
396 args.pitch = pitch;
397
398 drmCommandWriteRead(bo->rws->fd,
399 DRM_RADEON_GEM_SET_TILING,
400 &args,
401 sizeof(args));
402 }
403
404 static struct r300_winsys_cs_handle *radeon_drm_get_cs_handle(
405 struct r300_winsys_bo *_buf)
406 {
407 /* return radeon_bo. */
408 return (struct r300_winsys_cs_handle*)
409 get_radeon_bo(pb_buffer(_buf));
410 }
411
412 static unsigned get_pb_usage_from_create_flags(unsigned bind, unsigned usage,
413 enum r300_buffer_domain domain)
414 {
415 unsigned res = 0;
416
417 if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
418 res |= RADEON_PB_USAGE_CACHE;
419
420 if (domain & R300_DOMAIN_GTT)
421 res |= RADEON_PB_USAGE_DOMAIN_GTT;
422
423 if (domain & R300_DOMAIN_VRAM)
424 res |= RADEON_PB_USAGE_DOMAIN_VRAM;
425
426 return res;
427 }
428
429 static struct r300_winsys_bo *
430 radeon_winsys_bo_create(struct r300_winsys_screen *rws,
431 unsigned size,
432 unsigned alignment,
433 unsigned bind,
434 unsigned usage,
435 enum r300_buffer_domain domain)
436 {
437 struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
438 struct pb_desc desc;
439 struct pb_manager *provider;
440 struct pb_buffer *buffer;
441
442 memset(&desc, 0, sizeof(desc));
443 desc.alignment = alignment;
444 desc.usage = get_pb_usage_from_create_flags(bind, usage, domain);
445
446 /* Assign a buffer manager. */
447 if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
448 provider = ws->cman;
449 else
450 provider = ws->kman;
451
452 buffer = provider->create_buffer(provider, size, &desc);
453 if (!buffer)
454 return NULL;
455
456 return (struct r300_winsys_bo*)buffer;
457 }
458
459 static struct r300_winsys_bo *radeon_winsys_bo_from_handle(struct r300_winsys_screen *rws,
460 struct winsys_handle *whandle,
461 unsigned *stride,
462 unsigned *size)
463 {
464 struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
465 struct radeon_bo *bo;
466 struct radeon_bomgr *mgr = radeon_bomgr(ws->kman);
467 struct drm_gem_open open_arg = {};
468
469 /* We must maintain a list of pairs <handle, bo>, so that we always return
470 * the same BO for one particular handle. If we didn't do that and created
471 * more than one BO for the same handle and then relocated them in a CS,
472 * we would hit a deadlock in the kernel.
473 *
474 * The list of pairs is guarded by a mutex, of course. */
475 pipe_mutex_lock(mgr->bo_handles_mutex);
476
477 /* First check if there already is an existing bo for the handle. */
478 bo = util_hash_table_get(mgr->bo_handles, (void*)(uintptr_t)whandle->handle);
479 if (bo) {
480 /* Increase the refcount. */
481 struct pb_buffer *b = NULL;
482 pb_reference(&b, &bo->base);
483 goto done;
484 }
485
486 /* There isn't, create a new one. */
487 bo = CALLOC_STRUCT(radeon_bo);
488 if (!bo) {
489 goto fail;
490 }
491
492 /* Open the BO. */
493 open_arg.name = whandle->handle;
494 if (drmIoctl(ws->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) {
495 FREE(bo);
496 goto fail;
497 }
498 bo->handle = open_arg.handle;
499 bo->size = open_arg.size;
500 bo->name = whandle->handle;
501 radeon_bo_ref(bo);
502
503 /* Initialize it. */
504 pipe_reference_init(&bo->base.base.reference, 1);
505 bo->base.base.alignment = 0;
506 bo->base.base.usage = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
507 bo->base.base.size = bo->size;
508 bo->base.vtbl = &radeon_bo_vtbl;
509 bo->mgr = mgr;
510 bo->rws = mgr->rws;
511
512 util_hash_table_set(mgr->bo_handles, (void*)(uintptr_t)whandle->handle, bo);
513
514 done:
515 pipe_mutex_unlock(mgr->bo_handles_mutex);
516
517 if (stride)
518 *stride = whandle->stride;
519 if (size)
520 *size = bo->base.base.size;
521
522 return (struct r300_winsys_bo*)bo;
523
524 fail:
525 pipe_mutex_unlock(mgr->bo_handles_mutex);
526 return NULL;
527 }
528
529 static boolean radeon_winsys_bo_get_handle(struct r300_winsys_bo *buffer,
530 unsigned stride,
531 struct winsys_handle *whandle)
532 {
533 struct drm_gem_flink flink = {};
534 struct radeon_bo *bo = get_radeon_bo(pb_buffer(buffer));
535
536 if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
537 if (!bo->flinked) {
538 flink.handle = bo->handle;
539
540 if (ioctl(bo->rws->fd, DRM_IOCTL_GEM_FLINK, &flink)) {
541 return FALSE;
542 }
543
544 bo->flinked = TRUE;
545 bo->flink = flink.name;
546 }
547 whandle->handle = bo->flink;
548 } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
549 whandle->handle = bo->handle;
550 }
551
552 whandle->stride = stride;
553 return TRUE;
554 }
555
556 void radeon_bomgr_init_functions(struct radeon_drm_winsys *ws)
557 {
558 ws->base.buffer_get_cs_handle = radeon_drm_get_cs_handle;
559 ws->base.buffer_set_tiling = radeon_bo_set_tiling;
560 ws->base.buffer_get_tiling = radeon_bo_get_tiling;
561 ws->base.buffer_map = radeon_bo_map;
562 ws->base.buffer_unmap = pb_unmap;
563 ws->base.buffer_wait = radeon_bo_wait;
564 ws->base.buffer_is_busy = radeon_bo_is_busy;
565 ws->base.buffer_create = radeon_winsys_bo_create;
566 ws->base.buffer_from_handle = radeon_winsys_bo_from_handle;
567 ws->base.buffer_get_handle = radeon_winsys_bo_get_handle;
568 }