ilo: replace domains by reloc flags
[mesa.git] / src / gallium / winsys / intel / drm / intel_drm_winsys.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include <string.h>
29 #include <errno.h>
30 #ifndef ETIME
31 #define ETIME ETIMEDOUT
32 #endif
33
34 #include <xf86drm.h>
35 #include <i915_drm.h>
36 #include <intel_bufmgr.h>
37
38 #include "os/os_thread.h"
39 #include "state_tracker/drm_driver.h"
40 #include "pipe/p_state.h"
41 #include "util/u_inlines.h"
42 #include "util/u_memory.h"
43 #include "util/u_debug.h"
44 #include "../intel_winsys.h"
45
46 #define BATCH_SZ (8192 * sizeof(uint32_t))
47
48 struct intel_winsys {
49 int fd;
50 drm_intel_bufmgr *bufmgr;
51 struct intel_winsys_info info;
52
53 /* these are protected by the mutex */
54 pipe_mutex mutex;
55 drm_intel_context *first_gem_ctx;
56 struct drm_intel_decode *decode;
57 };
58
59 static drm_intel_bo *
60 gem_bo(const struct intel_bo *bo)
61 {
62 return (drm_intel_bo *) bo;
63 }
64
65 static bool
66 get_param(struct intel_winsys *winsys, int param, int *value)
67 {
68 struct drm_i915_getparam gp;
69 int err;
70
71 *value = 0;
72
73 memset(&gp, 0, sizeof(gp));
74 gp.param = param;
75 gp.value = value;
76
77 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
78 if (err) {
79 *value = 0;
80 return false;
81 }
82
83 return true;
84 }
85
86 static bool
87 test_address_swizzling(struct intel_winsys *winsys)
88 {
89 drm_intel_bo *bo;
90 uint32_t tiling = I915_TILING_X, swizzle;
91 unsigned long pitch;
92
93 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
94 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
95 if (bo) {
96 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
97 drm_intel_bo_unreference(bo);
98 }
99 else {
100 swizzle = I915_BIT_6_SWIZZLE_NONE;
101 }
102
103 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
104 }
105
106 static bool
107 test_reg_read(struct intel_winsys *winsys, uint32_t reg)
108 {
109 uint64_t dummy;
110
111 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
112 }
113
114 static bool
115 probe_winsys(struct intel_winsys *winsys)
116 {
117 struct intel_winsys_info *info = &winsys->info;
118 int val;
119
120 /*
121 * When we need the Nth vertex from a user vertex buffer, and the vertex is
122 * uploaded to, say, the beginning of a bo, we want the first vertex in the
123 * bo to be fetched. One way to do this is to set the base address of the
124 * vertex buffer to
125 *
126 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
127 *
128 * The second term may be negative, and we need kernel support to do that.
129 *
130 * This check is taken from the classic driver. u_vbuf_upload_buffers()
131 * guarantees the term is never negative, but it is good to require a
132 * recent kernel.
133 */
134 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
135 if (!val) {
136 debug_error("kernel 2.6.39 required");
137 return false;
138 }
139
140 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
141
142 if (drm_intel_get_aperture_sizes(winsys->fd,
143 &info->aperture_mappable, &info->aperture_total)) {
144 debug_error("failed to query aperture sizes");
145 return false;
146 }
147
148 info->max_batch_size = BATCH_SZ;
149
150 get_param(winsys, I915_PARAM_HAS_LLC, &val);
151 info->has_llc = val;
152 info->has_address_swizzling = test_address_swizzling(winsys);
153
154 winsys->first_gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
155 info->has_logical_context = (winsys->first_gem_ctx != NULL);
156
157 get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
158 info->has_ppgtt = val;
159
160 /* test TIMESTAMP read */
161 info->has_timestamp = test_reg_read(winsys, 0x2358);
162
163 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
164 info->has_gen7_sol_reset = val;
165
166 return true;
167 }
168
169 struct intel_winsys *
170 intel_winsys_create_for_fd(int fd)
171 {
172 struct intel_winsys *winsys;
173
174 winsys = CALLOC_STRUCT(intel_winsys);
175 if (!winsys)
176 return NULL;
177
178 winsys->fd = fd;
179
180 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, BATCH_SZ);
181 if (!winsys->bufmgr) {
182 debug_error("failed to create GEM buffer manager");
183 FREE(winsys);
184 return NULL;
185 }
186
187 pipe_mutex_init(winsys->mutex);
188
189 if (!probe_winsys(winsys)) {
190 pipe_mutex_destroy(winsys->mutex);
191 drm_intel_bufmgr_destroy(winsys->bufmgr);
192 FREE(winsys);
193 return NULL;
194 }
195
196 /*
197 * No need to implicitly set up a fence register for each non-linear reloc
198 * entry. INTEL_RELOC_FENCE will be set on reloc entries that need them.
199 */
200 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
201
202 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
203
204 return winsys;
205 }
206
207 void
208 intel_winsys_destroy(struct intel_winsys *winsys)
209 {
210 if (winsys->decode)
211 drm_intel_decode_context_free(winsys->decode);
212
213 if (winsys->first_gem_ctx)
214 drm_intel_gem_context_destroy(winsys->first_gem_ctx);
215
216 pipe_mutex_destroy(winsys->mutex);
217 drm_intel_bufmgr_destroy(winsys->bufmgr);
218 FREE(winsys);
219 }
220
221 const struct intel_winsys_info *
222 intel_winsys_get_info(const struct intel_winsys *winsys)
223 {
224 return &winsys->info;
225 }
226
227 struct intel_context *
228 intel_winsys_create_context(struct intel_winsys *winsys)
229 {
230 drm_intel_context *gem_ctx;
231
232 /* try the preallocated context first */
233 pipe_mutex_lock(winsys->mutex);
234 gem_ctx = winsys->first_gem_ctx;
235 winsys->first_gem_ctx = NULL;
236 pipe_mutex_unlock(winsys->mutex);
237
238 if (!gem_ctx)
239 gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
240
241 return (struct intel_context *) gem_ctx;
242 }
243
244 void
245 intel_winsys_destroy_context(struct intel_winsys *winsys,
246 struct intel_context *ctx)
247 {
248 drm_intel_gem_context_destroy((drm_intel_context *) ctx);
249 }
250
251 int
252 intel_winsys_read_reg(struct intel_winsys *winsys,
253 uint32_t reg, uint64_t *val)
254 {
255 return drm_intel_reg_read(winsys->bufmgr, reg, val);
256 }
257
258 struct intel_bo *
259 intel_winsys_alloc_bo(struct intel_winsys *winsys,
260 const char *name,
261 enum intel_tiling_mode tiling,
262 unsigned long pitch,
263 unsigned long height,
264 bool cpu_init)
265 {
266 const unsigned int alignment = 4096; /* always page-aligned */
267 unsigned long size;
268 drm_intel_bo *bo;
269
270 switch (tiling) {
271 case INTEL_TILING_X:
272 if (pitch % 512)
273 return NULL;
274 break;
275 case INTEL_TILING_Y:
276 if (pitch % 128)
277 return NULL;
278 break;
279 default:
280 break;
281 }
282
283 if (pitch > ULONG_MAX / height)
284 return NULL;
285
286 size = pitch * height;
287
288 if (cpu_init) {
289 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
290 }
291 else {
292 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
293 name, size, alignment);
294 }
295
296 if (bo && tiling != INTEL_TILING_NONE) {
297 uint32_t real_tiling = tiling;
298 int err;
299
300 err = drm_intel_bo_set_tiling(bo, &real_tiling, pitch);
301 if (err || real_tiling != tiling) {
302 assert(!"tiling mismatch");
303 drm_intel_bo_unreference(bo);
304 return NULL;
305 }
306 }
307
308 return (struct intel_bo *) bo;
309 }
310
311 struct intel_bo *
312 intel_winsys_import_handle(struct intel_winsys *winsys,
313 const char *name,
314 const struct winsys_handle *handle,
315 unsigned long height,
316 enum intel_tiling_mode *tiling,
317 unsigned long *pitch)
318 {
319 uint32_t real_tiling, swizzle;
320 drm_intel_bo *bo;
321 int err;
322
323 switch (handle->type) {
324 case DRM_API_HANDLE_TYPE_SHARED:
325 {
326 const uint32_t gem_name = handle->handle;
327 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
328 name, gem_name);
329 }
330 break;
331 case DRM_API_HANDLE_TYPE_FD:
332 {
333 const int fd = (int) handle->handle;
334 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
335 fd, height * handle->stride);
336 }
337 break;
338 default:
339 bo = NULL;
340 break;
341 }
342
343 if (!bo)
344 return NULL;
345
346 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
347 if (err) {
348 drm_intel_bo_unreference(bo);
349 return NULL;
350 }
351
352 *tiling = real_tiling;
353 *pitch = handle->stride;
354
355 return (struct intel_bo *) bo;
356 }
357
358 int
359 intel_winsys_export_handle(struct intel_winsys *winsys,
360 struct intel_bo *bo,
361 enum intel_tiling_mode tiling,
362 unsigned long pitch,
363 unsigned long height,
364 struct winsys_handle *handle)
365 {
366 int err = 0;
367
368 switch (handle->type) {
369 case DRM_API_HANDLE_TYPE_SHARED:
370 {
371 uint32_t name;
372
373 err = drm_intel_bo_flink(gem_bo(bo), &name);
374 if (!err)
375 handle->handle = name;
376 }
377 break;
378 case DRM_API_HANDLE_TYPE_KMS:
379 handle->handle = gem_bo(bo)->handle;
380 break;
381 case DRM_API_HANDLE_TYPE_FD:
382 {
383 int fd;
384
385 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
386 if (!err)
387 handle->handle = fd;
388 }
389 break;
390 default:
391 err = -EINVAL;
392 break;
393 }
394
395 if (err)
396 return err;
397
398 handle->stride = pitch;
399
400 return 0;
401 }
402
403 bool
404 intel_winsys_can_submit_bo(struct intel_winsys *winsys,
405 struct intel_bo **bo_array,
406 int count)
407 {
408 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
409 count);
410 }
411
412 int
413 intel_winsys_submit_bo(struct intel_winsys *winsys,
414 enum intel_ring_type ring,
415 struct intel_bo *bo, int used,
416 struct intel_context *ctx,
417 unsigned long flags)
418 {
419 const unsigned long exec_flags = (unsigned long) ring | flags;
420
421 /* logical contexts are only available for the render ring */
422 if (ring != INTEL_RING_RENDER)
423 ctx = NULL;
424
425 if (ctx) {
426 return drm_intel_gem_bo_context_exec(gem_bo(bo),
427 (drm_intel_context *) ctx, used, exec_flags);
428 }
429 else {
430 return drm_intel_bo_mrb_exec(gem_bo(bo),
431 used, NULL, 0, 0, exec_flags);
432 }
433 }
434
435 void
436 intel_winsys_decode_bo(struct intel_winsys *winsys,
437 struct intel_bo *bo, int used)
438 {
439 void *ptr;
440
441 ptr = intel_bo_map(bo, false);
442 if (!ptr) {
443 debug_printf("failed to map buffer for decoding\n");
444 return;
445 }
446
447 pipe_mutex_lock(winsys->mutex);
448
449 if (!winsys->decode) {
450 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
451 if (!winsys->decode) {
452 pipe_mutex_unlock(winsys->mutex);
453 intel_bo_unmap(bo);
454 return;
455 }
456
457 /* debug_printf()/debug_error() uses stderr by default */
458 drm_intel_decode_set_output_file(winsys->decode, stderr);
459 }
460
461 /* in dwords */
462 used /= 4;
463
464 drm_intel_decode_set_batch_pointer(winsys->decode,
465 ptr, gem_bo(bo)->offset64, used);
466
467 drm_intel_decode(winsys->decode);
468
469 pipe_mutex_unlock(winsys->mutex);
470
471 intel_bo_unmap(bo);
472 }
473
474 void
475 intel_bo_reference(struct intel_bo *bo)
476 {
477 drm_intel_bo_reference(gem_bo(bo));
478 }
479
480 void
481 intel_bo_unreference(struct intel_bo *bo)
482 {
483 drm_intel_bo_unreference(gem_bo(bo));
484 }
485
486 void *
487 intel_bo_map(struct intel_bo *bo, bool write_enable)
488 {
489 int err;
490
491 err = drm_intel_bo_map(gem_bo(bo), write_enable);
492 if (err) {
493 debug_error("failed to map bo");
494 return NULL;
495 }
496
497 return gem_bo(bo)->virtual;
498 }
499
500 void *
501 intel_bo_map_gtt(struct intel_bo *bo)
502 {
503 int err;
504
505 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
506 if (err) {
507 debug_error("failed to map bo");
508 return NULL;
509 }
510
511 return gem_bo(bo)->virtual;
512 }
513
514 void *
515 intel_bo_map_unsynchronized(struct intel_bo *bo)
516 {
517 int err;
518
519 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
520 if (err) {
521 debug_error("failed to map bo");
522 return NULL;
523 }
524
525 return gem_bo(bo)->virtual;
526 }
527
528 void
529 intel_bo_unmap(struct intel_bo *bo)
530 {
531 int err;
532
533 err = drm_intel_bo_unmap(gem_bo(bo));
534 assert(!err);
535 }
536
537 int
538 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
539 unsigned long size, const void *data)
540 {
541 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
542 }
543
544 int
545 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
546 unsigned long size, void *data)
547 {
548 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
549 }
550
551 int
552 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
553 struct intel_bo *target_bo, uint32_t target_offset,
554 uint32_t flags, uint64_t *presumed_offset)
555 {
556 uint32_t read_domains, write_domain;
557 int err;
558
559 if (flags & INTEL_RELOC_WRITE) {
560 /*
561 * Because of the translation to domains, INTEL_RELOC_GGTT should only
562 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
563 * kernel will translate it back to INTEL_RELOC_GGTT.
564 */
565 write_domain = (flags & INTEL_RELOC_GGTT) ?
566 I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
567 read_domains = write_domain;
568 } else {
569 write_domain = 0;
570 read_domains = I915_GEM_DOMAIN_RENDER |
571 I915_GEM_DOMAIN_SAMPLER |
572 I915_GEM_DOMAIN_INSTRUCTION |
573 I915_GEM_DOMAIN_VERTEX;
574 }
575
576 if (flags & INTEL_RELOC_FENCE) {
577 err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
578 gem_bo(target_bo), target_offset,
579 read_domains, write_domain);
580 } else {
581 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
582 gem_bo(target_bo), target_offset,
583 read_domains, write_domain);
584 }
585
586 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
587
588 return err;
589 }
590
591 int
592 intel_bo_get_reloc_count(struct intel_bo *bo)
593 {
594 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
595 }
596
597 void
598 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
599 {
600 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
601 }
602
603 bool
604 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
605 {
606 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
607 }
608
609 int
610 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
611 {
612 int err;
613
614 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
615 /* consider the bo idle on errors */
616 if (err && err != -ETIME)
617 err = 0;
618
619 return err;
620 }