#ifndef INTEL_BATCHBUFFER_H #define INTEL_BATCHBUFFER_H #include #include #include #include "igt_core.h" #include "intel_reg.h" #define BATCH_SZ 4096 #define BATCH_RESERVED 16 struct intel_batchbuffer { drm_intel_bufmgr *bufmgr; uint32_t devid; int gen; drm_intel_context *ctx; drm_intel_bo *bo; uint8_t buffer[BATCH_SZ]; uint8_t *ptr, *end; uint8_t *state; }; struct intel_batchbuffer *intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr, uint32_t devid); void intel_batchbuffer_set_context(struct intel_batchbuffer *batch, drm_intel_context *ctx); void intel_batchbuffer_free(struct intel_batchbuffer *batch); void intel_batchbuffer_flush(struct intel_batchbuffer *batch); void intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring); void intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch, drm_intel_context *context); void intel_batchbuffer_reset(struct intel_batchbuffer *batch); void intel_batchbuffer_data(struct intel_batchbuffer *batch, const void *data, unsigned int bytes); void intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch, drm_intel_bo *buffer, uint64_t delta, uint32_t read_domains, uint32_t write_domain, int fenced); /* Inline functions - might actually be better off with these * non-inlined. Certainly better off switching all command packets to * be passed as structs rather than dwords, but that's a little bit of * work... */ #pragma GCC diagnostic ignored "-Winline" static inline unsigned int intel_batchbuffer_space(struct intel_batchbuffer *batch) { return (BATCH_SZ - BATCH_RESERVED) - (batch->ptr - batch->buffer); } static inline void intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, uint32_t dword) { igt_assert(intel_batchbuffer_space(batch) >= 4); *(uint32_t *) (batch->ptr) = dword; batch->ptr += 4; } static inline void intel_batchbuffer_require_space(struct intel_batchbuffer *batch, unsigned int sz) { igt_assert(sz < BATCH_SZ - BATCH_RESERVED); if (intel_batchbuffer_space(batch) < sz) intel_batchbuffer_flush(batch); } /** * BEGIN_BATCH: * @n: number of DWORDS to emit * @r: number of RELOCS to emit * * Prepares a batch to emit @n DWORDS, flushing it if there's not enough space * available. * * This macro needs a pointer to an #intel_batchbuffer structure called batch in * scope. */ #define BEGIN_BATCH(n, r) do { \ int __n = (n); \ igt_assert(batch->end == NULL); \ if (batch->gen >= 8) __n += r; \ __n *= 4; \ intel_batchbuffer_require_space(batch, __n); \ batch->end = batch->ptr + __n; \ } while (0) /** * OUT_BATCH: * @d: DWORD to emit * * Emits @d into a batch. * * This macro needs a pointer to an #intel_batchbuffer structure called batch in * scope. */ #define OUT_BATCH(d) intel_batchbuffer_emit_dword(batch, d) /** * OUT_RELOC_FENCED: * @buf: relocation target libdrm buffer object * @read_domains: gem domain bits for the relocation * @write_domain: gem domain bit for the relocation * @delta: delta value to add to @buffer's gpu address * * Emits a fenced relocation into a batch. * * This macro needs a pointer to an #intel_batchbuffer structure called batch in * scope. */ #define OUT_RELOC_FENCED(buf, read_domains, write_domain, delta) do { \ igt_assert((delta) >= 0); \ intel_batchbuffer_emit_reloc(batch, buf, delta, \ read_domains, write_domain, 1); \ } while (0) /** * OUT_RELOC: * @buf: relocation target libdrm buffer object * @read_domains: gem domain bits for the relocation * @write_domain: gem domain bit for the relocation * @delta: delta value to add to @buffer's gpu address * * Emits a normal, unfenced relocation into a batch. * * This macro needs a pointer to an #intel_batchbuffer structure called batch in * scope. */ #define OUT_RELOC(buf, read_domains, write_domain, delta) do { \ igt_assert((delta) >= 0); \ intel_batchbuffer_emit_reloc(batch, buf, delta, \ read_domains, write_domain, 0); \ } while (0) /** * ADVANCE_BATCH: * * Completes the batch command emission sequence started with #BEGIN_BATCH. * * This macro needs a pointer to an #intel_batchbuffer structure called batch in * scope. */ #define ADVANCE_BATCH() do { \ igt_assert(batch->ptr == batch->end); \ batch->end = NULL; \ } while(0) #define BLIT_COPY_BATCH_START(flags) do { \ BEGIN_BATCH(8, 2); \ OUT_BATCH(XY_SRC_COPY_BLT_CMD | \ XY_SRC_COPY_BLT_WRITE_ALPHA | \ XY_SRC_COPY_BLT_WRITE_RGB | \ (flags) | \ (6 + 2*(batch->gen >= 8))); \ } while(0) #define COLOR_BLIT_COPY_BATCH_START(flags) do { \ BEGIN_BATCH(6, 1); \ OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | \ COLOR_BLT_WRITE_ALPHA | \ XY_COLOR_BLT_WRITE_RGB | \ (flags) | \ (4 + (batch->gen >= 8))); \ } while(0) void intel_blt_copy(struct intel_batchbuffer *batch, drm_intel_bo *src_bo, int src_x1, int src_y1, int src_pitch, drm_intel_bo *dst_bo, int dst_x1, int dst_y1, int dst_pitch, int width, int height, int bpp); void intel_copy_bo(struct intel_batchbuffer *batch, drm_intel_bo *dst_bo, drm_intel_bo *src_bo, long int size); /* * Yf/Ys tiling * * Tiling mode in the I915_TILING_... namespace for new tiling modes which are * defined in the kernel. (They are not fenceable so the kernel does not need * to know about them.) * * They are to be used the the blitting routines below. */ #define I915_TILING_Yf 3 #define I915_TILING_Ys 4 /** * igt_buf: * @bo: underlying libdrm buffer object * @stride: stride of the buffer * @tiling: tiling mode bits * @data: pointer to the memory mapping of the buffer * @size: size of the buffer object * * This is a i-g-t buffer object wrapper structure which augments the baseline * libdrm buffer object with suitable data needed by the render copy and the * fill functions. */ struct igt_buf { drm_intel_bo *bo; uint32_t stride; uint32_t tiling; uint32_t *data; uint32_t size; /*< private >*/ unsigned num_tiles; }; unsigned igt_buf_width(struct igt_buf *buf); unsigned igt_buf_height(struct igt_buf *buf); void igt_blitter_fast_copy(struct intel_batchbuffer *batch, struct igt_buf *src, unsigned src_x, unsigned src_y, unsigned width, unsigned height, int bpp, struct igt_buf *dst, unsigned dst_x, unsigned dst_y); void igt_blitter_fast_copy__raw(int fd, /* src */ uint32_t src_handle, unsigned int src_stride, unsigned int src_tiling, unsigned int src_x, unsigned src_y, /* size */ unsigned int width, unsigned int height, /* bpp */ int bpp, /* dst */ uint32_t dst_handle, unsigned int dst_stride, unsigned int dst_tiling, unsigned int dst_x, unsigned dst_y); /** * igt_render_copyfunc_t: * @batch: batchbuffer object * @context: libdrm hardware context to use * @src: source i-g-t buffer object * @src_x: source pixel x-coordination * @src_y: source pixel y-coordination * @width: width of the copied rectangle * @height: height of the copied rectangle * @dst: destination i-g-t buffer object * @dst_x: destination pixel x-coordination * @dst_y: destination pixel y-coordination * * This is the type of the per-platform render copy functions. The * platform-specific implementation can be obtained by calling * igt_get_render_copyfunc(). * * A render copy function will emit a batchbuffer to the kernel which executes * the specified blit copy operation using the render engine. @context is * optional and can be NULL. */ typedef void (*igt_render_copyfunc_t)(struct intel_batchbuffer *batch, drm_intel_context *context, struct igt_buf *src, unsigned src_x, unsigned src_y, unsigned width, unsigned height, struct igt_buf *dst, unsigned dst_x, unsigned dst_y); igt_render_copyfunc_t igt_get_render_copyfunc(int devid); /** * igt_fillfunc_t: * @batch: batchbuffer object * @dst: destination i-g-t buffer object * @x: destination pixel x-coordination * @y: destination pixel y-coordination * @width: width of the filled rectangle * @height: height of the filled rectangle * @color: fill color to use * * This is the type of the per-platform fill functions using media * or gpgpu pipeline. The platform-specific implementation can be obtained * by calling igt_get_media_fillfunc() or igt_get_gpgpu_fillfunc(). * * A fill function will emit a batchbuffer to the kernel which executes * the specified blit fill operation using the media/gpgpu engine. */ typedef void (*igt_fillfunc_t)(struct intel_batchbuffer *batch, struct igt_buf *dst, unsigned x, unsigned y, unsigned width, unsigned height, uint8_t color); igt_fillfunc_t igt_get_media_fillfunc(int devid); igt_fillfunc_t igt_get_gpgpu_fillfunc(int devid); /** * igt_media_spinfunc_t: * @batch: batchbuffer object * @dst: destination i-g-t buffer object * @spins: number of loops to execute * * This is the type of the per-platform media spin functions. The * platform-specific implementation can be obtained by calling * igt_get_media_spinfunc(). * * The media spin function emits a batchbuffer for the render engine with * the media pipeline selected. The workload consists of a single thread * which spins in a tight loop the requested number of times. Each spin * increments a counter whose final 32-bit value is written to the * destination buffer on completion. This utility provides a simple way * to keep the render engine busy for a set time for various tests. */ typedef void (*igt_media_spinfunc_t)(struct intel_batchbuffer *batch, struct igt_buf *dst, uint32_t spins); igt_media_spinfunc_t igt_get_media_spinfunc(int devid); #endif