2 * Mesa 3-D graphics library
4 * Copyright (C) 2012-2014 LunarG, Inc.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Chia-I Wu <olv@lunarg.com>
31 #define ETIME ETIMEDOUT
36 #include <intel_bufmgr.h>
38 #include "os/os_thread.h"
39 #include "state_tracker/drm_driver.h"
40 #include "pipe/p_state.h"
41 #include "util/u_inlines.h"
42 #include "util/u_memory.h"
43 #include "util/u_debug.h"
44 #include "ilo/core/intel_winsys.h"
45 #include "intel_drm_public.h"
49 drm_intel_bufmgr
*bufmgr
;
50 struct intel_winsys_info info
;
52 /* these are protected by the mutex */
54 drm_intel_context
*first_gem_ctx
;
55 struct drm_intel_decode
*decode
;
58 static drm_intel_context
*
59 gem_ctx(const struct intel_context
*ctx
)
61 return (drm_intel_context
*) ctx
;
65 gem_bo(const struct intel_bo
*bo
)
67 return (drm_intel_bo
*) bo
;
71 get_param(struct intel_winsys
*winsys
, int param
, int *value
)
73 struct drm_i915_getparam gp
;
78 memset(&gp
, 0, sizeof(gp
));
82 err
= drmCommandWriteRead(winsys
->fd
, DRM_I915_GETPARAM
, &gp
, sizeof(gp
));
92 test_address_swizzling(struct intel_winsys
*winsys
)
95 uint32_t tiling
= I915_TILING_X
, swizzle
;
98 bo
= drm_intel_bo_alloc_tiled(winsys
->bufmgr
,
99 "address swizzling test", 64, 64, 4, &tiling
, &pitch
, 0);
101 drm_intel_bo_get_tiling(bo
, &tiling
, &swizzle
);
102 drm_intel_bo_unreference(bo
);
105 swizzle
= I915_BIT_6_SWIZZLE_NONE
;
108 return (swizzle
!= I915_BIT_6_SWIZZLE_NONE
);
112 test_reg_read(struct intel_winsys
*winsys
, uint32_t reg
)
116 return !drm_intel_reg_read(winsys
->bufmgr
, reg
, &dummy
);
120 probe_winsys(struct intel_winsys
*winsys
)
122 struct intel_winsys_info
*info
= &winsys
->info
;
126 * When we need the Nth vertex from a user vertex buffer, and the vertex is
127 * uploaded to, say, the beginning of a bo, we want the first vertex in the
128 * bo to be fetched. One way to do this is to set the base address of the
131 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
133 * The second term may be negative, and we need kernel support to do that.
135 * This check is taken from the classic driver. u_vbuf_upload_buffers()
136 * guarantees the term is never negative, but it is good to require a
139 get_param(winsys
, I915_PARAM_HAS_RELAXED_DELTA
, &val
);
141 debug_error("kernel 2.6.39 required");
145 info
->devid
= drm_intel_bufmgr_gem_get_devid(winsys
->bufmgr
);
147 if (drm_intel_get_aperture_sizes(winsys
->fd
,
148 &info
->aperture_mappable
, &info
->aperture_total
)) {
149 debug_error("failed to query aperture sizes");
153 get_param(winsys
, I915_PARAM_HAS_LLC
, &val
);
155 info
->has_address_swizzling
= test_address_swizzling(winsys
);
157 winsys
->first_gem_ctx
= drm_intel_gem_context_create(winsys
->bufmgr
);
158 info
->has_logical_context
= (winsys
->first_gem_ctx
!= NULL
);
160 get_param(winsys
, I915_PARAM_HAS_ALIASING_PPGTT
, &val
);
161 info
->has_ppgtt
= val
;
163 /* test TIMESTAMP read */
164 info
->has_timestamp
= test_reg_read(winsys
, 0x2358);
166 get_param(winsys
, I915_PARAM_HAS_GEN7_SOL_RESET
, &val
);
167 info
->has_gen7_sol_reset
= val
;
172 struct intel_winsys
*
173 intel_winsys_create_for_fd(int fd
)
175 /* so that we can have enough (up to 4094) relocs per bo */
176 const int batch_size
= sizeof(uint32_t) * 8192;
177 struct intel_winsys
*winsys
;
179 winsys
= CALLOC_STRUCT(intel_winsys
);
185 winsys
->bufmgr
= drm_intel_bufmgr_gem_init(winsys
->fd
, batch_size
);
186 if (!winsys
->bufmgr
) {
187 debug_error("failed to create GEM buffer manager");
192 pipe_mutex_init(winsys
->mutex
);
194 if (!probe_winsys(winsys
)) {
195 pipe_mutex_destroy(winsys
->mutex
);
196 drm_intel_bufmgr_destroy(winsys
->bufmgr
);
202 * No need to implicitly set up a fence register for each non-linear reloc
203 * entry. INTEL_RELOC_FENCE will be set on reloc entries that need them.
205 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys
->bufmgr
);
207 drm_intel_bufmgr_gem_enable_reuse(winsys
->bufmgr
);
213 intel_winsys_destroy(struct intel_winsys
*winsys
)
216 drm_intel_decode_context_free(winsys
->decode
);
218 if (winsys
->first_gem_ctx
)
219 drm_intel_gem_context_destroy(winsys
->first_gem_ctx
);
221 pipe_mutex_destroy(winsys
->mutex
);
222 drm_intel_bufmgr_destroy(winsys
->bufmgr
);
226 const struct intel_winsys_info
*
227 intel_winsys_get_info(const struct intel_winsys
*winsys
)
229 return &winsys
->info
;
232 struct intel_context
*
233 intel_winsys_create_context(struct intel_winsys
*winsys
)
235 drm_intel_context
*gem_ctx
;
237 /* try the preallocated context first */
238 pipe_mutex_lock(winsys
->mutex
);
239 gem_ctx
= winsys
->first_gem_ctx
;
240 winsys
->first_gem_ctx
= NULL
;
241 pipe_mutex_unlock(winsys
->mutex
);
244 gem_ctx
= drm_intel_gem_context_create(winsys
->bufmgr
);
246 return (struct intel_context
*) gem_ctx
;
250 intel_winsys_destroy_context(struct intel_winsys
*winsys
,
251 struct intel_context
*ctx
)
253 drm_intel_gem_context_destroy(gem_ctx(ctx
));
257 intel_winsys_read_reg(struct intel_winsys
*winsys
,
258 uint32_t reg
, uint64_t *val
)
260 return drm_intel_reg_read(winsys
->bufmgr
, reg
, val
);
264 intel_winsys_get_reset_stats(struct intel_winsys
*winsys
,
265 struct intel_context
*ctx
,
266 uint32_t *active_lost
,
267 uint32_t *pending_lost
)
269 uint32_t reset_count
;
271 return drm_intel_get_reset_stats(gem_ctx(ctx
),
272 &reset_count
, active_lost
, pending_lost
);
276 intel_winsys_alloc_bo(struct intel_winsys
*winsys
,
281 const unsigned int alignment
= 4096; /* always page-aligned */
285 bo
= drm_intel_bo_alloc(winsys
->bufmgr
, name
, size
, alignment
);
287 bo
= drm_intel_bo_alloc_for_render(winsys
->bufmgr
,
288 name
, size
, alignment
);
291 return (struct intel_bo
*) bo
;
295 intel_winsys_import_userptr(struct intel_winsys
*winsys
,
305 intel_winsys_import_handle(struct intel_winsys
*winsys
,
307 const struct winsys_handle
*handle
,
308 unsigned long height
,
309 enum intel_tiling_mode
*tiling
,
310 unsigned long *pitch
)
312 uint32_t real_tiling
, swizzle
;
316 if (handle
->offset
!= 0) {
317 debug_error("attempt to import unsupported winsys offset");
321 switch (handle
->type
) {
322 case DRM_API_HANDLE_TYPE_SHARED
:
324 const uint32_t gem_name
= handle
->handle
;
325 bo
= drm_intel_bo_gem_create_from_name(winsys
->bufmgr
,
329 case DRM_API_HANDLE_TYPE_FD
:
331 const int fd
= (int) handle
->handle
;
332 bo
= drm_intel_bo_gem_create_from_prime(winsys
->bufmgr
,
333 fd
, height
* handle
->stride
);
344 err
= drm_intel_bo_get_tiling(bo
, &real_tiling
, &swizzle
);
346 drm_intel_bo_unreference(bo
);
350 *tiling
= real_tiling
;
351 *pitch
= handle
->stride
;
353 return (struct intel_bo
*) bo
;
357 intel_winsys_export_handle(struct intel_winsys
*winsys
,
359 enum intel_tiling_mode tiling
,
361 unsigned long height
,
362 struct winsys_handle
*handle
)
366 switch (handle
->type
) {
367 case DRM_API_HANDLE_TYPE_SHARED
:
371 err
= drm_intel_bo_flink(gem_bo(bo
), &name
);
373 handle
->handle
= name
;
376 case DRM_API_HANDLE_TYPE_KMS
:
377 handle
->handle
= gem_bo(bo
)->handle
;
379 case DRM_API_HANDLE_TYPE_FD
:
383 err
= drm_intel_bo_gem_export_to_prime(gem_bo(bo
), &fd
);
396 handle
->stride
= pitch
;
402 intel_winsys_can_submit_bo(struct intel_winsys
*winsys
,
403 struct intel_bo
**bo_array
,
406 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo
**) bo_array
,
411 intel_winsys_submit_bo(struct intel_winsys
*winsys
,
412 enum intel_ring_type ring
,
413 struct intel_bo
*bo
, int used
,
414 struct intel_context
*ctx
,
417 const unsigned long exec_flags
= (unsigned long) ring
| flags
;
419 /* logical contexts are only available for the render ring */
420 if (ring
!= INTEL_RING_RENDER
)
424 return drm_intel_gem_bo_context_exec(gem_bo(bo
),
425 (drm_intel_context
*) ctx
, used
, exec_flags
);
428 return drm_intel_bo_mrb_exec(gem_bo(bo
),
429 used
, NULL
, 0, 0, exec_flags
);
434 intel_winsys_decode_bo(struct intel_winsys
*winsys
,
435 struct intel_bo
*bo
, int used
)
439 ptr
= intel_bo_map(bo
, false);
441 debug_printf("failed to map buffer for decoding\n");
445 pipe_mutex_lock(winsys
->mutex
);
447 if (!winsys
->decode
) {
448 winsys
->decode
= drm_intel_decode_context_alloc(winsys
->info
.devid
);
449 if (!winsys
->decode
) {
450 pipe_mutex_unlock(winsys
->mutex
);
455 /* debug_printf()/debug_error() uses stderr by default */
456 drm_intel_decode_set_output_file(winsys
->decode
, stderr
);
462 drm_intel_decode_set_batch_pointer(winsys
->decode
,
463 ptr
, gem_bo(bo
)->offset64
, used
);
465 drm_intel_decode(winsys
->decode
);
467 pipe_mutex_unlock(winsys
->mutex
);
473 intel_bo_ref(struct intel_bo
*bo
)
476 drm_intel_bo_reference(gem_bo(bo
));
482 intel_bo_unref(struct intel_bo
*bo
)
485 drm_intel_bo_unreference(gem_bo(bo
));
489 intel_bo_set_tiling(struct intel_bo
*bo
,
490 enum intel_tiling_mode tiling
,
493 uint32_t real_tiling
= tiling
;
509 err
= drm_intel_bo_set_tiling(gem_bo(bo
), &real_tiling
, pitch
);
510 if (err
|| real_tiling
!= tiling
) {
511 assert(!"tiling mismatch");
519 intel_bo_map(struct intel_bo
*bo
, bool write_enable
)
523 err
= drm_intel_bo_map(gem_bo(bo
), write_enable
);
525 debug_error("failed to map bo");
529 return gem_bo(bo
)->virtual;
533 intel_bo_map_async(struct intel_bo
*bo
)
539 intel_bo_map_gtt(struct intel_bo
*bo
)
543 err
= drm_intel_gem_bo_map_gtt(gem_bo(bo
));
545 debug_error("failed to map bo");
549 return gem_bo(bo
)->virtual;
553 intel_bo_map_gtt_async(struct intel_bo
*bo
)
557 err
= drm_intel_gem_bo_map_unsynchronized(gem_bo(bo
));
559 debug_error("failed to map bo");
563 return gem_bo(bo
)->virtual;
567 intel_bo_unmap(struct intel_bo
*bo
)
571 err
= drm_intel_bo_unmap(gem_bo(bo
));
576 intel_bo_pwrite(struct intel_bo
*bo
, unsigned long offset
,
577 unsigned long size
, const void *data
)
579 return drm_intel_bo_subdata(gem_bo(bo
), offset
, size
, data
);
583 intel_bo_pread(struct intel_bo
*bo
, unsigned long offset
,
584 unsigned long size
, void *data
)
586 return drm_intel_bo_get_subdata(gem_bo(bo
), offset
, size
, data
);
590 intel_bo_add_reloc(struct intel_bo
*bo
, uint32_t offset
,
591 struct intel_bo
*target_bo
, uint32_t target_offset
,
592 uint32_t flags
, uint64_t *presumed_offset
)
594 uint32_t read_domains
, write_domain
;
597 if (flags
& INTEL_RELOC_WRITE
) {
599 * Because of the translation to domains, INTEL_RELOC_GGTT should only
600 * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL. The
601 * kernel will translate it back to INTEL_RELOC_GGTT.
603 write_domain
= (flags
& INTEL_RELOC_GGTT
) ?
604 I915_GEM_DOMAIN_INSTRUCTION
: I915_GEM_DOMAIN_RENDER
;
605 read_domains
= write_domain
;
608 read_domains
= I915_GEM_DOMAIN_RENDER
|
609 I915_GEM_DOMAIN_SAMPLER
|
610 I915_GEM_DOMAIN_INSTRUCTION
|
611 I915_GEM_DOMAIN_VERTEX
;
614 if (flags
& INTEL_RELOC_FENCE
) {
615 err
= drm_intel_bo_emit_reloc_fence(gem_bo(bo
), offset
,
616 gem_bo(target_bo
), target_offset
,
617 read_domains
, write_domain
);
619 err
= drm_intel_bo_emit_reloc(gem_bo(bo
), offset
,
620 gem_bo(target_bo
), target_offset
,
621 read_domains
, write_domain
);
624 *presumed_offset
= gem_bo(target_bo
)->offset64
+ target_offset
;
630 intel_bo_get_reloc_count(struct intel_bo
*bo
)
632 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo
));
636 intel_bo_truncate_relocs(struct intel_bo
*bo
, int start
)
638 drm_intel_gem_bo_clear_relocs(gem_bo(bo
), start
);
642 intel_bo_has_reloc(struct intel_bo
*bo
, struct intel_bo
*target_bo
)
644 return drm_intel_bo_references(gem_bo(bo
), gem_bo(target_bo
));
648 intel_bo_wait(struct intel_bo
*bo
, int64_t timeout
)
653 err
= drm_intel_gem_bo_wait(gem_bo(bo
), timeout
);
655 drm_intel_bo_wait_rendering(gem_bo(bo
));
659 /* consider the bo idle on errors */
660 if (err
&& err
!= -ETIME
)