1 #ifndef INTEL_BATCHBUFFER_H
2 #define INTEL_BATCHBUFFER_H
3 
4 #include <stdint.h>
5 #include <intel_bufmgr.h>
6 #include <i915_drm.h>
7 
8 #include "igt_core.h"
9 #include "intel_reg.h"
10 
11 #define BATCH_SZ 4096
12 #define BATCH_RESERVED 16
13 
14 struct intel_batchbuffer {
15 	drm_intel_bufmgr *bufmgr;
16 	uint32_t devid;
17 	int gen;
18 
19 	drm_intel_context *ctx;
20 	drm_intel_bo *bo;
21 
22 	uint8_t buffer[BATCH_SZ];
23 	uint8_t *ptr, *end;
24 };
25 
26 struct intel_batchbuffer *intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr,
27 						  uint32_t devid);
28 
29 void intel_batchbuffer_set_context(struct intel_batchbuffer *batch,
30 				   drm_intel_context *ctx);
31 
32 
33 void intel_batchbuffer_free(struct intel_batchbuffer *batch);
34 
35 
36 void intel_batchbuffer_flush(struct intel_batchbuffer *batch);
37 void intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring);
38 void intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch,
39 					  drm_intel_context *context);
40 
41 void intel_batchbuffer_reset(struct intel_batchbuffer *batch);
42 
43 uint32_t intel_batchbuffer_copy_data(struct intel_batchbuffer *batch,
44 				const void *data, unsigned int bytes,
45 				uint32_t align);
46 
47 void intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch,
48 				  drm_intel_bo *buffer,
49 				  uint64_t delta,
50 				  uint32_t read_domains,
51 				  uint32_t write_domain,
52 				  int fenced);
53 
54 uint32_t
55 intel_batchbuffer_align(struct intel_batchbuffer *batch, uint32_t align);
56 
57 void *
58 intel_batchbuffer_subdata_alloc(struct intel_batchbuffer *batch,
59 				uint32_t size, uint32_t align);
60 
61 uint32_t
62 intel_batchbuffer_subdata_offset(struct intel_batchbuffer *batch, void *ptr);
63 
64 /* Inline functions - might actually be better off with these
65  * non-inlined.  Certainly better off switching all command packets to
66  * be passed as structs rather than dwords, but that's a little bit of
67  * work...
68  */
69 #pragma GCC diagnostic ignored "-Winline"
70 static inline unsigned int
intel_batchbuffer_space(struct intel_batchbuffer * batch)71 intel_batchbuffer_space(struct intel_batchbuffer *batch)
72 {
73 	return (BATCH_SZ - BATCH_RESERVED) - (batch->ptr - batch->buffer);
74 }
75 
76 
77 static inline void
intel_batchbuffer_emit_dword(struct intel_batchbuffer * batch,uint32_t dword)78 intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, uint32_t dword)
79 {
80 	igt_assert(intel_batchbuffer_space(batch) >= 4);
81 	*(uint32_t *) (batch->ptr) = dword;
82 	batch->ptr += 4;
83 }
84 
85 static inline void
intel_batchbuffer_require_space(struct intel_batchbuffer * batch,unsigned int sz)86 intel_batchbuffer_require_space(struct intel_batchbuffer *batch,
87                                 unsigned int sz)
88 {
89 	igt_assert(sz < BATCH_SZ - BATCH_RESERVED);
90 	if (intel_batchbuffer_space(batch) < sz)
91 		intel_batchbuffer_flush(batch);
92 }
93 
94 /**
95  * BEGIN_BATCH:
96  * @n: number of DWORDS to emit
97  * @r: number of RELOCS to emit
98  *
99  * Prepares a batch to emit @n DWORDS, flushing it if there's not enough space
100  * available.
101  *
102  * This macro needs a pointer to an #intel_batchbuffer structure called batch in
103  * scope.
104  */
105 #define BEGIN_BATCH(n, r) do {						\
106 	int __n = (n); \
107 	igt_assert(batch->end == NULL); \
108 	if (batch->gen >= 8) __n += r;	\
109 	__n *= 4; \
110 	intel_batchbuffer_require_space(batch, __n);			\
111 	batch->end = batch->ptr + __n; \
112 } while (0)
113 
114 /**
115  * OUT_BATCH:
116  * @d: DWORD to emit
117  *
118  * Emits @d into a batch.
119  *
120  * This macro needs a pointer to an #intel_batchbuffer structure called batch in
121  * scope.
122  */
123 #define OUT_BATCH(d) intel_batchbuffer_emit_dword(batch, d)
124 
125 /**
126  * OUT_RELOC_FENCED:
127  * @buf: relocation target libdrm buffer object
128  * @read_domains: gem domain bits for the relocation
129  * @write_domain: gem domain bit for the relocation
130  * @delta: delta value to add to @buffer's gpu address
131  *
132  * Emits a fenced relocation into a batch.
133  *
134  * This macro needs a pointer to an #intel_batchbuffer structure called batch in
135  * scope.
136  */
137 #define OUT_RELOC_FENCED(buf, read_domains, write_domain, delta) do {		\
138 	igt_assert((delta) >= 0);						\
139 	intel_batchbuffer_emit_reloc(batch, buf, delta,			\
140 				     read_domains, write_domain, 1);	\
141 } while (0)
142 
143 /**
144  * OUT_RELOC:
145  * @buf: relocation target libdrm buffer object
146  * @read_domains: gem domain bits for the relocation
147  * @write_domain: gem domain bit for the relocation
148  * @delta: delta value to add to @buffer's gpu address
149  *
150  * Emits a normal, unfenced relocation into a batch.
151  *
152  * This macro needs a pointer to an #intel_batchbuffer structure called batch in
153  * scope.
154  */
155 #define OUT_RELOC(buf, read_domains, write_domain, delta) do {		\
156 	igt_assert((delta) >= 0);						\
157 	intel_batchbuffer_emit_reloc(batch, buf, delta,			\
158 				     read_domains, write_domain, 0);	\
159 } while (0)
160 
161 /**
162  * ADVANCE_BATCH:
163  *
164  * Completes the batch command emission sequence started with #BEGIN_BATCH.
165  *
166  * This macro needs a pointer to an #intel_batchbuffer structure called batch in
167  * scope.
168  */
169 #define ADVANCE_BATCH() do {						\
170 	igt_assert(batch->ptr == batch->end); \
171 	batch->end = NULL; \
172 } while(0)
173 
174 #define BLIT_COPY_BATCH_START(flags) do { \
175 	BEGIN_BATCH(8, 2); \
176 	OUT_BATCH(XY_SRC_COPY_BLT_CMD | \
177 		  XY_SRC_COPY_BLT_WRITE_ALPHA | \
178 		  XY_SRC_COPY_BLT_WRITE_RGB | \
179 		  (flags) | \
180 		  (6 + 2*(batch->gen >= 8))); \
181 } while(0)
182 
183 #define COLOR_BLIT_COPY_BATCH_START(flags) do { \
184 	BEGIN_BATCH(6, 1); \
185 	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | \
186 		  COLOR_BLT_WRITE_ALPHA | \
187 		  XY_COLOR_BLT_WRITE_RGB | \
188 		  (flags) | \
189 		  (4 + (batch->gen >= 8))); \
190 } while(0)
191 
192 void
193 intel_blt_copy(struct intel_batchbuffer *batch,
194 	      drm_intel_bo *src_bo, int src_x1, int src_y1, int src_pitch,
195 	      drm_intel_bo *dst_bo, int dst_x1, int dst_y1, int dst_pitch,
196 	      int width, int height, int bpp);
197 void intel_copy_bo(struct intel_batchbuffer *batch,
198 		   drm_intel_bo *dst_bo, drm_intel_bo *src_bo,
199 		   long int size);
200 
201 /*
202  * Yf/Ys tiling
203  *
204  * Tiling mode in the I915_TILING_... namespace for new tiling modes which are
205  * defined in the kernel. (They are not fenceable so the kernel does not need
206  * to know about them.)
207  *
208  * They are to be used the the blitting routines below.
209  */
210 #define I915_TILING_Yf	3
211 #define I915_TILING_Ys	4
212 
213 /**
214  * igt_buf:
215  * @bo: underlying libdrm buffer object
216  * @stride: stride of the buffer
217  * @tiling: tiling mode bits
218  * @bpp: bits per pixel, 8, 16 or 32.
219  * @data: pointer to the memory mapping of the buffer
220  * @size: size of the buffer object
221  *
222  * This is a i-g-t buffer object wrapper structure which augments the baseline
223  * libdrm buffer object with suitable data needed by the render copy and the
224  * fill functions.
225  */
226 struct igt_buf {
227 	drm_intel_bo *bo;
228 	uint32_t stride;
229 	uint32_t tiling;
230 	uint32_t bpp;
231 	uint32_t *data;
232 	uint32_t size;
233 	struct {
234 		uint32_t offset;
235 		uint32_t stride;
236 	} aux;
237 	/*< private >*/
238 	unsigned num_tiles;
239 };
240 
241 unsigned igt_buf_width(const struct igt_buf *buf);
242 unsigned igt_buf_height(const struct igt_buf *buf);
243 
244 void igt_blitter_fast_copy(struct intel_batchbuffer *batch,
245 			   const struct igt_buf *src, unsigned src_delta,
246 			   unsigned src_x, unsigned src_y,
247 			   unsigned width, unsigned height,
248 			   int bpp,
249 			   const struct igt_buf *dst, unsigned dst_delta,
250 			   unsigned dst_x, unsigned dst_y);
251 
252 void igt_blitter_fast_copy__raw(int fd,
253 				/* src */
254 				uint32_t src_handle,
255 				unsigned int src_delta,
256 				unsigned int src_stride,
257 				unsigned int src_tiling,
258 				unsigned int src_x, unsigned src_y,
259 
260 				/* size */
261 				unsigned int width, unsigned int height,
262 
263 				/* bpp */
264 				int bpp,
265 
266 				/* dst */
267 				uint32_t dst_handle,
268 				unsigned int dst_delta,
269 				unsigned int dst_stride,
270 				unsigned int dst_tiling,
271 				unsigned int dst_x, unsigned dst_y);
272 
273 /**
274  * igt_render_copyfunc_t:
275  * @batch: batchbuffer object
276  * @context: libdrm hardware context to use
277  * @src: source i-g-t buffer object
278  * @src_x: source pixel x-coordination
279  * @src_y: source pixel y-coordination
280  * @width: width of the copied rectangle
281  * @height: height of the copied rectangle
282  * @dst: destination i-g-t buffer object
283  * @dst_x: destination pixel x-coordination
284  * @dst_y: destination pixel y-coordination
285  *
286  * This is the type of the per-platform render copy functions. The
287  * platform-specific implementation can be obtained by calling
288  * igt_get_render_copyfunc().
289  *
290  * A render copy function will emit a batchbuffer to the kernel which executes
291  * the specified blit copy operation using the render engine. @context is
292  * optional and can be NULL.
293  */
294 typedef void (*igt_render_copyfunc_t)(struct intel_batchbuffer *batch,
295 				      drm_intel_context *context,
296 				      const struct igt_buf *src, unsigned src_x, unsigned src_y,
297 				      unsigned width, unsigned height,
298 				      const struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
299 
300 igt_render_copyfunc_t igt_get_render_copyfunc(int devid);
301 
302 /**
303  * igt_fillfunc_t:
304  * @batch: batchbuffer object
305  * @dst: destination i-g-t buffer object
306  * @x: destination pixel x-coordination
307  * @y: destination pixel y-coordination
308  * @width: width of the filled rectangle
309  * @height: height of the filled rectangle
310  * @color: fill color to use
311  *
312  * This is the type of the per-platform fill functions using media
313  * or gpgpu pipeline. The platform-specific implementation can be obtained
314  * by calling igt_get_media_fillfunc() or igt_get_gpgpu_fillfunc().
315  *
316  * A fill function will emit a batchbuffer to the kernel which executes
317  * the specified blit fill operation using the media/gpgpu engine.
318  */
319 typedef void (*igt_fillfunc_t)(struct intel_batchbuffer *batch,
320 			       const struct igt_buf *dst,
321 			       unsigned x, unsigned y,
322 			       unsigned width, unsigned height,
323 			       uint8_t color);
324 
325 igt_fillfunc_t igt_get_media_fillfunc(int devid);
326 igt_fillfunc_t igt_get_gpgpu_fillfunc(int devid);
327 
328 typedef void (*igt_vme_func_t)(struct intel_batchbuffer *batch,
329 			       const struct igt_buf *src,
330 			       unsigned int width, unsigned int height,
331 			       const struct igt_buf *dst);
332 
333 igt_vme_func_t igt_get_media_vme_func(int devid);
334 
335 /**
336  * igt_media_spinfunc_t:
337  * @batch: batchbuffer object
338  * @dst: destination i-g-t buffer object
339  * @spins: number of loops to execute
340  *
341  * This is the type of the per-platform media spin functions. The
342  * platform-specific implementation can be obtained by calling
343  * igt_get_media_spinfunc().
344  *
345  * The media spin function emits a batchbuffer for the render engine with
346  * the media pipeline selected. The workload consists of a single thread
347  * which spins in a tight loop the requested number of times. Each spin
348  * increments a counter whose final 32-bit value is written to the
349  * destination buffer on completion. This utility provides a simple way
350  * to keep the render engine busy for a set time for various tests.
351  */
352 typedef void (*igt_media_spinfunc_t)(struct intel_batchbuffer *batch,
353 				     const struct igt_buf *dst, uint32_t spins);
354 
355 igt_media_spinfunc_t igt_get_media_spinfunc(int devid);
356 
357 #endif
358