blob: 8e9f2850937df01ffcfd5cab75cb05da94bc8a6f [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 {
Chia-I Wuaaebcc52014-09-18 16:11:36 +0800339 uint32_t real_tiling = tiling;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800340 int fd;
341
Chia-I Wuaaebcc52014-09-18 16:11:36 +0800342 err = drm_intel_bo_set_tiling(gem_bo(bo), &real_tiling, pitch);
343 if (!err)
344 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800345 if (!err)
346 handle->handle = fd;
347 }
348 break;
349 default:
350 err = -EINVAL;
351 break;
352 }
353
354 if (err)
355 return err;
356
357 handle->stride = pitch;
358
359 return 0;
360}
361
362bool
363intel_winsys_can_submit_bo(struct intel_winsys *winsys,
364 struct intel_bo **bo_array,
365 int count)
366{
367 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
368 count);
369}
370
371int
372intel_winsys_submit_bo(struct intel_winsys *winsys,
373 enum intel_ring_type ring,
374 struct intel_bo *bo, int used,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800375 unsigned long flags)
376{
377 const unsigned long exec_flags = (unsigned long) ring | flags;
Chia-I Wu770b3092014-08-05 14:22:03 +0800378 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800379
380 /* logical contexts are only available for the render ring */
Chia-I Wu770b3092014-08-05 14:22:03 +0800381 ctx = (ring == INTEL_RING_RENDER) ? winsys->ctx : NULL;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800382
383 if (ctx) {
384 return drm_intel_gem_bo_context_exec(gem_bo(bo),
Chia-I Wu770b3092014-08-05 14:22:03 +0800385 ctx, used, exec_flags);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800386 }
387 else {
388 return drm_intel_bo_mrb_exec(gem_bo(bo),
389 used, NULL, 0, 0, exec_flags);
390 }
391}
392
393void
394intel_winsys_decode_bo(struct intel_winsys *winsys,
395 struct intel_bo *bo, int used)
396{
Chia-I Wu770b3092014-08-05 14:22:03 +0800397 struct drm_intel_decode *decode;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800398 void *ptr;
399
400 ptr = intel_bo_map(bo, false);
401 if (!ptr) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800402 return;
403 }
404
Chia-I Wu770b3092014-08-05 14:22:03 +0800405 decode = drm_intel_decode_context_alloc(winsys->info.devid);
406 if (!decode) {
407 intel_bo_unmap(bo);
408 return;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800409 }
410
Chia-I Wu770b3092014-08-05 14:22:03 +0800411 drm_intel_decode_set_output_file(decode, stderr);
412
Chia-I Wu6464ff22014-08-05 11:59:54 +0800413 /* in dwords */
414 used /= 4;
415
Chia-I Wu770b3092014-08-05 14:22:03 +0800416 drm_intel_decode_set_batch_pointer(decode,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800417 ptr, gem_bo(bo)->offset64, used);
418
Chia-I Wu770b3092014-08-05 14:22:03 +0800419 drm_intel_decode(decode);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800420
421 intel_bo_unmap(bo);
422}
423
424void
425intel_bo_reference(struct intel_bo *bo)
426{
427 drm_intel_bo_reference(gem_bo(bo));
428}
429
430void
431intel_bo_unreference(struct intel_bo *bo)
432{
433 drm_intel_bo_unreference(gem_bo(bo));
434}
435
436void *
437intel_bo_map(struct intel_bo *bo, bool write_enable)
438{
439 int err;
440
441 err = drm_intel_bo_map(gem_bo(bo), write_enable);
442 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800443 return NULL;
444 }
445
446 return gem_bo(bo)->virtual;
447}
448
449void *
450intel_bo_map_gtt(struct intel_bo *bo)
451{
452 int err;
453
454 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
455 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800456 return NULL;
457 }
458
459 return gem_bo(bo)->virtual;
460}
461
462void *
Chia-I Wu32a22462014-08-26 14:13:46 +0800463intel_bo_map_gtt_async(struct intel_bo *bo)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800464{
465 int err;
466
467 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
468 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800469 return NULL;
470 }
471
472 return gem_bo(bo)->virtual;
473}
474
475void
476intel_bo_unmap(struct intel_bo *bo)
477{
478 int err;
479
480 err = drm_intel_bo_unmap(gem_bo(bo));
481 assert(!err);
482}
483
484int
485intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
486 unsigned long size, const void *data)
487{
488 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
489}
490
491int
492intel_bo_pread(struct intel_bo *bo, unsigned long offset,
493 unsigned long size, void *data)
494{
495 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
496}
497
498int
499intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
500 struct intel_bo *target_bo, uint32_t target_offset,
Chia-I Wu32a22462014-08-26 14:13:46 +0800501 uint32_t flags, uint64_t *presumed_offset)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800502{
Chia-I Wu32a22462014-08-26 14:13:46 +0800503 uint32_t read_domains, write_domain;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800504 int err;
505
Chia-I Wu32a22462014-08-26 14:13:46 +0800506 if (flags & INTEL_RELOC_WRITE) {
507 /*
508 * Because of the translation to domains, INTEL_RELOC_GGTT should only
509 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
510 * kernel will translate it back to INTEL_RELOC_GGTT.
511 */
512 write_domain = (flags & INTEL_RELOC_GGTT) ?
513 I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
514 read_domains = write_domain;
515 } else {
516 write_domain = 0;
517 read_domains = I915_GEM_DOMAIN_RENDER |
518 I915_GEM_DOMAIN_SAMPLER |
519 I915_GEM_DOMAIN_INSTRUCTION |
520 I915_GEM_DOMAIN_VERTEX;
521 }
522
523 if (flags & INTEL_RELOC_FENCE) {
524 err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
525 gem_bo(target_bo), target_offset,
526 read_domains, write_domain);
527 } else {
528 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
529 gem_bo(target_bo), target_offset,
530 read_domains, write_domain);
531 }
Chia-I Wu6464ff22014-08-05 11:59:54 +0800532
533 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
534
535 return err;
536}
537
538int
539intel_bo_get_reloc_count(struct intel_bo *bo)
540{
541 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
542}
543
544void
545intel_bo_truncate_relocs(struct intel_bo *bo, int start)
546{
547 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
548}
549
550bool
551intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
552{
553 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
554}
555
556int
557intel_bo_wait(struct intel_bo *bo, int64_t timeout)
558{
559 int err;
560
561 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
562 /* consider the bo idle on errors */
563 if (err && err != -ETIME)
564 err = 0;
565
566 return err;
567}