diff --git a/helpers.c b/helpers.c index f648d5a4..9d791ea1 100644 --- a/helpers.c +++ b/helpers.c @@ -651,3 +651,40 @@ bool drv_has_modifier(const uint64_t *list, uint32_t count, uint64_t modifier) return false; } + +const u_int16_t ytile_width = 16; +const u_int16_t ytile_heigth = 32; +void one_ytile_to_linear(char *src, char *dst, u_int16_t x, u_int16_t y, u_int16_t width, u_int16_t height, u_int16_t offset) +{ + // x and y follow linear + u_int32_t count = x + y * width/ytile_width; + + for (int j = 0; j < ytile_width * ytile_heigth; j += ytile_width) { + memcpy(dst + offset + width * ytile_heigth * y + width * j / ytile_width + x * ytile_width, + src + offset + j + ytile_width * ytile_heigth * count, ytile_width); + } +} + +void * ytiled_to_linear(struct bo_metadata meta, void * src) +{ + void* dst = malloc(meta.total_size); + if (NULL == dst) return NULL; + + memset(dst, 0, meta.total_size); + + u_int16_t height = meta.sizes[0] / meta.strides[0]; + // Y + for (u_int16_t x = 0; x < meta.strides[0]/ytile_width; x++) { + for (u_int16_t y = 0; y < height/ytile_heigth; y++) { + one_ytile_to_linear(src, dst, x, y, meta.strides[0], height, 0); + } + } + // UV + for (u_int16_t x = 0; x < meta.strides[0]/ytile_width; x++) { + for (u_int16_t y = 0; y < ceil((double)height/ytile_heigth/2); y++) { + one_ytile_to_linear(src, dst, x, y, meta.strides[0], height, meta.sizes[0]); + } + } + + return dst; +} diff --git a/helpers.h b/helpers.h index 19d0fd74..e6c8e9bd 100644 --- a/helpers.h +++ b/helpers.h @@ -7,6 +7,7 @@ #ifndef HELPERS_H #define HELPERS_H +#include #include #include "drv.h" @@ -42,4 +43,8 @@ int drv_modify_linear_combinations(struct driver *drv); uint64_t drv_pick_modifier(const uint64_t *modifiers, uint32_t count, const uint64_t *modifier_order, uint32_t order_count); bool drv_has_modifier(const uint64_t *list, uint32_t count, uint64_t modifier); + +void one_ytile_to_linear(char *src, char *dst, u_int16_t x, u_int16_t y, + u_int16_t width, u_int16_t height, u_int16_t offset); +void *ytiled_to_linear(struct bo_metadata meta, void * src); #endif diff --git a/i915.c b/i915.c index 9c68d5c0..e6732376 100644 --- a/i915.c +++ b/i915.c @@ -967,6 +967,16 @@ static void *i915_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t /* And map it */ addr = mmap(0, bo->meta.total_size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->drv->fd, mmap_arg.offset); + + // TODO: GEM_MMAP_OFFSET cannot convert ytiled to linear, we have to convert it manually. + void* tmp_addr = ytiled_to_linear(bo->meta, addr); + + if (NULL != tmp_addr) { + // XXX: The releasing address when unmap is the one returned by mmap. + // So we need to copy data back to addr. + memcpy(addr, tmp_addr, bo->meta.total_size); + free(tmp_addr); + } } else if (bo->meta.tiling == I915_TILING_NONE) { struct drm_i915_gem_mmap gem_map; memset(&gem_map, 0, sizeof(gem_map));