diff options
author | Imre Deak <imre.deak@intel.com> | 2019-11-29 12:38:40 +0200 |
---|---|---|
committer | Imre Deak <imre.deak@intel.com> | 2019-12-09 10:29:33 +0200 |
commit | f36328e7ca04833aad3589ca3c5572aea6ce20c5 (patch) | |
tree | 9ff47f010bacff962d6e77873388c3dfbc17b638 /lib/intel_aux_pgtable.c | |
parent | b7f06455df8cb912b44edc9663994daf7a1e3e15 (diff) |
lib: Move aux pgtable state prepare/emit to intel_aux_pgtable.c
The AUX pagetables need to be set up for blits using the vebox engine
too, so move the related helper functions to intel_aux_pgtable.c.
Cc: Mika Kahola <mika.kahola@intel.com>
Cc: Brian Welty <brian.welty@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Mika Kahola <mika.kahola@intel.com>
Diffstat (limited to 'lib/intel_aux_pgtable.c')
-rw-r--r-- | lib/intel_aux_pgtable.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/intel_aux_pgtable.c b/lib/intel_aux_pgtable.c index ea909ec02..319b27450 100644 --- a/lib/intel_aux_pgtable.c +++ b/lib/intel_aux_pgtable.c @@ -370,3 +370,201 @@ intel_aux_pgtable_create(drm_intel_bufmgr *bufmgr, return pgt_bo; } + +static void +aux_pgtable_find_max_free_range(const struct igt_buf **bufs, int buf_count, + uint64_t *range_start, uint64_t *range_size) +{ + /* + * Keep the first page reserved, so we can differentiate pinned + * objects based on a non-NULL offset. + */ + uint64_t start = 0x1000; + /* For now alloc only from the first 4GB address space. */ + const uint64_t end = 1ULL << 32; + uint64_t max_range_start = 0; + uint64_t max_range_size = 0; + int i; + + for (i = 0; i < buf_count; i++) { + if (bufs[i]->bo->offset64 >= end) + break; + + if (bufs[i]->bo->offset64 - start > max_range_size) { + max_range_start = start; + max_range_size = bufs[i]->bo->offset64 - start; + } + start = bufs[i]->bo->offset64 + bufs[i]->bo->size; + } + + if (start < end && end - start > max_range_size) { + max_range_start = start; + max_range_size = end - start; + } + + *range_start = max_range_start; + *range_size = max_range_size; +} + +static uint64_t +aux_pgtable_find_free_range(const struct igt_buf **bufs, int buf_count, + uint32_t size) +{ + uint64_t range_start; + uint64_t range_size; + /* A compressed surface must be 64kB aligned. */ + const uint32_t align = 0x10000; + int pad; + + aux_pgtable_find_max_free_range(bufs, buf_count, + &range_start, &range_size); + + pad = ALIGN(range_start, align) - range_start; + range_start += pad; + range_size -= pad; + igt_assert(range_size >= size); + + return range_start + + ALIGN_DOWN(rand() % ((range_size - size) + 1), align); +} + +static void +aux_pgtable_reserve_range(const struct igt_buf **bufs, int buf_count, + const struct igt_buf *new_buf) +{ + int i; + + if (new_buf->aux.stride) { + uint64_t pin_offset = new_buf->bo->offset64; + + if (!pin_offset) + pin_offset = aux_pgtable_find_free_range(bufs, + buf_count, + new_buf->bo->size); + drm_intel_bo_set_softpin_offset(new_buf->bo, pin_offset); + igt_assert(new_buf->bo->offset64 == pin_offset); + } + + for (i = 0; i < buf_count; i++) + if (bufs[i]->bo->offset64 > new_buf->bo->offset64) + break; + + memmove(&bufs[i + 1], &bufs[i], sizeof(bufs[0]) * (buf_count - i)); + + bufs[i] = new_buf; +} + +void +gen12_aux_pgtable_init(struct aux_pgtable_info *info, + drm_intel_bufmgr *bufmgr, + const struct igt_buf *src_buf, + const struct igt_buf *dst_buf) +{ + const struct igt_buf *bufs[2]; + const struct igt_buf *reserved_bufs[2]; + int reserved_buf_count; + int i; + + if (!src_buf->aux.stride && !dst_buf->aux.stride) + return; + + bufs[0] = src_buf; + bufs[1] = dst_buf; + + /* + * Ideally we'd need an IGT-wide GFX address space allocator, which + * would consider all allocations and thus avoid evictions. For now use + * a simpler scheme here, which only considers the buffers involved in + * the blit, which should at least minimize the chance for evictions + * in the case of subsequent blits: + * 1. If they were already bound (bo->offset64 != 0), use this + * address. + * 2. Pick a range randomly from the 4GB address space, that is not + * already occupied by a bound object, or an object we pinned. + */ + reserved_buf_count = 0; + /* First reserve space for any bufs that are bound already. */ + for (i = 0; i < ARRAY_SIZE(bufs); i++) + if (bufs[i]->bo->offset64) + aux_pgtable_reserve_range(reserved_bufs, + reserved_buf_count++, + bufs[i]); + + /* Next, reserve space for unbound bufs with an AUX surface. */ + for (i = 0; i < ARRAY_SIZE(bufs); i++) + if (!bufs[i]->bo->offset64 && bufs[i]->aux.stride) + aux_pgtable_reserve_range(reserved_bufs, + reserved_buf_count++, + bufs[i]); + + /* Create AUX pgtable entries only for bufs with an AUX surface */ + info->buf_count = 0; + for (i = 0; i < reserved_buf_count; i++) { + if (!reserved_bufs[i]->aux.stride) + continue; + + info->bufs[info->buf_count] = reserved_bufs[i]; + info->buf_pin_offsets[info->buf_count] = + reserved_bufs[i]->bo->offset64; + info->buf_count++; + } + + info->pgtable_bo = intel_aux_pgtable_create(bufmgr, + info->bufs, + info->buf_count); + igt_assert(info->pgtable_bo); +} + +void +gen12_aux_pgtable_cleanup(struct aux_pgtable_info *info) +{ + int i; + + /* Check that the pinned bufs kept their offset after the exec. */ + for (i = 0; i < info->buf_count; i++) + igt_assert_eq_u64(info->bufs[i]->bo->offset64, + info->buf_pin_offsets[i]); + + drm_intel_bo_unreference(info->pgtable_bo); +} + +uint32_t +gen12_create_aux_pgtable_state(struct intel_batchbuffer *batch, + drm_intel_bo *aux_pgtable_bo) +{ + uint64_t *pgtable_ptr; + uint32_t pgtable_ptr_offset; + int ret; + + if (!aux_pgtable_bo) + return 0; + + pgtable_ptr = intel_batchbuffer_subdata_alloc(batch, + sizeof(*pgtable_ptr), + sizeof(*pgtable_ptr)); + pgtable_ptr_offset = intel_batchbuffer_subdata_offset(batch, + pgtable_ptr); + + *pgtable_ptr = aux_pgtable_bo->offset64; + ret = drm_intel_bo_emit_reloc(batch->bo, pgtable_ptr_offset, + aux_pgtable_bo, 0, + 0, 0); + assert(ret == 0); + + return pgtable_ptr_offset; +} + +void +gen12_emit_aux_pgtable_state(struct intel_batchbuffer *batch, uint32_t state) +{ + if (!state) + return; + + OUT_BATCH(MI_LOAD_REGISTER_MEM_GEN8); + OUT_BATCH(GEN12_GFX_AUX_TABLE_BASE_ADDR); + OUT_RELOC(batch->bo, 0, 0, state); + + OUT_BATCH(MI_LOAD_REGISTER_MEM_GEN8); + OUT_BATCH(GEN12_GFX_AUX_TABLE_BASE_ADDR + 4); + OUT_RELOC(batch->bo, 0, 0, state + 4); +} |