ilo: require hardware logical context support
[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 unsigned long exec_flags;
53
54 /* these are protected by the mutex */
55 pipe_mutex mutex;
56 drm_intel_context *first_gem_ctx;
57 struct drm_intel_decode *decode;
58 };
59
60 static drm_intel_bo *
61 gem_bo(const struct intel_bo *bo)
62 {
63 return (drm_intel_bo *) bo;
64 }
65
66 static bool
67 get_param(struct intel_winsys *winsys, int param, int *value)
68 {
69 struct drm_i915_getparam gp;
70 int err;
71
72 *value = 0;
73
74 memset(&gp, 0, sizeof(gp));
75 gp.param = param;
76 gp.value = value;
77
78 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
79 if (err) {
80 *value = 0;
81 return false;
82 }
83
84 return true;
85 }
86
87 static bool
88 test_address_swizzling(struct intel_winsys *winsys)
89 {
90 drm_intel_bo *bo;
91 uint32_t tiling = I915_TILING_X, swizzle;
92 unsigned long pitch;
93
94 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
95 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
96 if (bo) {
97 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
98 drm_intel_bo_unreference(bo);
99 }
100 else {
101 swizzle = I915_BIT_6_SWIZZLE_NONE;
102 }
103
104 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
105 }
106
107 static bool
108 test_reg_read(struct intel_winsys *winsys, uint32_t reg)
109 {
110 uint64_t dummy;
111
112 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
113 }
114
115 static bool
116 probe_winsys(struct intel_winsys *winsys)
117 {
118 struct intel_winsys_info *info = &winsys->info;
119 int val;
120
121 /*
122 * When we need the Nth vertex from a user vertex buffer, and the vertex is
123 * uploaded to, say, the beginning of a bo, we want the first vertex in the
124 * bo to be fetched. One way to do this is to set the base address of the
125 * vertex buffer to
126 *
127 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
128 *
129 * The second term may be negative, and we need kernel support to do that.
130 *
131 * This check is taken from the classic driver. u_vbuf_upload_buffers()
132 * guarantees the term is never negative, but it is good to require a
133 * recent kernel.
134 */
135 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
136 if (!val) {
137 debug_error("kernel 2.6.39 required");
138 return false;
139 }
140
141 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
142
143 info->max_batch_size = BATCH_SZ;
144
145 get_param(winsys, I915_PARAM_HAS_LLC, &val);
146 info->has_llc = val;
147 info->has_address_swizzling = test_address_swizzling(winsys);
148
149 winsys->first_gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
150 info->has_logical_context = (winsys->first_gem_ctx != NULL);
151
152 /* test TIMESTAMP read */
153 info->has_timestamp = test_reg_read(winsys, 0x2358);
154
155 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
156 info->has_gen7_sol_reset = val;
157
158 /*
159 * pipe drivers are expected to write the presumed offsets after adding
160 * reloc entries
161 */
162 get_param(winsys, I915_PARAM_HAS_EXEC_NO_RELOC, &val);
163 if (val)
164 winsys->exec_flags |= I915_EXEC_NO_RELOC;
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 drm_intel_bufmgr_destroy(winsys->bufmgr);
191 FREE(winsys);
192 return NULL;
193 }
194
195 /*
196 * No need to implicitly set up a fence register for each non-linear reloc
197 * entry. When a fence register is needed for a reloc entry,
198 * drm_intel_bo_emit_reloc_fence() will be called explicitly.
199 *
200 * intel_bo_add_reloc() currently lacks "bool fenced" for this to work.
201 * But we never need a fence register on GEN4+ so we do not need to worry
202 * about it yet.
203 */
204 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
205
206 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
207
208 return winsys;
209 }
210
211 void
212 intel_winsys_destroy(struct intel_winsys *winsys)
213 {
214 if (winsys->decode)
215 drm_intel_decode_context_free(winsys->decode);
216
217 if (winsys->first_gem_ctx)
218 drm_intel_gem_context_destroy(winsys->first_gem_ctx);
219
220 pipe_mutex_destroy(winsys->mutex);
221 drm_intel_bufmgr_destroy(winsys->bufmgr);
222 FREE(winsys);
223 }
224
225 const struct intel_winsys_info *
226 intel_winsys_get_info(const struct intel_winsys *winsys)
227 {
228 return &winsys->info;
229 }
230
231 struct intel_context *
232 intel_winsys_create_context(struct intel_winsys *winsys)
233 {
234 drm_intel_context *gem_ctx;
235
236 /* try the preallocated context first */
237 pipe_mutex_lock(winsys->mutex);
238 gem_ctx = winsys->first_gem_ctx;
239 winsys->first_gem_ctx = NULL;
240 pipe_mutex_unlock(winsys->mutex);
241
242 if (!gem_ctx)
243 gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
244
245 return (struct intel_context *) gem_ctx;
246 }
247
248 void
249 intel_winsys_destroy_context(struct intel_winsys *winsys,
250 struct intel_context *ctx)
251 {
252 drm_intel_gem_context_destroy((drm_intel_context *) ctx);
253 }
254
255 int
256 intel_winsys_read_reg(struct intel_winsys *winsys,
257 uint32_t reg, uint64_t *val)
258 {
259 return drm_intel_reg_read(winsys->bufmgr, reg, val);
260 }
261
262 struct intel_bo *
263 intel_winsys_alloc_buffer(struct intel_winsys *winsys,
264 const char *name,
265 unsigned long size,
266 uint32_t initial_domain)
267 {
268 const bool for_render =
269 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION));
270 const int alignment = 4096; /* always page-aligned */
271 drm_intel_bo *bo;
272
273 if (for_render) {
274 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
275 name, size, alignment);
276 }
277 else {
278 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
279 }
280
281 return (struct intel_bo *) bo;
282 }
283
284 struct intel_bo *
285 intel_winsys_alloc_texture(struct intel_winsys *winsys,
286 const char *name,
287 int width, int height, int cpp,
288 enum intel_tiling_mode tiling,
289 uint32_t initial_domain,
290 unsigned long *pitch)
291 {
292 const unsigned long flags =
293 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION)) ?
294 BO_ALLOC_FOR_RENDER : 0;
295 uint32_t real_tiling = tiling;
296 drm_intel_bo *bo;
297
298 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr, name,
299 width, height, cpp, &real_tiling, pitch, flags);
300 if (!bo)
301 return NULL;
302
303 if (real_tiling != tiling) {
304 assert(!"tiling mismatch");
305 drm_intel_bo_unreference(bo);
306 return NULL;
307 }
308
309 return (struct intel_bo *) bo;
310 }
311
312 struct intel_bo *
313 intel_winsys_import_handle(struct intel_winsys *winsys,
314 const char *name,
315 const struct winsys_handle *handle,
316 int width, int height, int cpp,
317 enum intel_tiling_mode *tiling,
318 unsigned long *pitch)
319 {
320 uint32_t real_tiling, swizzle;
321 drm_intel_bo *bo;
322 int err;
323
324 switch (handle->type) {
325 case DRM_API_HANDLE_TYPE_SHARED:
326 {
327 const uint32_t gem_name = handle->handle;
328 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
329 name, gem_name);
330 }
331 break;
332 case DRM_API_HANDLE_TYPE_FD:
333 {
334 const int fd = (int) handle->handle;
335 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
336 fd, height * handle->stride);
337 }
338 break;
339 default:
340 bo = NULL;
341 break;
342 }
343
344 if (!bo)
345 return NULL;
346
347 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
348 if (err) {
349 drm_intel_bo_unreference(bo);
350 return NULL;
351 }
352
353 *tiling = real_tiling;
354 *pitch = handle->stride;
355
356 return (struct intel_bo *) bo;
357 }
358
359 int
360 intel_winsys_export_handle(struct intel_winsys *winsys,
361 struct intel_bo *bo,
362 enum intel_tiling_mode tiling,
363 unsigned long pitch,
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 =
420 winsys->exec_flags | (unsigned long) ring | flags;
421
422 /* logical contexts are only available for the render ring */
423 if (ring != INTEL_RING_RENDER)
424 ctx = NULL;
425
426 if (ctx) {
427 return drm_intel_gem_bo_context_exec(gem_bo(bo),
428 (drm_intel_context *) ctx, used, exec_flags);
429 }
430 else {
431 return drm_intel_bo_mrb_exec(gem_bo(bo),
432 used, NULL, 0, 0, exec_flags);
433 }
434 }
435
436 void
437 intel_winsys_decode_bo(struct intel_winsys *winsys,
438 struct intel_bo *bo, int used)
439 {
440 void *ptr;
441
442 ptr = intel_bo_map(bo, false);
443 if (!ptr) {
444 debug_printf("failed to map buffer for decoding\n");
445 return;
446 }
447
448 pipe_mutex_lock(winsys->mutex);
449
450 if (!winsys->decode) {
451 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
452 if (!winsys->decode) {
453 pipe_mutex_unlock(winsys->mutex);
454 intel_bo_unmap(bo);
455 return;
456 }
457
458 /* debug_printf()/debug_error() uses stderr by default */
459 drm_intel_decode_set_output_file(winsys->decode, stderr);
460 }
461
462 /* in dwords */
463 used /= 4;
464
465 drm_intel_decode_set_batch_pointer(winsys->decode,
466 ptr, gem_bo(bo)->offset64, used);
467
468 drm_intel_decode(winsys->decode);
469
470 pipe_mutex_unlock(winsys->mutex);
471
472 intel_bo_unmap(bo);
473 }
474
475 void
476 intel_bo_reference(struct intel_bo *bo)
477 {
478 drm_intel_bo_reference(gem_bo(bo));
479 }
480
481 void
482 intel_bo_unreference(struct intel_bo *bo)
483 {
484 drm_intel_bo_unreference(gem_bo(bo));
485 }
486
487 void *
488 intel_bo_map(struct intel_bo *bo, bool write_enable)
489 {
490 int err;
491
492 err = drm_intel_bo_map(gem_bo(bo), write_enable);
493 if (err) {
494 debug_error("failed to map bo");
495 return NULL;
496 }
497
498 return gem_bo(bo)->virtual;
499 }
500
501 void *
502 intel_bo_map_gtt(struct intel_bo *bo)
503 {
504 int err;
505
506 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
507 if (err) {
508 debug_error("failed to map bo");
509 return NULL;
510 }
511
512 return gem_bo(bo)->virtual;
513 }
514
515 void *
516 intel_bo_map_unsynchronized(struct intel_bo *bo)
517 {
518 int err;
519
520 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
521 if (err) {
522 debug_error("failed to map bo");
523 return NULL;
524 }
525
526 return gem_bo(bo)->virtual;
527 }
528
529 void
530 intel_bo_unmap(struct intel_bo *bo)
531 {
532 int err;
533
534 err = drm_intel_bo_unmap(gem_bo(bo));
535 assert(!err);
536 }
537
538 int
539 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
540 unsigned long size, const void *data)
541 {
542 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
543 }
544
545 int
546 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
547 unsigned long size, void *data)
548 {
549 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
550 }
551
552 int
553 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
554 struct intel_bo *target_bo, uint32_t target_offset,
555 uint32_t read_domains, uint32_t write_domain,
556 uint64_t *presumed_offset)
557 {
558 int err;
559
560 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
561 gem_bo(target_bo), target_offset,
562 read_domains, write_domain);
563
564 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
565
566 return err;
567 }
568
569 int
570 intel_bo_get_reloc_count(struct intel_bo *bo)
571 {
572 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
573 }
574
575 void
576 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
577 {
578 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
579 }
580
581 bool
582 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
583 {
584 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
585 }
586
587 int
588 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
589 {
590 int err;
591
592 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
593 /* consider the bo idle on errors */
594 if (err && err != -ETIME)
595 err = 0;
596
597 return err;
598 }