e119f9ed9a194cc623ea3cc107e3b2dfb8b12c07
[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 "state_tracker/drm_driver.h"
39 #include "pipe/p_state.h"
40 #include "util/u_inlines.h"
41 #include "util/u_memory.h"
42 #include "util/u_debug.h"
43 #include "../intel_winsys.h"
44
45 #define BATCH_SZ (8192 * sizeof(uint32_t))
46
47 struct intel_winsys {
48 int fd;
49 drm_intel_bufmgr *bufmgr;
50 struct intel_winsys_info info;
51
52 struct drm_intel_decode *decode;
53 };
54
55 static drm_intel_bo *
56 gem_bo(const struct intel_bo *bo)
57 {
58 return (drm_intel_bo *) bo;
59 }
60
61 static bool
62 get_param(struct intel_winsys *winsys, int param, int *value)
63 {
64 struct drm_i915_getparam gp;
65 int err;
66
67 *value = 0;
68
69 memset(&gp, 0, sizeof(gp));
70 gp.param = param;
71 gp.value = value;
72
73 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
74 if (err) {
75 *value = 0;
76 return false;
77 }
78
79 return true;
80 }
81
82 static bool
83 test_address_swizzling(struct intel_winsys *winsys)
84 {
85 drm_intel_bo *bo;
86 uint32_t tiling = I915_TILING_X, swizzle;
87 unsigned long pitch;
88
89 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
90 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
91 if (bo) {
92 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
93 drm_intel_bo_unreference(bo);
94 }
95 else {
96 swizzle = I915_BIT_6_SWIZZLE_NONE;
97 }
98
99 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
100 }
101
102 static bool
103 init_info(struct intel_winsys *winsys)
104 {
105 struct intel_winsys_info *info = &winsys->info;
106 int val;
107
108 /*
109 * When we need the Nth vertex from a user vertex buffer, and the vertex is
110 * uploaded to, say, the beginning of a bo, we want the first vertex in the
111 * bo to be fetched. One way to do this is to set the base address of the
112 * vertex buffer to
113 *
114 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
115 *
116 * The second term may be negative, and we need kernel support to do that.
117 *
118 * This check is taken from the classic driver. u_vbuf_upload_buffers()
119 * guarantees the term is never negative, but it is good to require a
120 * recent kernel.
121 */
122 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
123 if (!val) {
124 debug_error("kernel 2.6.39 required");
125 return false;
126 }
127
128 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
129
130 get_param(winsys, I915_PARAM_HAS_LLC, &val);
131 info->has_llc = val;
132
133 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
134 info->has_gen7_sol_reset = val;
135
136 info->has_address_swizzling = test_address_swizzling(winsys);
137
138 return true;
139 }
140
141 struct intel_winsys *
142 intel_winsys_create_for_fd(int fd)
143 {
144 struct intel_winsys *winsys;
145
146 winsys = CALLOC_STRUCT(intel_winsys);
147 if (!winsys)
148 return NULL;
149
150 winsys->fd = fd;
151
152 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, BATCH_SZ);
153 if (!winsys->bufmgr) {
154 debug_error("failed to create GEM buffer manager");
155 FREE(winsys);
156 return NULL;
157 }
158
159 if (!init_info(winsys)) {
160 drm_intel_bufmgr_destroy(winsys->bufmgr);
161 FREE(winsys);
162 return NULL;
163 }
164
165 /*
166 * No need to implicitly set up a fence register for each non-linear reloc
167 * entry. When a fence register is needed for a reloc entry,
168 * drm_intel_bo_emit_reloc_fence() will be called explicitly.
169 *
170 * intel_bo_add_reloc() currently lacks "bool fenced" for this to work.
171 * But we never need a fence register on GEN4+ so we do not need to worry
172 * about it yet.
173 */
174 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
175
176 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
177
178 return winsys;
179 }
180
181 void
182 intel_winsys_destroy(struct intel_winsys *winsys)
183 {
184 if (winsys->decode)
185 drm_intel_decode_context_free(winsys->decode);
186
187 drm_intel_bufmgr_destroy(winsys->bufmgr);
188 FREE(winsys);
189 }
190
191 const struct intel_winsys_info *
192 intel_winsys_get_info(const struct intel_winsys *winsys)
193 {
194 return &winsys->info;
195 }
196
197 struct intel_context *
198 intel_winsys_create_context(struct intel_winsys *winsys)
199 {
200 return (struct intel_context *)
201 drm_intel_gem_context_create(winsys->bufmgr);
202 }
203
204 void
205 intel_winsys_destroy_context(struct intel_winsys *winsys,
206 struct intel_context *ctx)
207 {
208 drm_intel_gem_context_destroy((drm_intel_context *) ctx);
209 }
210
211 int
212 intel_winsys_read_reg(struct intel_winsys *winsys,
213 uint32_t reg, uint64_t *val)
214 {
215 return drm_intel_reg_read(winsys->bufmgr, reg, val);
216 }
217
218 struct intel_bo *
219 intel_winsys_alloc_buffer(struct intel_winsys *winsys,
220 const char *name,
221 unsigned long size,
222 uint32_t initial_domain)
223 {
224 const bool for_render =
225 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION));
226 const int alignment = 4096; /* always page-aligned */
227 drm_intel_bo *bo;
228
229 if (for_render) {
230 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
231 name, size, alignment);
232 }
233 else {
234 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
235 }
236
237 return (struct intel_bo *) bo;
238 }
239
240 struct intel_bo *
241 intel_winsys_alloc_texture(struct intel_winsys *winsys,
242 const char *name,
243 int width, int height, int cpp,
244 enum intel_tiling_mode tiling,
245 uint32_t initial_domain,
246 unsigned long *pitch)
247 {
248 const unsigned long flags =
249 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION)) ?
250 BO_ALLOC_FOR_RENDER : 0;
251 uint32_t real_tiling = tiling;
252 drm_intel_bo *bo;
253
254 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr, name,
255 width, height, cpp, &real_tiling, pitch, flags);
256 if (!bo)
257 return NULL;
258
259 if (real_tiling != tiling) {
260 assert(!"tiling mismatch");
261 drm_intel_bo_unreference(bo);
262 return NULL;
263 }
264
265 return (struct intel_bo *) bo;
266 }
267
268 struct intel_bo *
269 intel_winsys_import_handle(struct intel_winsys *winsys,
270 const char *name,
271 const struct winsys_handle *handle,
272 int width, int height, int cpp,
273 enum intel_tiling_mode *tiling,
274 unsigned long *pitch)
275 {
276 uint32_t real_tiling, swizzle;
277 drm_intel_bo *bo;
278 int err;
279
280 switch (handle->type) {
281 case DRM_API_HANDLE_TYPE_SHARED:
282 {
283 const uint32_t gem_name = handle->handle;
284 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
285 name, gem_name);
286 }
287 break;
288 case DRM_API_HANDLE_TYPE_FD:
289 {
290 const int fd = (int) handle->handle;
291 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
292 fd, height * handle->stride);
293 }
294 break;
295 default:
296 bo = NULL;
297 break;
298 }
299
300 if (!bo)
301 return NULL;
302
303 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
304 if (err) {
305 drm_intel_bo_unreference(bo);
306 return NULL;
307 }
308
309 *tiling = real_tiling;
310 *pitch = handle->stride;
311
312 return (struct intel_bo *) bo;
313 }
314
315 int
316 intel_winsys_export_handle(struct intel_winsys *winsys,
317 struct intel_bo *bo,
318 enum intel_tiling_mode tiling,
319 unsigned long pitch,
320 struct winsys_handle *handle)
321 {
322 int err = 0;
323
324 switch (handle->type) {
325 case DRM_API_HANDLE_TYPE_SHARED:
326 {
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;
334 case DRM_API_HANDLE_TYPE_KMS:
335 handle->handle = gem_bo(bo)->handle;
336 break;
337 case DRM_API_HANDLE_TYPE_FD:
338 {
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
359 int
360 intel_winsys_check_aperture_space(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
368 void
369 intel_winsys_decode_commands(struct intel_winsys *winsys,
370 struct intel_bo *bo, int used)
371 {
372 void *ptr;
373
374 if (!winsys->decode) {
375 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
376 if (!winsys->decode)
377 return;
378
379 /* debug_printf()/debug_error() uses stderr by default */
380 drm_intel_decode_set_output_file(winsys->decode, stderr);
381 }
382
383 ptr = intel_bo_map(bo, false);
384 if (!ptr) {
385 debug_printf("failed to map buffer for decoding\n");
386 return;
387 }
388
389 /* in dwords */
390 used /= 4;
391
392 drm_intel_decode_set_batch_pointer(winsys->decode,
393 ptr, gem_bo(bo)->offset64, used);
394
395 drm_intel_decode(winsys->decode);
396
397 intel_bo_unmap(bo);
398 }
399
400 void
401 intel_bo_reference(struct intel_bo *bo)
402 {
403 drm_intel_bo_reference(gem_bo(bo));
404 }
405
406 void
407 intel_bo_unreference(struct intel_bo *bo)
408 {
409 drm_intel_bo_unreference(gem_bo(bo));
410 }
411
412 void *
413 intel_bo_map(struct intel_bo *bo, bool write_enable)
414 {
415 int err;
416
417 err = drm_intel_bo_map(gem_bo(bo), write_enable);
418 if (err) {
419 debug_error("failed to map bo");
420 return NULL;
421 }
422
423 return gem_bo(bo)->virtual;
424 }
425
426 void *
427 intel_bo_map_gtt(struct intel_bo *bo)
428 {
429 int err;
430
431 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
432 if (err) {
433 debug_error("failed to map bo");
434 return NULL;
435 }
436
437 return gem_bo(bo)->virtual;
438 }
439
440 void *
441 intel_bo_map_unsynchronized(struct intel_bo *bo)
442 {
443 int err;
444
445 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
446 if (err) {
447 debug_error("failed to map bo");
448 return NULL;
449 }
450
451 return gem_bo(bo)->virtual;
452 }
453
454 void
455 intel_bo_unmap(struct intel_bo *bo)
456 {
457 int err;
458
459 err = drm_intel_bo_unmap(gem_bo(bo));
460 assert(!err);
461 }
462
463 int
464 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
465 unsigned long size, const void *data)
466 {
467 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
468 }
469
470 int
471 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
472 unsigned long size, void *data)
473 {
474 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
475 }
476
477 int
478 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
479 struct intel_bo *target_bo, uint32_t target_offset,
480 uint32_t read_domains, uint32_t write_domain,
481 uint64_t *presumed_offset)
482 {
483 int err;
484
485 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
486 gem_bo(target_bo), target_offset,
487 read_domains, write_domain);
488
489 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
490
491 return err;
492 }
493
494 int
495 intel_bo_get_reloc_count(struct intel_bo *bo)
496 {
497 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
498 }
499
500 void
501 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
502 {
503 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
504 }
505
506 bool
507 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
508 {
509 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
510 }
511
512 int
513 intel_bo_exec(struct intel_bo *bo, int used,
514 struct intel_context *ctx, unsigned long flags)
515 {
516 if (ctx) {
517 return drm_intel_gem_bo_context_exec(gem_bo(bo),
518 (drm_intel_context *) ctx, used, flags);
519 }
520 else {
521 return drm_intel_bo_mrb_exec(gem_bo(bo),
522 used, NULL, 0, 0, flags);
523 }
524 }
525
526 int
527 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
528 {
529 int err;
530
531 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
532 /* consider the bo idle on errors */
533 if (err && err != -ETIME)
534 err = 0;
535
536 return err;
537 }