blob: ba022b96652e767bf9c3f8a6f53209a3aeeb190b [file] [log] [blame]
Chia-I Wu6464ff22014-08-05 11:59:54 +08001/*
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>
Chia-I Wu770b3092014-08-05 14:22:03 +080029#include <limits.h>
Chia-I Wu6464ff22014-08-05 11:59:54 +080030#include <errno.h>
31#ifndef ETIME
32#define ETIME ETIMEDOUT
33#endif
Chia-I Wu770b3092014-08-05 14:22:03 +080034#include <assert.h>
Chia-I Wu6464ff22014-08-05 11:59:54 +080035
36#include <xf86drm.h>
37#include <i915_drm.h>
38#include <intel_bufmgr.h>
39
Chia-I Wu770b3092014-08-05 14:22:03 +080040#include "icd.h"
41#include "winsys.h"
Chia-I Wu6464ff22014-08-05 11:59:54 +080042
Chia-I Wu6464ff22014-08-05 11:59:54 +080043struct intel_winsys {
44 int fd;
45 drm_intel_bufmgr *bufmgr;
46 struct intel_winsys_info info;
47
Chia-I Wu770b3092014-08-05 14:22:03 +080048 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +080049};
50
51static drm_intel_bo *
52gem_bo(const struct intel_bo *bo)
53{
54 return (drm_intel_bo *) bo;
55}
56
57static bool
58get_param(struct intel_winsys *winsys, int param, int *value)
59{
60 struct drm_i915_getparam gp;
61 int err;
62
63 *value = 0;
64
65 memset(&gp, 0, sizeof(gp));
66 gp.param = param;
67 gp.value = value;
68
69 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
70 if (err) {
71 *value = 0;
72 return false;
73 }
74
75 return true;
76}
77
78static bool
79test_address_swizzling(struct intel_winsys *winsys)
80{
81 drm_intel_bo *bo;
82 uint32_t tiling = I915_TILING_X, swizzle;
83 unsigned long pitch;
84
85 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
86 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
87 if (bo) {
88 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
89 drm_intel_bo_unreference(bo);
90 }
91 else {
92 swizzle = I915_BIT_6_SWIZZLE_NONE;
93 }
94
95 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
96}
97
98static bool
99test_reg_read(struct intel_winsys *winsys, uint32_t reg)
100{
101 uint64_t dummy;
102
103 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
104}
105
106static bool
107probe_winsys(struct intel_winsys *winsys)
108{
109 struct intel_winsys_info *info = &winsys->info;
110 int val;
111
112 /*
113 * When we need the Nth vertex from a user vertex buffer, and the vertex is
114 * uploaded to, say, the beginning of a bo, we want the first vertex in the
115 * bo to be fetched. One way to do this is to set the base address of the
116 * vertex buffer to
117 *
118 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
119 *
120 * The second term may be negative, and we need kernel support to do that.
121 *
122 * This check is taken from the classic driver. u_vbuf_upload_buffers()
123 * guarantees the term is never negative, but it is good to require a
124 * recent kernel.
125 */
126 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
127 if (!val) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800128 return false;
129 }
130
131 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
132
Chia-I Wu6464ff22014-08-05 11:59:54 +0800133 get_param(winsys, I915_PARAM_HAS_LLC, &val);
134 info->has_llc = val;
135 info->has_address_swizzling = test_address_swizzling(winsys);
136
Chia-I Wu770b3092014-08-05 14:22:03 +0800137 winsys->ctx = drm_intel_gem_context_create(winsys->bufmgr);
138 if (!winsys->ctx)
139 return false;
140
141 info->has_logical_context = (winsys->ctx != NULL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800142
143 get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
144 info->has_ppgtt = val;
145
146 /* test TIMESTAMP read */
147 info->has_timestamp = test_reg_read(winsys, 0x2358);
148
149 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
150 info->has_gen7_sol_reset = val;
151
152 return true;
153}
154
155struct intel_winsys *
156intel_winsys_create_for_fd(int fd)
157{
Chia-I Wu32a22462014-08-26 14:13:46 +0800158 /* so that we can have enough (up to 4094) relocs per bo */
159 const int batch_size = sizeof(uint32_t) * 8192;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800160 struct intel_winsys *winsys;
161
Chia-I Wu770b3092014-08-05 14:22:03 +0800162 winsys = icd_alloc(sizeof(*winsys), 0, XGL_SYSTEM_ALLOC_INTERNAL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800163 if (!winsys)
164 return NULL;
165
Chia-I Wu770b3092014-08-05 14:22:03 +0800166 memset(winsys, 0, sizeof(*winsys));
167
Chia-I Wu6464ff22014-08-05 11:59:54 +0800168 winsys->fd = fd;
169
Chia-I Wu32a22462014-08-26 14:13:46 +0800170 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, batch_size);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800171 if (!winsys->bufmgr) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800172 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800173 return NULL;
174 }
175
Chia-I Wu6464ff22014-08-05 11:59:54 +0800176 if (!probe_winsys(winsys)) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800177 drm_intel_bufmgr_destroy(winsys->bufmgr);
Chia-I Wu770b3092014-08-05 14:22:03 +0800178 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800179 return NULL;
180 }
181
182 /*
183 * No need to implicitly set up a fence register for each non-linear reloc
Chia-I Wu32a22462014-08-26 14:13:46 +0800184 * entry. INTEL_RELOC_FENCE will be set on reloc entries that need them.
Chia-I Wu6464ff22014-08-05 11:59:54 +0800185 */
186 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
187
188 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
189
190 return winsys;
191}
192
193void
194intel_winsys_destroy(struct intel_winsys *winsys)
195{
Chia-I Wu770b3092014-08-05 14:22:03 +0800196 drm_intel_gem_context_destroy(winsys->ctx);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800197 drm_intel_bufmgr_destroy(winsys->bufmgr);
Chia-I Wu770b3092014-08-05 14:22:03 +0800198 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800199}
200
201const struct intel_winsys_info *
202intel_winsys_get_info(const struct intel_winsys *winsys)
203{
204 return &winsys->info;
205}
206
Chia-I Wu6464ff22014-08-05 11:59:54 +0800207int
208intel_winsys_read_reg(struct intel_winsys *winsys,
209 uint32_t reg, uint64_t *val)
210{
211 return drm_intel_reg_read(winsys->bufmgr, reg, val);
212}
213
214struct intel_bo *
215intel_winsys_alloc_bo(struct intel_winsys *winsys,
216 const char *name,
217 enum intel_tiling_mode tiling,
218 unsigned long pitch,
219 unsigned long height,
Chia-I Wu32a22462014-08-26 14:13:46 +0800220 bool cpu_init)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800221{
Chia-I Wu6464ff22014-08-05 11:59:54 +0800222 const unsigned int alignment = 4096; /* always page-aligned */
223 unsigned long size;
224 drm_intel_bo *bo;
225
226 switch (tiling) {
227 case INTEL_TILING_X:
228 if (pitch % 512)
229 return NULL;
230 break;
231 case INTEL_TILING_Y:
232 if (pitch % 128)
233 return NULL;
234 break;
235 default:
236 break;
237 }
238
239 if (pitch > ULONG_MAX / height)
240 return NULL;
241
242 size = pitch * height;
243
Chia-I Wu32a22462014-08-26 14:13:46 +0800244 if (cpu_init) {
245 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800246 }
247 else {
Chia-I Wu32a22462014-08-26 14:13:46 +0800248 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
249 name, size, alignment);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800250 }
251
252 if (bo && tiling != INTEL_TILING_NONE) {
253 uint32_t real_tiling = tiling;
254 int err;
255
256 err = drm_intel_bo_set_tiling(bo, &real_tiling, pitch);
257 if (err || real_tiling != tiling) {
258 assert(!"tiling mismatch");
259 drm_intel_bo_unreference(bo);
260 return NULL;
261 }
262 }
263
264 return (struct intel_bo *) bo;
265}
266
267struct intel_bo *
268intel_winsys_import_handle(struct intel_winsys *winsys,
269 const char *name,
Chia-I Wu770b3092014-08-05 14:22:03 +0800270 const struct intel_winsys_handle *handle,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800271 unsigned long height,
272 enum intel_tiling_mode *tiling,
273 unsigned long *pitch)
274{
275 uint32_t real_tiling, swizzle;
276 drm_intel_bo *bo;
277 int err;
278
279 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800280 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800281 {
282 const uint32_t gem_name = handle->handle;
283 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
284 name, gem_name);
285 }
286 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800287 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800288 {
289 const int fd = (int) handle->handle;
290 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
291 fd, height * handle->stride);
292 }
293 break;
294 default:
295 bo = NULL;
296 break;
297 }
298
299 if (!bo)
300 return NULL;
301
302 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
303 if (err) {
304 drm_intel_bo_unreference(bo);
305 return NULL;
306 }
307
308 *tiling = real_tiling;
309 *pitch = handle->stride;
310
311 return (struct intel_bo *) bo;
312}
313
314int
315intel_winsys_export_handle(struct intel_winsys *winsys,
316 struct intel_bo *bo,
317 enum intel_tiling_mode tiling,
318 unsigned long pitch,
319 unsigned long height,
Chia-I Wu770b3092014-08-05 14:22:03 +0800320 struct intel_winsys_handle *handle)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800321{
322 int err = 0;
323
324 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800325 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800326 {
327 uint32_t name;
328
329 err = drm_intel_bo_flink(gem_bo(bo), &name);
330 if (!err)
331 handle->handle = name;
332 }
333 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800334 case INTEL_WINSYS_HANDLE_KMS:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800335 handle->handle = gem_bo(bo)->handle;
336 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800337 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800338 {
339 int fd;
340
341 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
342 if (!err)
343 handle->handle = fd;
344 }
345 break;
346 default:
347 err = -EINVAL;
348 break;
349 }
350
351 if (err)
352 return err;
353
354 handle->stride = pitch;
355
356 return 0;
357}
358
359bool
360intel_winsys_can_submit_bo(struct intel_winsys *winsys,
361 struct intel_bo **bo_array,
362 int count)
363{
364 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
365 count);
366}
367
368int
369intel_winsys_submit_bo(struct intel_winsys *winsys,
370 enum intel_ring_type ring,
371 struct intel_bo *bo, int used,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800372 unsigned long flags)
373{
374 const unsigned long exec_flags = (unsigned long) ring | flags;
Chia-I Wu770b3092014-08-05 14:22:03 +0800375 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800376
377 /* logical contexts are only available for the render ring */
Chia-I Wu770b3092014-08-05 14:22:03 +0800378 ctx = (ring == INTEL_RING_RENDER) ? winsys->ctx : NULL;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800379
380 if (ctx) {
381 return drm_intel_gem_bo_context_exec(gem_bo(bo),
Chia-I Wu770b3092014-08-05 14:22:03 +0800382 ctx, used, exec_flags);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800383 }
384 else {
385 return drm_intel_bo_mrb_exec(gem_bo(bo),
386 used, NULL, 0, 0, exec_flags);
387 }
388}
389
390void
391intel_winsys_decode_bo(struct intel_winsys *winsys,
392 struct intel_bo *bo, int used)
393{
Chia-I Wu770b3092014-08-05 14:22:03 +0800394 struct drm_intel_decode *decode;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800395 void *ptr;
396
397 ptr = intel_bo_map(bo, false);
398 if (!ptr) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800399 return;
400 }
401
Chia-I Wu770b3092014-08-05 14:22:03 +0800402 decode = drm_intel_decode_context_alloc(winsys->info.devid);
403 if (!decode) {
404 intel_bo_unmap(bo);
405 return;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800406 }
407
Chia-I Wu770b3092014-08-05 14:22:03 +0800408 drm_intel_decode_set_output_file(decode, stderr);
409
Chia-I Wu6464ff22014-08-05 11:59:54 +0800410 /* in dwords */
411 used /= 4;
412
Chia-I Wu770b3092014-08-05 14:22:03 +0800413 drm_intel_decode_set_batch_pointer(decode,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800414 ptr, gem_bo(bo)->offset64, used);
415
Chia-I Wu770b3092014-08-05 14:22:03 +0800416 drm_intel_decode(decode);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800417
418 intel_bo_unmap(bo);
419}
420
421void
422intel_bo_reference(struct intel_bo *bo)
423{
424 drm_intel_bo_reference(gem_bo(bo));
425}
426
427void
428intel_bo_unreference(struct intel_bo *bo)
429{
430 drm_intel_bo_unreference(gem_bo(bo));
431}
432
433void *
434intel_bo_map(struct intel_bo *bo, bool write_enable)
435{
436 int err;
437
438 err = drm_intel_bo_map(gem_bo(bo), write_enable);
439 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800440 return NULL;
441 }
442
443 return gem_bo(bo)->virtual;
444}
445
446void *
447intel_bo_map_gtt(struct intel_bo *bo)
448{
449 int err;
450
451 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
452 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800453 return NULL;
454 }
455
456 return gem_bo(bo)->virtual;
457}
458
459void *
Chia-I Wu32a22462014-08-26 14:13:46 +0800460intel_bo_map_gtt_async(struct intel_bo *bo)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800461{
462 int err;
463
464 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
465 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800466 return NULL;
467 }
468
469 return gem_bo(bo)->virtual;
470}
471
472void
473intel_bo_unmap(struct intel_bo *bo)
474{
475 int err;
476
477 err = drm_intel_bo_unmap(gem_bo(bo));
478 assert(!err);
479}
480
481int
482intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
483 unsigned long size, const void *data)
484{
485 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
486}
487
488int
489intel_bo_pread(struct intel_bo *bo, unsigned long offset,
490 unsigned long size, void *data)
491{
492 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
493}
494
495int
496intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
497 struct intel_bo *target_bo, uint32_t target_offset,
Chia-I Wu32a22462014-08-26 14:13:46 +0800498 uint32_t flags, uint64_t *presumed_offset)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800499{
Chia-I Wu32a22462014-08-26 14:13:46 +0800500 uint32_t read_domains, write_domain;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800501 int err;
502
Chia-I Wu32a22462014-08-26 14:13:46 +0800503 if (flags & INTEL_RELOC_WRITE) {
504 /*
505 * Because of the translation to domains, INTEL_RELOC_GGTT should only
506 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
507 * kernel will translate it back to INTEL_RELOC_GGTT.
508 */
509 write_domain = (flags & INTEL_RELOC_GGTT) ?
510 I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
511 read_domains = write_domain;
512 } else {
513 write_domain = 0;
514 read_domains = I915_GEM_DOMAIN_RENDER |
515 I915_GEM_DOMAIN_SAMPLER |
516 I915_GEM_DOMAIN_INSTRUCTION |
517 I915_GEM_DOMAIN_VERTEX;
518 }
519
520 if (flags & INTEL_RELOC_FENCE) {
521 err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
522 gem_bo(target_bo), target_offset,
523 read_domains, write_domain);
524 } else {
525 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
526 gem_bo(target_bo), target_offset,
527 read_domains, write_domain);
528 }
Chia-I Wu6464ff22014-08-05 11:59:54 +0800529
530 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
531
532 return err;
533}
534
535int
536intel_bo_get_reloc_count(struct intel_bo *bo)
537{
538 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
539}
540
541void
542intel_bo_truncate_relocs(struct intel_bo *bo, int start)
543{
544 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
545}
546
547bool
548intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
549{
550 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
551}
552
553int
554intel_bo_wait(struct intel_bo *bo, int64_t timeout)
555{
556 int err;
557
558 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
559 /* consider the bo idle on errors */
560 if (err && err != -ETIME)
561 err = 0;
562
563 return err;
564}