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 "ilo/core/intel_winsys.h"
45 #include "intel_drm_public.h"
46
47 struct intel_winsys {
48 int fd;
49 drm_intel_bufmgr *bufmgr;
50 struct intel_winsys_info info;
51
52 /* these are protected by the mutex */
53 pipe_mutex mutex;
54 drm_intel_context *first_gem_ctx;
55 struct drm_intel_decode *decode;
56 };
57
58 static drm_intel_context *
gem_ctx(const struct intel_context * ctx)59 gem_ctx(const struct intel_context *ctx)
60 {
61 return (drm_intel_context *) ctx;
62 }
63
64 static drm_intel_bo *
gem_bo(const struct intel_bo * bo)65 gem_bo(const struct intel_bo *bo)
66 {
67 return (drm_intel_bo *) bo;
68 }
69
70 static bool
get_param(struct intel_winsys * winsys,int param,int * value)71 get_param(struct intel_winsys *winsys, int param, int *value)
72 {
73 struct drm_i915_getparam gp;
74 int err;
75
76 *value = 0;
77
78 memset(&gp, 0, sizeof(gp));
79 gp.param = param;
80 gp.value = value;
81
82 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
83 if (err) {
84 *value = 0;
85 return false;
86 }
87
88 return true;
89 }
90
91 static bool
test_address_swizzling(struct intel_winsys * winsys)92 test_address_swizzling(struct intel_winsys *winsys)
93 {
94 drm_intel_bo *bo;
95 uint32_t tiling = I915_TILING_X, swizzle;
96 unsigned long pitch;
97
98 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
99 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
100 if (bo) {
101 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
102 drm_intel_bo_unreference(bo);
103 }
104 else {
105 swizzle = I915_BIT_6_SWIZZLE_NONE;
106 }
107
108 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
109 }
110
111 static bool
test_reg_read(struct intel_winsys * winsys,uint32_t reg)112 test_reg_read(struct intel_winsys *winsys, uint32_t reg)
113 {
114 uint64_t dummy;
115
116 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
117 }
118
119 static bool
probe_winsys(struct intel_winsys * winsys)120 probe_winsys(struct intel_winsys *winsys)
121 {
122 struct intel_winsys_info *info = &winsys->info;
123 int val;
124
125 /*
126 * When we need the Nth vertex from a user vertex buffer, and the vertex is
127 * uploaded to, say, the beginning of a bo, we want the first vertex in the
128 * bo to be fetched. One way to do this is to set the base address of the
129 * vertex buffer to
130 *
131 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
132 *
133 * The second term may be negative, and we need kernel support to do that.
134 *
135 * This check is taken from the classic driver. u_vbuf_upload_buffers()
136 * guarantees the term is never negative, but it is good to require a
137 * recent kernel.
138 */
139 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
140 if (!val) {
141 debug_error("kernel 2.6.39 required");
142 return false;
143 }
144
145 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
146
147 if (drm_intel_get_aperture_sizes(winsys->fd,
148 &info->aperture_mappable, &info->aperture_total)) {
149 debug_error("failed to query aperture sizes");
150 return false;
151 }
152
153 get_param(winsys, I915_PARAM_HAS_LLC, &val);
154 info->has_llc = val;
155 info->has_address_swizzling = test_address_swizzling(winsys);
156
157 winsys->first_gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
158 info->has_logical_context = (winsys->first_gem_ctx != NULL);
159
160 get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
161 info->has_ppgtt = val;
162
163 /* test TIMESTAMP read */
164 info->has_timestamp = test_reg_read(winsys, 0x2358);
165
166 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
167 info->has_gen7_sol_reset = val;
168
169 return true;
170 }
171
172 struct intel_winsys *
intel_winsys_create_for_fd(int fd)173 intel_winsys_create_for_fd(int fd)
174 {
175 /* so that we can have enough (up to 4094) relocs per bo */
176 const int batch_size = sizeof(uint32_t) * 8192;
177 struct intel_winsys *winsys;
178
179 winsys = CALLOC_STRUCT(intel_winsys);
180 if (!winsys)
181 return NULL;
182
183 winsys->fd = fd;
184
185 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, batch_size);
186 if (!winsys->bufmgr) {
187 debug_error("failed to create GEM buffer manager");
188 FREE(winsys);
189 return NULL;
190 }
191
192 pipe_mutex_init(winsys->mutex);
193
194 if (!probe_winsys(winsys)) {
195 pipe_mutex_destroy(winsys->mutex);
196 drm_intel_bufmgr_destroy(winsys->bufmgr);
197 FREE(winsys);
198 return NULL;
199 }
200
201 /*
202 * No need to implicitly set up a fence register for each non-linear reloc
203 * entry. INTEL_RELOC_FENCE will be set on reloc entries that need them.
204 */
205 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
206
207 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
208
209 return winsys;
210 }
211
212 void
intel_winsys_destroy(struct intel_winsys * winsys)213 intel_winsys_destroy(struct intel_winsys *winsys)
214 {
215 if (winsys->decode)
216 drm_intel_decode_context_free(winsys->decode);
217
218 if (winsys->first_gem_ctx)
219 drm_intel_gem_context_destroy(winsys->first_gem_ctx);
220
221 pipe_mutex_destroy(winsys->mutex);
222 drm_intel_bufmgr_destroy(winsys->bufmgr);
223 FREE(winsys);
224 }
225
226 const struct intel_winsys_info *
intel_winsys_get_info(const struct intel_winsys * winsys)227 intel_winsys_get_info(const struct intel_winsys *winsys)
228 {
229 return &winsys->info;
230 }
231
232 struct intel_context *
intel_winsys_create_context(struct intel_winsys * winsys)233 intel_winsys_create_context(struct intel_winsys *winsys)
234 {
235 drm_intel_context *gem_ctx;
236
237 /* try the preallocated context first */
238 pipe_mutex_lock(winsys->mutex);
239 gem_ctx = winsys->first_gem_ctx;
240 winsys->first_gem_ctx = NULL;
241 pipe_mutex_unlock(winsys->mutex);
242
243 if (!gem_ctx)
244 gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
245
246 return (struct intel_context *) gem_ctx;
247 }
248
249 void
intel_winsys_destroy_context(struct intel_winsys * winsys,struct intel_context * ctx)250 intel_winsys_destroy_context(struct intel_winsys *winsys,
251 struct intel_context *ctx)
252 {
253 drm_intel_gem_context_destroy(gem_ctx(ctx));
254 }
255
256 int
intel_winsys_read_reg(struct intel_winsys * winsys,uint32_t reg,uint64_t * val)257 intel_winsys_read_reg(struct intel_winsys *winsys,
258 uint32_t reg, uint64_t *val)
259 {
260 return drm_intel_reg_read(winsys->bufmgr, reg, val);
261 }
262
263 int
intel_winsys_get_reset_stats(struct intel_winsys * winsys,struct intel_context * ctx,uint32_t * active_lost,uint32_t * pending_lost)264 intel_winsys_get_reset_stats(struct intel_winsys *winsys,
265 struct intel_context *ctx,
266 uint32_t *active_lost,
267 uint32_t *pending_lost)
268 {
269 uint32_t reset_count;
270
271 return drm_intel_get_reset_stats(gem_ctx(ctx),
272 &reset_count, active_lost, pending_lost);
273 }
274
275 struct intel_bo *
intel_winsys_alloc_bo(struct intel_winsys * winsys,const char * name,unsigned long size,bool cpu_init)276 intel_winsys_alloc_bo(struct intel_winsys *winsys,
277 const char *name,
278 unsigned long size,
279 bool cpu_init)
280 {
281 const unsigned int alignment = 4096; /* always page-aligned */
282 drm_intel_bo *bo;
283
284 if (cpu_init) {
285 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
286 } else {
287 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
288 name, size, alignment);
289 }
290
291 return (struct intel_bo *) bo;
292 }
293
294 struct intel_bo *
intel_winsys_import_userptr(struct intel_winsys * winsys,const char * name,void * userptr,unsigned long size,unsigned long flags)295 intel_winsys_import_userptr(struct intel_winsys *winsys,
296 const char *name,
297 void *userptr,
298 unsigned long size,
299 unsigned long flags)
300 {
301 return NULL;
302 }
303
304 struct intel_bo *
intel_winsys_import_handle(struct intel_winsys * winsys,const char * name,const struct winsys_handle * handle,unsigned long height,enum intel_tiling_mode * tiling,unsigned long * pitch)305 intel_winsys_import_handle(struct intel_winsys *winsys,
306 const char *name,
307 const struct winsys_handle *handle,
308 unsigned long height,
309 enum intel_tiling_mode *tiling,
310 unsigned long *pitch)
311 {
312 uint32_t real_tiling, swizzle;
313 drm_intel_bo *bo;
314 int err;
315
316 if (handle->offset != 0) {
317 debug_error("attempt to import unsupported winsys offset");
318 return NULL;
319 }
320
321 switch (handle->type) {
322 case DRM_API_HANDLE_TYPE_SHARED:
323 {
324 const uint32_t gem_name = handle->handle;
325 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
326 name, gem_name);
327 }
328 break;
329 case DRM_API_HANDLE_TYPE_FD:
330 {
331 const int fd = (int) handle->handle;
332 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
333 fd, height * handle->stride);
334 }
335 break;
336 default:
337 bo = NULL;
338 break;
339 }
340
341 if (!bo)
342 return NULL;
343
344 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
345 if (err) {
346 drm_intel_bo_unreference(bo);
347 return NULL;
348 }
349
350 *tiling = real_tiling;
351 *pitch = handle->stride;
352
353 return (struct intel_bo *) bo;
354 }
355
356 int
intel_winsys_export_handle(struct intel_winsys * winsys,struct intel_bo * bo,enum intel_tiling_mode tiling,unsigned long pitch,unsigned long height,struct winsys_handle * handle)357 intel_winsys_export_handle(struct intel_winsys *winsys,
358 struct intel_bo *bo,
359 enum intel_tiling_mode tiling,
360 unsigned long pitch,
361 unsigned long height,
362 struct winsys_handle *handle)
363 {
364 int err = 0;
365
366 switch (handle->type) {
367 case DRM_API_HANDLE_TYPE_SHARED:
368 {
369 uint32_t name;
370
371 err = drm_intel_bo_flink(gem_bo(bo), &name);
372 if (!err)
373 handle->handle = name;
374 }
375 break;
376 case DRM_API_HANDLE_TYPE_KMS:
377 handle->handle = gem_bo(bo)->handle;
378 break;
379 case DRM_API_HANDLE_TYPE_FD:
380 {
381 int fd;
382
383 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
384 if (!err)
385 handle->handle = fd;
386 }
387 break;
388 default:
389 err = -EINVAL;
390 break;
391 }
392
393 if (err)
394 return err;
395
396 handle->stride = pitch;
397
398 return 0;
399 }
400
401 bool
intel_winsys_can_submit_bo(struct intel_winsys * winsys,struct intel_bo ** bo_array,int count)402 intel_winsys_can_submit_bo(struct intel_winsys *winsys,
403 struct intel_bo **bo_array,
404 int count)
405 {
406 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
407 count);
408 }
409
410 int
intel_winsys_submit_bo(struct intel_winsys * winsys,enum intel_ring_type ring,struct intel_bo * bo,int used,struct intel_context * ctx,unsigned long flags)411 intel_winsys_submit_bo(struct intel_winsys *winsys,
412 enum intel_ring_type ring,
413 struct intel_bo *bo, int used,
414 struct intel_context *ctx,
415 unsigned long flags)
416 {
417 const unsigned long exec_flags = (unsigned long) ring | flags;
418
419 /* logical contexts are only available for the render ring */
420 if (ring != INTEL_RING_RENDER)
421 ctx = NULL;
422
423 if (ctx) {
424 return drm_intel_gem_bo_context_exec(gem_bo(bo),
425 (drm_intel_context *) ctx, used, exec_flags);
426 }
427 else {
428 return drm_intel_bo_mrb_exec(gem_bo(bo),
429 used, NULL, 0, 0, exec_flags);
430 }
431 }
432
433 void
intel_winsys_decode_bo(struct intel_winsys * winsys,struct intel_bo * bo,int used)434 intel_winsys_decode_bo(struct intel_winsys *winsys,
435 struct intel_bo *bo, int used)
436 {
437 void *ptr;
438
439 ptr = intel_bo_map(bo, false);
440 if (!ptr) {
441 debug_printf("failed to map buffer for decoding\n");
442 return;
443 }
444
445 pipe_mutex_lock(winsys->mutex);
446
447 if (!winsys->decode) {
448 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
449 if (!winsys->decode) {
450 pipe_mutex_unlock(winsys->mutex);
451 intel_bo_unmap(bo);
452 return;
453 }
454
455 /* debug_printf()/debug_error() uses stderr by default */
456 drm_intel_decode_set_output_file(winsys->decode, stderr);
457 }
458
459 /* in dwords */
460 used /= 4;
461
462 drm_intel_decode_set_batch_pointer(winsys->decode,
463 ptr, gem_bo(bo)->offset64, used);
464
465 drm_intel_decode(winsys->decode);
466
467 pipe_mutex_unlock(winsys->mutex);
468
469 intel_bo_unmap(bo);
470 }
471
472 struct intel_bo *
intel_bo_ref(struct intel_bo * bo)473 intel_bo_ref(struct intel_bo *bo)
474 {
475 if (bo)
476 drm_intel_bo_reference(gem_bo(bo));
477
478 return bo;
479 }
480
481 void
intel_bo_unref(struct intel_bo * bo)482 intel_bo_unref(struct intel_bo *bo)
483 {
484 if (bo)
485 drm_intel_bo_unreference(gem_bo(bo));
486 }
487
488 int
intel_bo_set_tiling(struct intel_bo * bo,enum intel_tiling_mode tiling,unsigned long pitch)489 intel_bo_set_tiling(struct intel_bo *bo,
490 enum intel_tiling_mode tiling,
491 unsigned long pitch)
492 {
493 uint32_t real_tiling = tiling;
494 int err;
495
496 switch (tiling) {
497 case INTEL_TILING_X:
498 if (pitch % 512)
499 return -1;
500 break;
501 case INTEL_TILING_Y:
502 if (pitch % 128)
503 return -1;
504 break;
505 default:
506 break;
507 }
508
509 err = drm_intel_bo_set_tiling(gem_bo(bo), &real_tiling, pitch);
510 if (err || real_tiling != tiling) {
511 assert(!"tiling mismatch");
512 return -1;
513 }
514
515 return 0;
516 }
517
518 void *
intel_bo_map(struct intel_bo * bo,bool write_enable)519 intel_bo_map(struct intel_bo *bo, bool write_enable)
520 {
521 int err;
522
523 err = drm_intel_bo_map(gem_bo(bo), write_enable);
524 if (err) {
525 debug_error("failed to map bo");
526 return NULL;
527 }
528
529 return gem_bo(bo)->virtual;
530 }
531
532 void *
intel_bo_map_async(struct intel_bo * bo)533 intel_bo_map_async(struct intel_bo *bo)
534 {
535 return NULL;
536 }
537
538 void *
intel_bo_map_gtt(struct intel_bo * bo)539 intel_bo_map_gtt(struct intel_bo *bo)
540 {
541 int err;
542
543 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
544 if (err) {
545 debug_error("failed to map bo");
546 return NULL;
547 }
548
549 return gem_bo(bo)->virtual;
550 }
551
552 void *
intel_bo_map_gtt_async(struct intel_bo * bo)553 intel_bo_map_gtt_async(struct intel_bo *bo)
554 {
555 int err;
556
557 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
558 if (err) {
559 debug_error("failed to map bo");
560 return NULL;
561 }
562
563 return gem_bo(bo)->virtual;
564 }
565
566 void
intel_bo_unmap(struct intel_bo * bo)567 intel_bo_unmap(struct intel_bo *bo)
568 {
569 int err;
570
571 err = drm_intel_bo_unmap(gem_bo(bo));
572 assert(!err);
573 }
574
575 int
intel_bo_pwrite(struct intel_bo * bo,unsigned long offset,unsigned long size,const void * data)576 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
577 unsigned long size, const void *data)
578 {
579 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
580 }
581
582 int
intel_bo_pread(struct intel_bo * bo,unsigned long offset,unsigned long size,void * data)583 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
584 unsigned long size, void *data)
585 {
586 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
587 }
588
589 int
intel_bo_add_reloc(struct intel_bo * bo,uint32_t offset,struct intel_bo * target_bo,uint32_t target_offset,uint32_t flags,uint64_t * presumed_offset)590 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
591 struct intel_bo *target_bo, uint32_t target_offset,
592 uint32_t flags, uint64_t *presumed_offset)
593 {
594 uint32_t read_domains, write_domain;
595 int err;
596
597 if (flags & INTEL_RELOC_WRITE) {
598 /*
599 * Because of the translation to domains, INTEL_RELOC_GGTT should only
600 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
601 * kernel will translate it back to INTEL_RELOC_GGTT.
602 */
603 write_domain = (flags & INTEL_RELOC_GGTT) ?
604 I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
605 read_domains = write_domain;
606 } else {
607 write_domain = 0;
608 read_domains = I915_GEM_DOMAIN_RENDER |
609 I915_GEM_DOMAIN_SAMPLER |
610 I915_GEM_DOMAIN_INSTRUCTION |
611 I915_GEM_DOMAIN_VERTEX;
612 }
613
614 if (flags & INTEL_RELOC_FENCE) {
615 err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
616 gem_bo(target_bo), target_offset,
617 read_domains, write_domain);
618 } else {
619 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
620 gem_bo(target_bo), target_offset,
621 read_domains, write_domain);
622 }
623
624 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
625
626 return err;
627 }
628
629 int
intel_bo_get_reloc_count(struct intel_bo * bo)630 intel_bo_get_reloc_count(struct intel_bo *bo)
631 {
632 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
633 }
634
635 void
intel_bo_truncate_relocs(struct intel_bo * bo,int start)636 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
637 {
638 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
639 }
640
641 bool
intel_bo_has_reloc(struct intel_bo * bo,struct intel_bo * target_bo)642 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
643 {
644 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
645 }
646
647 int
intel_bo_wait(struct intel_bo * bo,int64_t timeout)648 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
649 {
650 int err;
651
652 if (timeout >= 0) {
653 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
654 } else {
655 drm_intel_bo_wait_rendering(gem_bo(bo));
656 err = 0;
657 }
658
659 /* consider the bo idle on errors */
660 if (err && err != -ETIME)
661 err = 0;
662
663 return err;
664 }
665