blob: e91dac1915897fb51229d69d0834fbb5b45707b0 [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>
Courtney Goeltzenleuchter8d651042014-09-25 18:15:33 -060029#include <stdlib.h>
Chia-I Wu770b3092014-08-05 14:22:03 +080030#include <limits.h>
Chia-I Wu6464ff22014-08-05 11:59:54 +080031#include <errno.h>
32#ifndef ETIME
33#define ETIME ETIMEDOUT
34#endif
Chia-I Wu770b3092014-08-05 14:22:03 +080035#include <assert.h>
Chia-I Wu6464ff22014-08-05 11:59:54 +080036
37#include <xf86drm.h>
38#include <i915_drm.h>
39#include <intel_bufmgr.h>
40
Chia-I Wu900364b2015-01-03 13:55:22 +080041#include "icd-alloc.h"
Chia-I Wu770b3092014-08-05 14:22:03 +080042#include "winsys.h"
Chia-I Wu6464ff22014-08-05 11:59:54 +080043
Chia-I Wu6464ff22014-08-05 11:59:54 +080044struct intel_winsys {
45 int fd;
46 drm_intel_bufmgr *bufmgr;
47 struct intel_winsys_info info;
48
Chia-I Wu770b3092014-08-05 14:22:03 +080049 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +080050};
51
52static drm_intel_bo *
53gem_bo(const struct intel_bo *bo)
54{
55 return (drm_intel_bo *) bo;
56}
57
58static bool
59get_param(struct intel_winsys *winsys, int param, int *value)
60{
61 struct drm_i915_getparam gp;
62 int err;
63
64 *value = 0;
65
66 memset(&gp, 0, sizeof(gp));
67 gp.param = param;
68 gp.value = value;
69
70 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
71 if (err) {
72 *value = 0;
73 return false;
74 }
75
76 return true;
77}
78
79static bool
80test_address_swizzling(struct intel_winsys *winsys)
81{
82 drm_intel_bo *bo;
83 uint32_t tiling = I915_TILING_X, swizzle;
84 unsigned long pitch;
85
86 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
87 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
88 if (bo) {
89 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
90 drm_intel_bo_unreference(bo);
91 }
92 else {
93 swizzle = I915_BIT_6_SWIZZLE_NONE;
94 }
95
96 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
97}
98
99static bool
100test_reg_read(struct intel_winsys *winsys, uint32_t reg)
101{
102 uint64_t dummy;
103
104 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
105}
106
107static bool
108probe_winsys(struct intel_winsys *winsys)
109{
110 struct intel_winsys_info *info = &winsys->info;
111 int val;
112
113 /*
114 * When we need the Nth vertex from a user vertex buffer, and the vertex is
115 * uploaded to, say, the beginning of a bo, we want the first vertex in the
116 * bo to be fetched. One way to do this is to set the base address of the
117 * vertex buffer to
118 *
119 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
120 *
121 * The second term may be negative, and we need kernel support to do that.
122 *
123 * This check is taken from the classic driver. u_vbuf_upload_buffers()
124 * guarantees the term is never negative, but it is good to require a
125 * recent kernel.
126 */
127 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
128 if (!val) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800129 return false;
130 }
131
132 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
133
Chia-I Wubbedc592015-02-11 11:10:14 -0700134 if (drm_intel_get_aperture_sizes(winsys->fd,
135 &info->aperture_mappable, &info->aperture_total)) {
136 return false;
137 }
138
Chia-I Wu6464ff22014-08-05 11:59:54 +0800139 get_param(winsys, I915_PARAM_HAS_LLC, &val);
140 info->has_llc = val;
141 info->has_address_swizzling = test_address_swizzling(winsys);
142
Chia-I Wu770b3092014-08-05 14:22:03 +0800143 winsys->ctx = drm_intel_gem_context_create(winsys->bufmgr);
144 if (!winsys->ctx)
145 return false;
146
147 info->has_logical_context = (winsys->ctx != NULL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800148
149 get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
150 info->has_ppgtt = val;
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 return true;
159}
160
161struct intel_winsys *
162intel_winsys_create_for_fd(int fd)
163{
Mike Stroyan9fca7122015-02-09 13:08:26 -0700164 /* so that we can have enough relocs per bo */
165 const int batch_size = sizeof(uint32_t) * 150 * 1024;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800166 struct intel_winsys *winsys;
167
Chia-I Wu770b3092014-08-05 14:22:03 +0800168 winsys = icd_alloc(sizeof(*winsys), 0, XGL_SYSTEM_ALLOC_INTERNAL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800169 if (!winsys)
170 return NULL;
171
Chia-I Wu770b3092014-08-05 14:22:03 +0800172 memset(winsys, 0, sizeof(*winsys));
173
Chia-I Wu6464ff22014-08-05 11:59:54 +0800174 winsys->fd = fd;
175
Chia-I Wu32a22462014-08-26 14:13:46 +0800176 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, batch_size);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800177 if (!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
Chia-I Wu6464ff22014-08-05 11:59:54 +0800182 if (!probe_winsys(winsys)) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800183 drm_intel_bufmgr_destroy(winsys->bufmgr);
Chia-I Wu770b3092014-08-05 14:22:03 +0800184 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800185 return NULL;
186 }
187
188 /*
189 * No need to implicitly set up a fence register for each non-linear reloc
Chia-I Wu32a22462014-08-26 14:13:46 +0800190 * entry. INTEL_RELOC_FENCE will be set on reloc entries that need them.
Chia-I Wu6464ff22014-08-05 11:59:54 +0800191 */
192 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
193
194 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
Chia-I Wuf5359fa2014-12-02 00:23:55 +0800195 drm_intel_bufmgr_gem_set_vma_cache_size(winsys->bufmgr, 1024);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800196
197 return winsys;
198}
199
200void
201intel_winsys_destroy(struct intel_winsys *winsys)
202{
Chia-I Wu770b3092014-08-05 14:22:03 +0800203 drm_intel_gem_context_destroy(winsys->ctx);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800204 drm_intel_bufmgr_destroy(winsys->bufmgr);
Chia-I Wu770b3092014-08-05 14:22:03 +0800205 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800206}
207
208const struct intel_winsys_info *
209intel_winsys_get_info(const struct intel_winsys *winsys)
210{
211 return &winsys->info;
212}
213
Chia-I Wu6464ff22014-08-05 11:59:54 +0800214int
215intel_winsys_read_reg(struct intel_winsys *winsys,
216 uint32_t reg, uint64_t *val)
217{
218 return drm_intel_reg_read(winsys->bufmgr, reg, val);
219}
220
221struct intel_bo *
222intel_winsys_alloc_bo(struct intel_winsys *winsys,
223 const char *name,
224 enum intel_tiling_mode tiling,
225 unsigned long pitch,
226 unsigned long height,
Chia-I Wu32a22462014-08-26 14:13:46 +0800227 bool cpu_init)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800228{
Chia-I Wu6464ff22014-08-05 11:59:54 +0800229 const unsigned int alignment = 4096; /* always page-aligned */
230 unsigned long size;
231 drm_intel_bo *bo;
232
233 switch (tiling) {
234 case INTEL_TILING_X:
235 if (pitch % 512)
236 return NULL;
237 break;
238 case INTEL_TILING_Y:
239 if (pitch % 128)
240 return NULL;
241 break;
242 default:
243 break;
244 }
245
246 if (pitch > ULONG_MAX / height)
247 return NULL;
248
249 size = pitch * height;
250
Chia-I Wu32a22462014-08-26 14:13:46 +0800251 if (cpu_init) {
252 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800253 }
254 else {
Chia-I Wu32a22462014-08-26 14:13:46 +0800255 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
256 name, size, alignment);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800257 }
258
259 if (bo && tiling != INTEL_TILING_NONE) {
260 uint32_t real_tiling = tiling;
261 int err;
262
263 err = drm_intel_bo_set_tiling(bo, &real_tiling, pitch);
264 if (err || real_tiling != tiling) {
265 assert(!"tiling mismatch");
266 drm_intel_bo_unreference(bo);
267 return NULL;
268 }
269 }
270
271 return (struct intel_bo *) bo;
272}
273
274struct intel_bo *
275intel_winsys_import_handle(struct intel_winsys *winsys,
276 const char *name,
Chia-I Wu770b3092014-08-05 14:22:03 +0800277 const struct intel_winsys_handle *handle,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800278 unsigned long height,
279 enum intel_tiling_mode *tiling,
280 unsigned long *pitch)
281{
282 uint32_t real_tiling, swizzle;
283 drm_intel_bo *bo;
284 int err;
285
286 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800287 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800288 {
289 const uint32_t gem_name = handle->handle;
290 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
291 name, gem_name);
292 }
293 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800294 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800295 {
296 const int fd = (int) handle->handle;
297 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
298 fd, height * handle->stride);
299 }
300 break;
301 default:
302 bo = NULL;
303 break;
304 }
305
306 if (!bo)
307 return NULL;
308
309 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
310 if (err) {
311 drm_intel_bo_unreference(bo);
312 return NULL;
313 }
314
315 *tiling = real_tiling;
316 *pitch = handle->stride;
317
318 return (struct intel_bo *) bo;
319}
320
321int
322intel_winsys_export_handle(struct intel_winsys *winsys,
323 struct intel_bo *bo,
324 enum intel_tiling_mode tiling,
325 unsigned long pitch,
326 unsigned long height,
Chia-I Wu770b3092014-08-05 14:22:03 +0800327 struct intel_winsys_handle *handle)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800328{
329 int err = 0;
330
331 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800332 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800333 {
334 uint32_t name;
335
336 err = drm_intel_bo_flink(gem_bo(bo), &name);
337 if (!err)
338 handle->handle = name;
339 }
340 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800341 case INTEL_WINSYS_HANDLE_KMS:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800342 handle->handle = gem_bo(bo)->handle;
343 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800344 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800345 {
Chia-I Wuaaebcc52014-09-18 16:11:36 +0800346 uint32_t real_tiling = tiling;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800347 int fd;
348
Chia-I Wuaaebcc52014-09-18 16:11:36 +0800349 err = drm_intel_bo_set_tiling(gem_bo(bo), &real_tiling, pitch);
350 if (!err)
351 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800352 if (!err)
353 handle->handle = fd;
354 }
355 break;
356 default:
357 err = -EINVAL;
358 break;
359 }
360
361 if (err)
362 return err;
363
364 handle->stride = pitch;
365
366 return 0;
367}
368
369bool
370intel_winsys_can_submit_bo(struct intel_winsys *winsys,
371 struct intel_bo **bo_array,
372 int count)
373{
374 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
375 count);
376}
377
378int
379intel_winsys_submit_bo(struct intel_winsys *winsys,
380 enum intel_ring_type ring,
381 struct intel_bo *bo, int used,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800382 unsigned long flags)
383{
384 const unsigned long exec_flags = (unsigned long) ring | flags;
Chia-I Wu770b3092014-08-05 14:22:03 +0800385 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800386
387 /* logical contexts are only available for the render ring */
Chia-I Wu770b3092014-08-05 14:22:03 +0800388 ctx = (ring == INTEL_RING_RENDER) ? winsys->ctx : NULL;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800389
390 if (ctx) {
391 return drm_intel_gem_bo_context_exec(gem_bo(bo),
Chia-I Wu770b3092014-08-05 14:22:03 +0800392 ctx, used, exec_flags);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800393 }
394 else {
395 return drm_intel_bo_mrb_exec(gem_bo(bo),
396 used, NULL, 0, 0, exec_flags);
397 }
398}
399
400void
401intel_winsys_decode_bo(struct intel_winsys *winsys,
402 struct intel_bo *bo, int used)
403{
Chia-I Wu770b3092014-08-05 14:22:03 +0800404 struct drm_intel_decode *decode;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800405 void *ptr;
406
407 ptr = intel_bo_map(bo, false);
408 if (!ptr) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800409 return;
410 }
411
Chia-I Wu770b3092014-08-05 14:22:03 +0800412 decode = drm_intel_decode_context_alloc(winsys->info.devid);
413 if (!decode) {
414 intel_bo_unmap(bo);
415 return;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800416 }
417
Chia-I Wu770b3092014-08-05 14:22:03 +0800418 drm_intel_decode_set_output_file(decode, stderr);
419
Chia-I Wu6464ff22014-08-05 11:59:54 +0800420 /* in dwords */
421 used /= 4;
422
Chia-I Wu770b3092014-08-05 14:22:03 +0800423 drm_intel_decode_set_batch_pointer(decode,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800424 ptr, gem_bo(bo)->offset64, used);
425
Chia-I Wu770b3092014-08-05 14:22:03 +0800426 drm_intel_decode(decode);
Courtney Goeltzenleuchter8d651042014-09-25 18:15:33 -0600427 free(decode);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800428 intel_bo_unmap(bo);
429}
430
431void
432intel_bo_reference(struct intel_bo *bo)
433{
434 drm_intel_bo_reference(gem_bo(bo));
435}
436
437void
438intel_bo_unreference(struct intel_bo *bo)
439{
440 drm_intel_bo_unreference(gem_bo(bo));
441}
442
443void *
444intel_bo_map(struct intel_bo *bo, bool write_enable)
445{
446 int err;
447
448 err = drm_intel_bo_map(gem_bo(bo), write_enable);
449 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800450 return NULL;
451 }
452
453 return gem_bo(bo)->virtual;
454}
455
456void *
457intel_bo_map_gtt(struct intel_bo *bo)
458{
459 int err;
460
461 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
462 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800463 return NULL;
464 }
465
466 return gem_bo(bo)->virtual;
467}
468
469void *
Chia-I Wu32a22462014-08-26 14:13:46 +0800470intel_bo_map_gtt_async(struct intel_bo *bo)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800471{
472 int err;
473
474 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
475 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800476 return NULL;
477 }
478
479 return gem_bo(bo)->virtual;
480}
481
482void
483intel_bo_unmap(struct intel_bo *bo)
484{
485 int err;
486
487 err = drm_intel_bo_unmap(gem_bo(bo));
488 assert(!err);
489}
490
491int
492intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
493 unsigned long size, const void *data)
494{
495 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
496}
497
498int
499intel_bo_pread(struct intel_bo *bo, unsigned long offset,
500 unsigned long size, void *data)
501{
502 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
503}
504
505int
506intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
507 struct intel_bo *target_bo, uint32_t target_offset,
Chia-I Wu32a22462014-08-26 14:13:46 +0800508 uint32_t flags, uint64_t *presumed_offset)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800509{
Chia-I Wu32a22462014-08-26 14:13:46 +0800510 uint32_t read_domains, write_domain;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800511 int err;
512
Chia-I Wu32a22462014-08-26 14:13:46 +0800513 if (flags & INTEL_RELOC_WRITE) {
514 /*
515 * Because of the translation to domains, INTEL_RELOC_GGTT should only
516 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
517 * kernel will translate it back to INTEL_RELOC_GGTT.
518 */
519 write_domain = (flags & INTEL_RELOC_GGTT) ?
520 I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
521 read_domains = write_domain;
522 } else {
523 write_domain = 0;
524 read_domains = I915_GEM_DOMAIN_RENDER |
525 I915_GEM_DOMAIN_SAMPLER |
526 I915_GEM_DOMAIN_INSTRUCTION |
527 I915_GEM_DOMAIN_VERTEX;
528 }
529
530 if (flags & INTEL_RELOC_FENCE) {
531 err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
532 gem_bo(target_bo), target_offset,
533 read_domains, write_domain);
534 } else {
535 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
536 gem_bo(target_bo), target_offset,
537 read_domains, write_domain);
538 }
Chia-I Wu6464ff22014-08-05 11:59:54 +0800539
540 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
541
542 return err;
543}
544
545int
546intel_bo_get_reloc_count(struct intel_bo *bo)
547{
548 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
549}
550
551void
552intel_bo_truncate_relocs(struct intel_bo *bo, int start)
553{
554 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
555}
556
557bool
558intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
559{
560 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
561}
562
563int
564intel_bo_wait(struct intel_bo *bo, int64_t timeout)
565{
Chia-I Wu05a45f82014-10-13 13:20:11 +0800566 int err = 0;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800567
Chia-I Wu05a45f82014-10-13 13:20:11 +0800568 if (timeout >= 0)
569 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
570 else
571 drm_intel_bo_wait_rendering(gem_bo(bo));
572
Chia-I Wu6464ff22014-08-05 11:59:54 +0800573 /* consider the bo idle on errors */
574 if (err && err != -ETIME)
575 err = 0;
576
577 return err;
578}