[igt-dev] [PATCH i-g-t v2 1/2] lib/intel_bufops: Introduce buffer operations

Zbigniew Kempczyński
2019-12-01T19:09:50Z

Different GENs supports different tile surfaces. Older GENs
have HW fences to allow X / Y surface tiling / detiling.
Newer GENs have to tile / detile such surface in software.

To make test developer life easier this code adds buffer
operations (short bufops) to use appropriate functions allowing
copying linear buffer to BO and from BO to linear buffer
regardless GPU generation and tiling within BO. For GENs having
fences support preference is to use them if they are available
(X / Y tiling is probed on bufops initalization).

Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Katarzyna Dec <katarzyna.dec@intel.com>
---
lib/Makefile.sources | 2 +
lib/intel_bufops.c | 689 +++++++++++++++++++++++++++++++++++++++++++
lib/intel_bufops.h | 24 ++
lib/meson.build | 1 +
4 files changed, 716 insertions(+)
create mode 100644 lib/intel_bufops.c
create mode 100644 lib/intel_bufops.h

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 9d1a4e06..b808f294 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -65,6 +65,8 @@ lib_source_list = \
intel_aub.h \
intel_batchbuffer.c \
intel_batchbuffer.h \
+ intel_bufops.c \
+ intel_bufops.h \
intel_chipset.c \
intel_chipset.h \
intel_device_info.c \
diff --git a/lib/intel_bufops.c b/lib/intel_bufops.c
new file mode 100644
index 00000000..fdb8bdc7
--- /dev/null
+++ b/lib/intel_bufops.c
@@ -0,0 +1,689 @@
+#include <sys/ioctl.h>
+#include "igt.h"
+#include "igt_x86.h"
+#include "intel_bufops.h"
+
+#define TILE_NONE (1 << I915_TILING_NONE)
+#define TILE_X (1 << I915_TILING_X)
+#define TILE_Y (1 << I915_TILING_Y)
+#define TILE_Yf (1 << I915_TILING_Yf)
+#define TILE_Ys (1 << I915_TILING_Ys)
+
+typedef void (*bo_copy)(int, struct igt_buf *, uint32_t *);
+
+struct buf_ops {
+ int fd;
+ drm_intel_bufmgr *bufmgr;
+ int gen_start;
+ int gen_end;
+ int intel_gen;
+ uint32_t supported_tiles;
+ uint32_t hw_tiles;
+ bo_copy linear_to;
+ bo_copy linear_to_x;
+ bo_copy linear_to_y;
+ bo_copy linear_to_yf;
+ bo_copy linear_to_ys;
+ bo_copy to_linear;
+ bo_copy x_to_linear;
+ bo_copy y_to_linear;
+ bo_copy yf_to_linear;
+ bo_copy ys_to_linear;
+};
+
+static void *x_ptr(void *ptr,
+ unsigned int x, unsigned int y,
+ unsigned int stride, unsigned int cpp)
+{
+ const int tile_width = 512;
+ const int tile_height = 8;
+ const int tile_size = tile_width * tile_height;
+ int tile_x, tile_y;
+ int offset_x, offset_y, pos;
+
+ x *= cpp;
+ tile_x = x / tile_width;
+ tile_y = y / tile_height;
+ offset_x = (tile_x * tile_size);
+ offset_y = (tile_y * stride * tile_height);
+
+ pos = offset_y + offset_x +
+ (y % tile_height * tile_width) + (x % tile_width);
+
+ return ptr + pos;
+}
+
+static void *y_ptr(void *ptr,
+ unsigned int x, unsigned int y,
+ unsigned int stride, unsigned int cpp)
+{
+ const int tile_width = 128;
+ const int tile_height = 32;
+ const int owords = 16;
+ const int tile_size = tile_width * tile_height;
+ int tile_x, tile_y;
+ int offset_x, offset_y, pos;
+ int shift_x, shift_y;
+
+ x *= cpp;
+ tile_x = x / tile_width;
+ tile_y = y / tile_height;
+ offset_x = tile_x * tile_size;
+ offset_y = tile_y * stride * tile_height;
+ shift_x = x % owords + (x % tile_width) / owords * tile_width * cpp;
+ shift_y = y % tile_height * owords;
+
+ pos = offset_y + offset_x + shift_x + shift_y;
+
+ return ptr + pos;
+}
+
+static void *yf_ptr(void *ptr,
+ unsigned int x, unsigned int y,
+ unsigned int stride, unsigned int cpp)
+{
+ const int tile_size = 4 * 1024;
+ const int tile_width = 128;
+ int row_size = (stride / tile_width) * tile_size;
+
+ x *= cpp; /* convert to Byte offset */
+
+
+ /*
+ * Within a 4k Yf tile, the byte swizzling pattern is
+ * msb......lsb
+ * xyxyxyyyxxxx
+ * The tiles themselves are laid out in row major order.
+ */
+ return ptr +
+ ((x & 0xf) * 1) + /* 4x1 pixels(32bpp) = 16B */
+ ((y & 0x3) * 16) + /* 4x4 pixels = 64B */
+ (((y & 0x4) >> 2) * 64) + /* 1x2 64B blocks */
+ (((x & 0x10) >> 4) * 128) + /* 2x2 64B blocks = 256B block */
+ (((y & 0x8) >> 3) * 256) + /* 2x1 256B blocks */
+ (((x & 0x20) >> 5) * 512) + /* 2x2 256B blocks */
+ (((y & 0x10) >> 4) * 1024) + /* 4x2 256 blocks */
+ (((x & 0x40) >> 6) * 2048) + /* 4x4 256B blocks = 4k tile */
+ (((x & ~0x7f) >> 7) * tile_size) + /* row of tiles */
+ (((y & ~0x1f) >> 5) * row_size);
+}
+
+typedef void *(*fn_ptr)(void *, unsigned int, unsigned int,
+ unsigned int, unsigned int);
+static fn_ptr __get_tile_fn_ptr(int tiling)
+{
+ fn_ptr fn = NULL;
+
+ switch (tiling) {
+ case I915_TILING_X:
+ fn = x_ptr;
+ break;
+ case I915_TILING_Y:
+ fn = y_ptr;
+ break;
+ case I915_TILING_Yf:
+ fn = yf_ptr;
+ break;
+ case I915_TILING_Ys:
+ /* To be implemented */
+ break;
+ }
+
+ igt_assert_f(fn, "Can't find tile function for tiling: %d\n", tiling);
+
+ return fn;
+}
+
+static void __copy_linear_to(int fd, struct igt_buf *buf,
+ const uint32_t *linear, int tiling)
+{
+ int height = igt_buf_height(buf);
+ int width = igt_buf_width(buf);
+ fn_ptr fn = __get_tile_fn_ptr(tiling);
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+ map = gem_mmap__cpu(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ | PROT_WRITE);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ uint32_t *ptr = fn(map, x, y,
+ buf->stride, buf->bpp / 8);
+
+ *ptr = linear[y * width + x];
+ }
+ }
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_linear_to_x(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_linear_to(fd, buf, linear, I915_TILING_X);
+}
+
+static void copy_linear_to_y(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_linear_to(fd, buf, linear, I915_TILING_Y);
+}
+
+static void copy_linear_to_yf(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_linear_to(fd, buf, linear, I915_TILING_Yf);
+}
+
+static void __copy_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear, int tiling)
+{
+ int height = igt_buf_height(buf);
+ int width = igt_buf_width(buf);
+ fn_ptr fn = __get_tile_fn_ptr(tiling);
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_CPU, 0);
+ map = gem_mmap__cpu(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ uint32_t *ptr = fn(map, x, y,
+ buf->stride, buf->bpp / 8);
+
+ linear[y * width + x] = *ptr;
+ }
+ }
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_yf_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_to_linear(fd, buf, linear, I915_TILING_Yf);
+}
+
+static void copy_x_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_to_linear(fd, buf, linear, I915_TILING_X);
+}
+
+static void copy_y_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ __copy_to_linear(fd, buf, linear, I915_TILING_Y);
+}
+
+static void copy_linear_to_gtt(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+ map = gem_mmap__gtt(fd, buf->bo->handle,
+ buf->bo->size, PROT_READ | PROT_WRITE);
+
+ memcpy(map, linear, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_gtt_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_GTT, 0);
+
+ map = gem_mmap__gtt(fd, buf->bo->handle,
+ buf->bo->size, PROT_READ);
+
+ igt_memcpy_from_wc(linear, map, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_linear_to_wc(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+ map = gem_mmap__wc(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ | PROT_WRITE);
+
+ memcpy(map, linear, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_wc_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_GTT, 0);
+
+ map = gem_mmap__wc(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ);
+
+ igt_memcpy_from_wc(linear, map, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_linear_to_cpu(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+
+ map = gem_mmap__cpu(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ | PROT_WRITE);
+
+ memcpy(map, linear, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+static void copy_cpu_to_linear(int fd, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ void *map;
+
+ gem_set_domain(fd, buf->bo->handle,
+ I915_GEM_DOMAIN_CPU, 0);
+
+ map = gem_mmap__cpu(fd, buf->bo->handle, 0,
+ buf->bo->size, PROT_READ);
+
+ memcpy(linear, map, buf->bo->size);
+
+ munmap(map, buf->bo->size);
+}
+
+void copy_buf_to_linear(struct buf_ops *bops, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ igt_assert(bops);
+
+ switch (buf->tiling) {
+ case I915_TILING_NONE:
+ igt_assert(bops->to_linear);
+ bops->to_linear(bops->fd, buf, linear);
+ break;
+ case I915_TILING_X:
+ igt_assert(bops->x_to_linear);
+ bops->x_to_linear(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Y:
+ igt_assert(bops->y_to_linear);
+ bops->y_to_linear(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Yf:
+ igt_assert(bops->yf_to_linear);
+ bops->yf_to_linear(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Ys:
+ igt_assert(bops->ys_to_linear);
+ bops->ys_to_linear(bops->fd, buf, linear);
+ break;
+ }
+}
+
+void copy_linear_to_buf(struct buf_ops *bops, struct igt_buf *buf,
+ uint32_t *linear)
+{
+ igt_assert(bops);
+
+ switch (buf->tiling) {
+ case I915_TILING_NONE:
+ igt_assert(bops->linear_to);
+ bops->linear_to(bops->fd, buf, linear);
+ break;
+ case I915_TILING_X:
+ igt_assert(bops->linear_to_x);
+ bops->linear_to_x(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Y:
+ igt_assert(bops->linear_to_y);
+ bops->linear_to_y(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Yf:
+ igt_assert(bops->linear_to_yf);
+ bops->linear_to_yf(bops->fd, buf, linear);
+ break;
+ case I915_TILING_Ys:
+ igt_assert(bops->linear_to_ys);
+ bops->linear_to_ys(bops->fd, buf, linear);
+ break;
+ }
+}
+
+struct buf_ops buf_ops_arr[] = {
+ /* Generations 0 - 8 */
+{
+ .gen_start = 0,
+ .gen_end = 8,
+ .supported_tiles = TILE_NONE | TILE_X | TILE_Y,
+ .hw_tiles = TILE_X | TILE_Y,
+ .linear_to = copy_linear_to_cpu,
+ .linear_to_x = copy_linear_to_gtt,
+ .linear_to_y = copy_linear_to_gtt,
+ .to_linear = copy_cpu_to_linear,
+ .x_to_linear = copy_gtt_to_linear,
+ .y_to_linear = copy_gtt_to_linear,
+},
+/* Generations 9 - 11 */
+{
+ .gen_start = 9,
+ .gen_end = 11,
+ .supported_tiles = TILE_NONE | TILE_X | TILE_Y | TILE_Yf,
+ .hw_tiles = TILE_X | TILE_Y,
+ .linear_to = copy_linear_to_cpu,
+ .linear_to_x = copy_linear_to_gtt,
+ .linear_to_y = copy_linear_to_gtt,
+ .linear_to_yf = copy_linear_to_yf,
+ .to_linear = copy_cpu_to_linear,
+ .x_to_linear = copy_gtt_to_linear,
+ .y_to_linear = copy_gtt_to_linear,
+ .yf_to_linear = copy_yf_to_linear,
+},
+/* Generation 12 */
+{
+ .gen_start = 12,
+ .gen_end = 12,
+ .supported_tiles = TILE_NONE | TILE_X | TILE_Y | TILE_Yf | TILE_Ys,
+ .linear_to = copy_linear_to_wc,
+ .linear_to_x = copy_linear_to_x,
+ .linear_to_y = copy_linear_to_y,
+ .linear_to_yf = copy_linear_to_yf,
+ .linear_to_ys = NULL, /* to be implemented */
+ .to_linear = copy_wc_to_linear,
+ .x_to_linear = copy_x_to_linear,
+ .y_to_linear = copy_y_to_linear,
+ .yf_to_linear = copy_yf_to_linear,
+ .ys_to_linear = NULL, /* to be implemented */
+},
+};
+
+static int __gem_get_tiling(int fd, struct drm_i915_gem_get_tiling *arg)
+{
+ int err;
+
+ err = 0;
+ if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, arg))
+ err = -errno;
+ errno = 0;
+
+ return err;
+}
+
+static bool __get_tiling(int fd, uint32_t handle, uint32_t *tiling,
+ uint32_t *swizzle)
+{
+ struct drm_i915_gem_get_tiling get_tiling;
+
+ memset(&get_tiling, 0, sizeof(get_tiling));
+ get_tiling.handle = handle;
+
+ if (__gem_get_tiling(fd, &get_tiling) != 0)
+ return false;
+
+ *tiling = get_tiling.tiling_mode;
+ *swizzle = get_tiling.swizzle_mode;
+
+ return get_tiling.phys_swizzle_mode == get_tiling.swizzle_mode;
+}
+
+static bool probe_hw_tiling(int fd, uint32_t tiling)
+{
+ struct drm_i915_gem_set_tiling st;
+ uint64_t size = 1024 * 1024;
+ uint32_t handle, buf_tiling, buf_swizzle;
+ uint32_t stride;
+ int ret;
+ bool is_set;
+
+ if (tiling == I915_TILING_X)
+ stride = 512;
+ else if (tiling == I915_TILING_Y)
+ stride = 128;
+ else
+ return false;
+
+ handle = gem_create(fd, size);
+
+ /* Single shot, if no fences are available we fail immediately */
+ st.handle = handle;
+ st.tiling_mode = tiling;
+ st.stride = tiling ? stride : 0;
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &st);
+ if (ret)
+ goto end;
+
+ is_set = __get_tiling(fd, handle, &buf_tiling, &buf_swizzle);
+
+end:
+ gem_close(fd, handle);
+
+ return is_set;
+}
+
+struct buf_ops *buf_ops_get(int fd, drm_intel_bufmgr *bufmgr)
+{
+ struct buf_ops *bops = calloc(1, sizeof(*bops));
+ uint32_t devid;
+ int generation;
+
+ igt_assert(bufmgr);
+ igt_assert(bops);
+
+ devid = intel_get_drm_devid(fd);
+ generation = intel_gen(devid);
+
+ /* Predefined settings */
+ for (int i = 0; i < ARRAY_SIZE(buf_ops_arr); i++) {
+ if (generation >= buf_ops_arr[i].gen_start &&
+ generation <= buf_ops_arr[i].gen_end) {
+ memcpy(bops, &buf_ops_arr[i], sizeof(*bops));
+ bops->fd = fd;
+ bops->bufmgr = bufmgr;
+ bops->intel_gen = generation;
+ igt_debug("generation: %d, supported tiles: 0x%02x\n",
+ generation, bops->supported_tiles);
+ break;
+ }
+ }
+
+ /* Let's probe X and Y hw tiling support */
+ if (bops->hw_tiles & TILE_X) {
+ bool supported = probe_hw_tiling(fd, I915_TILING_X);
+
+ igt_debug("X fence support: %s\n", supported ? "yes" : "no");
+ if (!supported) {
+ bops->hw_tiles &= ~TILE_X;
+ bops->linear_to_x = copy_linear_to_x;
+ bops->x_to_linear = copy_x_to_linear;
+ }
+ }
+
+ if (bops->hw_tiles & TILE_Y) {
+ bool supported = probe_hw_tiling(fd, I915_TILING_Y);
+
+ igt_debug("Y fence support: %s\n", supported ? "yes" : "no");
+ if (!supported) {
+ bops->hw_tiles &= ~TILE_Y;
+ bops->linear_to_y = copy_linear_to_y;
+ bops->y_to_linear = copy_y_to_linear;
+ }
+ }
+
+ igt_assert(bops->intel_gen);
+
+ return bops;
+}
+
+void buf_ops_switch_to_sofware_tiling(struct buf_ops *bops)
+{
+ igt_debug("Switch to software tiling/detiling of X/Y surfaces\n");
+
+ igt_assert(bops);
+
+ bops->hw_tiles = 0;
+ bops->linear_to_x = copy_linear_to_x;
+ bops->linear_to_y = copy_linear_to_y;
+ bops->x_to_linear = copy_x_to_linear;
+ bops->y_to_linear = copy_y_to_linear;
+}
+
+bool buf_ops_has_hw_fence(struct buf_ops *bops, uint32_t tiling)
+{
+ uint32_t tile_mask = (1 << tiling);
+
+ igt_assert(bops);
+
+ if (tile_mask & bops->hw_tiles)
+ return true;
+
+ return false;
+}
+
+bool buf_ops_has_tiling_support(struct buf_ops *bops, uint32_t tiling)
+{
+ uint32_t tile_mask = (1 << tiling);
+
+ igt_assert(bops);
+
+ if (tile_mask & bops->supported_tiles)
+ return true;
+
+ return false;
+}
+
+static int buf_aux_width(int gen, const struct igt_buf *buf)
+{
+ /*
+ * GEN12+: The AUX CCS unit size is 64 bytes mapping 4 main surface
+ * tiles. Thus the width of the CCS unit is 4*32=128 pixels on the
+ * main surface.
+ */
+ if (gen >= 12)
+ return DIV_ROUND_UP(igt_buf_width(buf), 128) * 64;
+
+ return DIV_ROUND_UP(igt_buf_width(buf), 1024) * 128;
+}
+
+static int buf_aux_height(int gen, const struct igt_buf *buf)
+{
+ /*
+ * GEN12+: The AUX CCS unit size is 64 bytes mapping 4 main surface
+ * tiles. Thus the height of the CCS unit is 32 pixel rows on the main
+ * surface.
+ */
+ if (gen >= 12)
+ return DIV_ROUND_UP(igt_buf_height(buf), 32);
+
+ return DIV_ROUND_UP(igt_buf_height(buf), 512) * 32;
+}
+
+void igt_buf_init(struct buf_ops *bops, struct igt_buf *buf,
+ int width, int height, int bpp,
+ uint32_t req_tiling, bool ccs)
+{
+ uint32_t tiling = req_tiling;
+ bool supports_hw_fences;
+
+ igt_assert(bops);
+
+ supports_hw_fences = buf_ops_has_hw_fence(bops, req_tiling);
+
+ memset(buf, 0, sizeof(*buf));
+
+ if (ccs) {
+ int aux_width, aux_height;
+ int size;
+
+ igt_require(bops->intel_gen >= 9);
+ igt_assert(req_tiling == I915_TILING_Y ||
+ req_tiling == I915_TILING_Yf);
+
+ /*
+ * On GEN12+ we align the main surface to 4 * 4 main surface
+ * tiles, which is 64kB. These 16 tiles are mapped by 4 AUX
+ * CCS units, that is 4 * 64 bytes. These 4 CCS units are in
+ * turn mapped by one L1 AUX page table entry.
+ */
+ if (bops->intel_gen >= 12)
+ buf->stride = ALIGN(width * (bpp / 8), 128 * 4);
+ else
+ buf->stride = ALIGN(width * (bpp / 8), 128);
+
+ if (bops->intel_gen >= 12)
+ height = ALIGN(height, 4 * 32);
+
+ buf->size = buf->stride * height;
+ buf->tiling = tiling;
+ buf->bpp = bpp;
+
+ aux_width = buf_aux_width(bops->intel_gen, buf);
+ aux_height = buf_aux_height(bops->intel_gen, buf);
+
+ buf->aux.offset = buf->stride * ALIGN(height, 32);
+ buf->aux.stride = aux_width;
+
+ size = buf->aux.offset + aux_width * aux_height;
+
+ buf->bo = drm_intel_bo_alloc(bops->bufmgr, "", size, 4096);
+
+ if (tiling == I915_TILING_Y && supports_hw_fences) {
+ drm_intel_bo_set_tiling(buf->bo, &tiling, buf->stride);
+ igt_assert_eq(tiling, req_tiling);
+ }
+ } else {
+ /* Requested bo must be hw tiled */
+ if (supports_hw_fences) {
+ unsigned long pitch;
+
+ buf->bo = drm_intel_bo_alloc_tiled(bops->bufmgr, "",
+ width, height,
+ bpp / 8,
+ &tiling, &pitch, 0);
+ igt_assert_eq(tiling, req_tiling);
+ igt_assert(buf->bo);
+
+ buf->stride = pitch;
+ buf->tiling = tiling;
+ buf->size = pitch * height;
+ buf->bpp = bpp;
+ } else {
+ /* Use bo alloc and software tiling/detiling */
+ int size;
+
+ buf->stride = ALIGN(width * (bpp / 8), 128);
+ buf->size = buf->stride * height;
+ buf->tiling = tiling;
+ buf->bpp = bpp;
+
+ size = buf->stride * ALIGN(height, 32);
+
+ buf->bo = drm_intel_bo_alloc(bops->bufmgr, "", size,
+ 4096);
+ igt_assert(buf->bo);
+ }
+ }
+}
diff --git a/lib/intel_bufops.h b/lib/intel_bufops.h
new file mode 100644
index 00000000..e53c6ebc
--- /dev/null
+++ b/lib/intel_bufops.h
@@ -0,0 +1,24 @@
+#ifndef __INTEL_BUFOPS_H__
+#define __INTEL_BUFOPS_H__
+
+#include "intel_batchbuffer.h"
+
+struct buf_ops;
+
+struct buf_ops *buf_ops_get(int fd, drm_intel_bufmgr *bufmgr);
+void buf_ops_switch_to_sofware_tiling(struct buf_ops *bops);
+
+void copy_buf_to_linear(struct buf_ops *bops, struct igt_buf *buf,
+ uint32_t *linear);
+
+void copy_linear_to_buf(struct buf_ops *bops, struct igt_buf *buf,
+ uint32_t *linear);
+
+bool buf_ops_has_hw_fence(struct buf_ops *bops, uint32_t tiling);
+bool buf_ops_has_tiling_support(struct buf_ops *bops, uint32_t tiling);
+
+void igt_buf_init(struct buf_ops *bops, struct igt_buf *buf,
+ int width, int height, int bpp,
+ uint32_t req_tiling, bool ccs);
+
+#endif
diff --git a/lib/meson.build b/lib/meson.build
index 3f908912..a88c3e89 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -26,6 +26,7 @@ lib_sources = [
'igt_x86.c',
'instdone.c',
'intel_batchbuffer.c',
+ 'intel_bufops.c',
'intel_chipset.c',
'intel_device_info.c',
'intel_os.c',
--
2.23.0