blob: 571e3b83cb8770ddd59bb99d2af816736c0981ff [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
43#define BATCH_SZ (8192 * sizeof(uint32_t))
44
45struct intel_winsys {
46 int fd;
47 drm_intel_bufmgr *bufmgr;
48 struct intel_winsys_info info;
49
Chia-I Wu770b3092014-08-05 14:22:03 +080050 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +080051};
52
53static drm_intel_bo *
54gem_bo(const struct intel_bo *bo)
55{
56 return (drm_intel_bo *) bo;
57}
58
59static bool
60get_param(struct intel_winsys *winsys, int param, int *value)
61{
62 struct drm_i915_getparam gp;
63 int err;
64
65 *value = 0;
66
67 memset(&gp, 0, sizeof(gp));
68 gp.param = param;
69 gp.value = value;
70
71 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
72 if (err) {
73 *value = 0;
74 return false;
75 }
76
77 return true;
78}
79
80static bool
81test_address_swizzling(struct intel_winsys *winsys)
82{
83 drm_intel_bo *bo;
84 uint32_t tiling = I915_TILING_X, swizzle;
85 unsigned long pitch;
86
87 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
88 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
89 if (bo) {
90 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
91 drm_intel_bo_unreference(bo);
92 }
93 else {
94 swizzle = I915_BIT_6_SWIZZLE_NONE;
95 }
96
97 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
98}
99
100static bool
101test_reg_read(struct intel_winsys *winsys, uint32_t reg)
102{
103 uint64_t dummy;
104
105 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
106}
107
108static bool
109probe_winsys(struct intel_winsys *winsys)
110{
111 struct intel_winsys_info *info = &winsys->info;
112 int val;
113
114 /*
115 * When we need the Nth vertex from a user vertex buffer, and the vertex is
116 * uploaded to, say, the beginning of a bo, we want the first vertex in the
117 * bo to be fetched. One way to do this is to set the base address of the
118 * vertex buffer to
119 *
120 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
121 *
122 * The second term may be negative, and we need kernel support to do that.
123 *
124 * This check is taken from the classic driver. u_vbuf_upload_buffers()
125 * guarantees the term is never negative, but it is good to require a
126 * recent kernel.
127 */
128 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
129 if (!val) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800130 return false;
131 }
132
133 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
134
135 info->max_batch_size = BATCH_SZ;
136
137 get_param(winsys, I915_PARAM_HAS_LLC, &val);
138 info->has_llc = val;
139 info->has_address_swizzling = test_address_swizzling(winsys);
140
Chia-I Wu770b3092014-08-05 14:22:03 +0800141 winsys->ctx = drm_intel_gem_context_create(winsys->bufmgr);
142 if (!winsys->ctx)
143 return false;
144
145 info->has_logical_context = (winsys->ctx != NULL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800146
147 get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
148 info->has_ppgtt = val;
149
150 /* test TIMESTAMP read */
151 info->has_timestamp = test_reg_read(winsys, 0x2358);
152
153 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
154 info->has_gen7_sol_reset = val;
155
156 return true;
157}
158
159struct intel_winsys *
160intel_winsys_create_for_fd(int fd)
161{
162 struct intel_winsys *winsys;
163
Chia-I Wu770b3092014-08-05 14:22:03 +0800164 winsys = icd_alloc(sizeof(*winsys), 0, XGL_SYSTEM_ALLOC_INTERNAL);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800165 if (!winsys)
166 return NULL;
167
Chia-I Wu770b3092014-08-05 14:22:03 +0800168 memset(winsys, 0, sizeof(*winsys));
169
Chia-I Wu6464ff22014-08-05 11:59:54 +0800170 winsys->fd = fd;
171
172 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, BATCH_SZ);
173 if (!winsys->bufmgr) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800174 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800175 return NULL;
176 }
177
Chia-I Wu6464ff22014-08-05 11:59:54 +0800178 if (!probe_winsys(winsys)) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800179 drm_intel_bufmgr_destroy(winsys->bufmgr);
Chia-I Wu770b3092014-08-05 14:22:03 +0800180 icd_free(winsys);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800181 return NULL;
182 }
183
184 /*
185 * No need to implicitly set up a fence register for each non-linear reloc
186 * entry. When a fence register is needed for a reloc entry,
187 * drm_intel_bo_emit_reloc_fence() will be called explicitly.
188 *
189 * intel_bo_add_reloc() currently lacks "bool fenced" for this to work.
190 * But we never need a fence register on GEN4+ so we do not need to worry
191 * about it yet.
192 */
193 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
194
195 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
196
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,
227 uint32_t initial_domain)
228{
229 const bool for_render =
230 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION));
231 const unsigned int alignment = 4096; /* always page-aligned */
232 unsigned long size;
233 drm_intel_bo *bo;
234
235 switch (tiling) {
236 case INTEL_TILING_X:
237 if (pitch % 512)
238 return NULL;
239 break;
240 case INTEL_TILING_Y:
241 if (pitch % 128)
242 return NULL;
243 break;
244 default:
245 break;
246 }
247
248 if (pitch > ULONG_MAX / height)
249 return NULL;
250
251 size = pitch * height;
252
253 if (for_render) {
254 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
255 name, size, alignment);
256 }
257 else {
258 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
259 }
260
261 if (bo && tiling != INTEL_TILING_NONE) {
262 uint32_t real_tiling = tiling;
263 int err;
264
265 err = drm_intel_bo_set_tiling(bo, &real_tiling, pitch);
266 if (err || real_tiling != tiling) {
267 assert(!"tiling mismatch");
268 drm_intel_bo_unreference(bo);
269 return NULL;
270 }
271 }
272
273 return (struct intel_bo *) bo;
274}
275
276struct intel_bo *
277intel_winsys_import_handle(struct intel_winsys *winsys,
278 const char *name,
Chia-I Wu770b3092014-08-05 14:22:03 +0800279 const struct intel_winsys_handle *handle,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800280 unsigned long height,
281 enum intel_tiling_mode *tiling,
282 unsigned long *pitch)
283{
284 uint32_t real_tiling, swizzle;
285 drm_intel_bo *bo;
286 int err;
287
288 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800289 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800290 {
291 const uint32_t gem_name = handle->handle;
292 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
293 name, gem_name);
294 }
295 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800296 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800297 {
298 const int fd = (int) handle->handle;
299 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
300 fd, height * handle->stride);
301 }
302 break;
303 default:
304 bo = NULL;
305 break;
306 }
307
308 if (!bo)
309 return NULL;
310
311 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
312 if (err) {
313 drm_intel_bo_unreference(bo);
314 return NULL;
315 }
316
317 *tiling = real_tiling;
318 *pitch = handle->stride;
319
320 return (struct intel_bo *) bo;
321}
322
323int
324intel_winsys_export_handle(struct intel_winsys *winsys,
325 struct intel_bo *bo,
326 enum intel_tiling_mode tiling,
327 unsigned long pitch,
328 unsigned long height,
Chia-I Wu770b3092014-08-05 14:22:03 +0800329 struct intel_winsys_handle *handle)
Chia-I Wu6464ff22014-08-05 11:59:54 +0800330{
331 int err = 0;
332
333 switch (handle->type) {
Chia-I Wu770b3092014-08-05 14:22:03 +0800334 case INTEL_WINSYS_HANDLE_SHARED:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800335 {
336 uint32_t name;
337
338 err = drm_intel_bo_flink(gem_bo(bo), &name);
339 if (!err)
340 handle->handle = name;
341 }
342 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800343 case INTEL_WINSYS_HANDLE_KMS:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800344 handle->handle = gem_bo(bo)->handle;
345 break;
Chia-I Wu770b3092014-08-05 14:22:03 +0800346 case INTEL_WINSYS_HANDLE_FD:
Chia-I Wu6464ff22014-08-05 11:59:54 +0800347 {
348 int fd;
349
350 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
351 if (!err)
352 handle->handle = fd;
353 }
354 break;
355 default:
356 err = -EINVAL;
357 break;
358 }
359
360 if (err)
361 return err;
362
363 handle->stride = pitch;
364
365 return 0;
366}
367
368bool
369intel_winsys_can_submit_bo(struct intel_winsys *winsys,
370 struct intel_bo **bo_array,
371 int count)
372{
373 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
374 count);
375}
376
377int
378intel_winsys_submit_bo(struct intel_winsys *winsys,
379 enum intel_ring_type ring,
380 struct intel_bo *bo, int used,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800381 unsigned long flags)
382{
383 const unsigned long exec_flags = (unsigned long) ring | flags;
Chia-I Wu770b3092014-08-05 14:22:03 +0800384 drm_intel_context *ctx;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800385
386 /* logical contexts are only available for the render ring */
Chia-I Wu770b3092014-08-05 14:22:03 +0800387 ctx = (ring == INTEL_RING_RENDER) ? winsys->ctx : NULL;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800388
389 if (ctx) {
390 return drm_intel_gem_bo_context_exec(gem_bo(bo),
Chia-I Wu770b3092014-08-05 14:22:03 +0800391 ctx, used, exec_flags);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800392 }
393 else {
394 return drm_intel_bo_mrb_exec(gem_bo(bo),
395 used, NULL, 0, 0, exec_flags);
396 }
397}
398
399void
400intel_winsys_decode_bo(struct intel_winsys *winsys,
401 struct intel_bo *bo, int used)
402{
Chia-I Wu770b3092014-08-05 14:22:03 +0800403 struct drm_intel_decode *decode;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800404 void *ptr;
405
406 ptr = intel_bo_map(bo, false);
407 if (!ptr) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800408 return;
409 }
410
Chia-I Wu770b3092014-08-05 14:22:03 +0800411 decode = drm_intel_decode_context_alloc(winsys->info.devid);
412 if (!decode) {
413 intel_bo_unmap(bo);
414 return;
Chia-I Wu6464ff22014-08-05 11:59:54 +0800415 }
416
Chia-I Wu770b3092014-08-05 14:22:03 +0800417 drm_intel_decode_set_output_file(decode, stderr);
418
Chia-I Wu6464ff22014-08-05 11:59:54 +0800419 /* in dwords */
420 used /= 4;
421
Chia-I Wu770b3092014-08-05 14:22:03 +0800422 drm_intel_decode_set_batch_pointer(decode,
Chia-I Wu6464ff22014-08-05 11:59:54 +0800423 ptr, gem_bo(bo)->offset64, used);
424
Chia-I Wu770b3092014-08-05 14:22:03 +0800425 drm_intel_decode(decode);
Chia-I Wu6464ff22014-08-05 11:59:54 +0800426
427 intel_bo_unmap(bo);
428}
429
430void
431intel_bo_reference(struct intel_bo *bo)
432{
433 drm_intel_bo_reference(gem_bo(bo));
434}
435
436void
437intel_bo_unreference(struct intel_bo *bo)
438{
439 drm_intel_bo_unreference(gem_bo(bo));
440}
441
442void *
443intel_bo_map(struct intel_bo *bo, bool write_enable)
444{
445 int err;
446
447 err = drm_intel_bo_map(gem_bo(bo), write_enable);
448 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800449 return NULL;
450 }
451
452 return gem_bo(bo)->virtual;
453}
454
455void *
456intel_bo_map_gtt(struct intel_bo *bo)
457{
458 int err;
459
460 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
461 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800462 return NULL;
463 }
464
465 return gem_bo(bo)->virtual;
466}
467
468void *
469intel_bo_map_unsynchronized(struct intel_bo *bo)
470{
471 int err;
472
473 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
474 if (err) {
Chia-I Wu6464ff22014-08-05 11:59:54 +0800475 return NULL;
476 }
477
478 return gem_bo(bo)->virtual;
479}
480
481void
482intel_bo_unmap(struct intel_bo *bo)
483{
484 int err;
485
486 err = drm_intel_bo_unmap(gem_bo(bo));
487 assert(!err);
488}
489
490int
491intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
492 unsigned long size, const void *data)
493{
494 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
495}
496
497int
498intel_bo_pread(struct intel_bo *bo, unsigned long offset,
499 unsigned long size, void *data)
500{
501 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
502}
503
504int
505intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
506 struct intel_bo *target_bo, uint32_t target_offset,
507 uint32_t read_domains, uint32_t write_domain,
508 uint64_t *presumed_offset)
509{
510 int err;
511
512 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
513 gem_bo(target_bo), target_offset,
514 read_domains, write_domain);
515
516 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
517
518 return err;
519}
520
521int
522intel_bo_get_reloc_count(struct intel_bo *bo)
523{
524 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
525}
526
527void
528intel_bo_truncate_relocs(struct intel_bo *bo, int start)
529{
530 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
531}
532
533bool
534intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
535{
536 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
537}
538
539int
540intel_bo_wait(struct intel_bo *bo, int64_t timeout)
541{
542 int err;
543
544 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
545 /* consider the bo idle on errors */
546 if (err && err != -ETIME)
547 err = 0;
548
549 return err;
550}