ilo: reduce BLT function parameters
[mesa.git] / src / gallium / drivers / ilo / ilo_blitter_blt.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "genhw/genhw.h"
29 #include "util/u_pack_color.h"
30
31 #include "ilo_3d.h"
32 #include "ilo_builder_mi.h"
33 #include "ilo_builder_blt.h"
34 #include "ilo_context.h"
35 #include "ilo_cp.h"
36 #include "ilo_blit.h"
37 #include "ilo_resource.h"
38 #include "ilo_blitter.h"
39
40 static uint32_t
41 ilo_blitter_blt_begin(struct ilo_blitter *blitter, int max_cmd_size,
42 struct intel_bo *dst, enum intel_tiling_mode dst_tiling,
43 struct intel_bo *src, enum intel_tiling_mode src_tiling)
44 {
45 struct ilo_context *ilo = blitter->ilo;
46 struct intel_bo *aper_check[2];
47 int count;
48 uint32_t swctrl;
49
50 /* change ring */
51 ilo_cp_set_ring(ilo->cp, INTEL_RING_BLT);
52 ilo_cp_set_owner(ilo->cp, NULL, 0);
53
54 /* check aperture space */
55 aper_check[0] = dst;
56 count = 1;
57
58 if (src) {
59 aper_check[1] = src;
60 count++;
61 }
62
63 if (!ilo_builder_validate(&ilo->cp->builder, count, aper_check))
64 ilo_cp_flush(ilo->cp, "out of aperture");
65
66 /* set BCS_SWCTRL */
67 swctrl = 0x0;
68
69 if (dst_tiling == INTEL_TILING_Y) {
70 swctrl |= GEN6_REG_BCS_SWCTRL_DST_TILING_Y << 16 |
71 GEN6_REG_BCS_SWCTRL_DST_TILING_Y;
72 }
73
74 if (src && src_tiling == INTEL_TILING_Y) {
75 swctrl |= GEN6_REG_BCS_SWCTRL_SRC_TILING_Y << 16 |
76 GEN6_REG_BCS_SWCTRL_SRC_TILING_Y;
77 }
78
79 /*
80 * Most clients expect BLT engine to be stateless. If we have to set
81 * BCS_SWCTRL to a non-default value, we have to set it back in the same
82 * batch buffer.
83 */
84 if (swctrl)
85 max_cmd_size += (4 + 3) * 2;
86
87 if (ilo_cp_space(ilo->cp) < max_cmd_size) {
88 ilo_cp_flush(ilo->cp, "out of space");
89 assert(ilo_cp_space(ilo->cp) >= max_cmd_size);
90 }
91
92 if (swctrl) {
93 /*
94 * From the Ivy Bridge PRM, volume 1 part 4, page 133:
95 *
96 * "SW is required to flush the HW before changing the polarity of
97 * this bit (Tile Y Destination/Source)."
98 */
99 gen6_MI_FLUSH_DW(&ilo->cp->builder);
100 gen6_MI_LOAD_REGISTER_IMM(&ilo->cp->builder,
101 GEN6_REG_BCS_SWCTRL, swctrl);
102
103 swctrl &= ~(GEN6_REG_BCS_SWCTRL_DST_TILING_Y |
104 GEN6_REG_BCS_SWCTRL_SRC_TILING_Y);
105 }
106
107 return swctrl;
108 }
109
110 static void
111 ilo_blitter_blt_end(struct ilo_blitter *blitter, uint32_t swctrl)
112 {
113 struct ilo_context *ilo = blitter->ilo;
114
115 /* set BCS_SWCTRL back */
116 if (swctrl) {
117 gen6_MI_FLUSH_DW(&ilo->cp->builder);
118 gen6_MI_LOAD_REGISTER_IMM(&ilo->cp->builder, GEN6_REG_BCS_SWCTRL, swctrl);
119 }
120 }
121
122 static bool
123 buf_clear_region(struct ilo_blitter *blitter,
124 struct ilo_buffer *buf, unsigned offset,
125 uint32_t val, unsigned size,
126 enum gen6_blt_mask value_mask,
127 enum gen6_blt_mask write_mask)
128 {
129 const uint8_t rop = 0xf0; /* PATCOPY */
130 const int cpp = gen6_blt_translate_value_cpp(value_mask);
131 struct ilo_context *ilo = blitter->ilo;
132 struct gen6_blt_bo dst;
133
134 if (offset % cpp || size % cpp)
135 return false;
136
137 dst.bo = buf->bo;
138 dst.offset = offset;
139
140 ilo_blitter_blt_begin(blitter, 0,
141 dst.bo, INTEL_TILING_NONE, NULL, INTEL_TILING_NONE);
142
143 while (size) {
144 unsigned width, height;
145
146 width = size;
147 height = 1;
148
149 if (width > gen6_blt_max_bytes_per_scanline) {
150 /* less than INT16_MAX and dword-aligned */
151 width = 32764;
152 height = size / width;
153 if (height > gen6_blt_max_scanlines)
154 height = gen6_blt_max_scanlines;
155
156 dst.pitch = width;
157 } else {
158 dst.pitch = 0;
159 }
160
161 gen6_COLOR_BLT(&ilo->cp->builder, &dst, val,
162 width, height, rop, value_mask, write_mask);
163
164 dst.offset += dst.pitch * height;
165 size -= width * height;
166 }
167
168 ilo_blitter_blt_end(blitter, 0);
169
170 return true;
171 }
172
173 static bool
174 buf_copy_region(struct ilo_blitter *blitter,
175 struct ilo_buffer *dst_buf, unsigned dst_offset,
176 struct ilo_buffer *src_buf, unsigned src_offset,
177 unsigned size)
178 {
179 const uint8_t rop = 0xcc; /* SRCCOPY */
180 struct ilo_context *ilo = blitter->ilo;
181 struct gen6_blt_bo dst, src;
182
183 dst.bo = dst_buf->bo;
184 dst.offset = dst_offset;
185 dst.pitch = 0;
186
187 src.bo = src_buf->bo;
188 src.offset = src_offset;
189 src.pitch = 0;
190
191 ilo_blitter_blt_begin(blitter, 0,
192 dst_buf->bo, INTEL_TILING_NONE, src_buf->bo, INTEL_TILING_NONE);
193
194 while (size) {
195 unsigned width, height;
196
197 width = size;
198 height = 1;
199
200 if (width > gen6_blt_max_bytes_per_scanline) {
201 /* less than INT16_MAX and dword-aligned */
202 width = 32764;
203 height = size / width;
204 if (height > gen6_blt_max_scanlines)
205 height = gen6_blt_max_scanlines;
206
207 dst.pitch = width;
208 src.pitch = width;
209 } else {
210 dst.pitch = 0;
211 src.pitch = 0;
212 }
213
214 gen6_SRC_COPY_BLT(&ilo->cp->builder, &dst, &src,
215 width, height, rop, GEN6_BLT_MASK_8, GEN6_BLT_MASK_8);
216
217 dst.offset += dst.pitch * height;
218 src.offset += src.pitch * height;
219 size -= width * height;
220 }
221
222 ilo_blitter_blt_end(blitter, 0);
223
224 return true;
225 }
226
227 static bool
228 tex_clear_region(struct ilo_blitter *blitter,
229 struct ilo_texture *dst_tex, unsigned dst_level,
230 const struct pipe_box *dst_box,
231 uint32_t val,
232 enum gen6_blt_mask value_mask,
233 enum gen6_blt_mask write_mask)
234 {
235 const int cpp = gen6_blt_translate_value_cpp(value_mask);
236 const unsigned max_extent = 32767; /* INT16_MAX */
237 const uint8_t rop = 0xf0; /* PATCOPY */
238 struct ilo_context *ilo = blitter->ilo;
239 struct gen6_blt_xy_bo dst;
240 uint32_t swctrl;
241 int slice;
242
243 /* no W-tiling support */
244 if (dst_tex->separate_s8)
245 return false;
246
247 if (dst_tex->layout.bo_stride > max_extent)
248 return false;
249
250 if (dst_box->width * cpp > gen6_blt_max_bytes_per_scanline)
251 return false;
252
253 dst.bo = dst_tex->bo;
254 dst.offset = 0;
255 dst.pitch = dst_tex->layout.bo_stride;
256 dst.tiling = dst_tex->layout.tiling;
257
258 swctrl = ilo_blitter_blt_begin(blitter, dst_box->depth * 6,
259 dst_tex->bo, dst_tex->layout.tiling, NULL, INTEL_TILING_NONE);
260
261 for (slice = 0; slice < dst_box->depth; slice++) {
262 unsigned x, y;
263
264 ilo_layout_get_slice_pos(&dst_tex->layout,
265 dst_level, dst_box->z + slice, &x, &y);
266
267 dst.x = x + dst_box->x;
268 dst.y = y + dst_box->y;
269
270 if (dst.x + dst_box->width > max_extent ||
271 dst.y + dst_box->height > max_extent)
272 break;
273
274 gen6_XY_COLOR_BLT(&ilo->cp->builder, &dst, val,
275 dst_box->width, dst_box->height, rop, value_mask, write_mask);
276 }
277
278 ilo_blitter_blt_end(blitter, swctrl);
279
280 return (slice == dst_box->depth);
281 }
282
283 static bool
284 tex_copy_region(struct ilo_blitter *blitter,
285 struct ilo_texture *dst_tex,
286 unsigned dst_level,
287 unsigned dst_x, unsigned dst_y, unsigned dst_z,
288 struct ilo_texture *src_tex,
289 unsigned src_level,
290 const struct pipe_box *src_box)
291 {
292 const struct util_format_description *desc =
293 util_format_description(dst_tex->layout.format);
294 const unsigned max_extent = 32767; /* INT16_MAX */
295 const uint8_t rop = 0xcc; /* SRCCOPY */
296 struct ilo_context *ilo = blitter->ilo;
297 enum gen6_blt_mask mask;
298 struct gen6_blt_xy_bo dst, src;
299 uint32_t swctrl;
300 int cpp, xscale, slice;
301
302 /* no W-tiling support */
303 if (dst_tex->separate_s8 || src_tex->separate_s8)
304 return false;
305
306 if (dst_tex->layout.bo_stride > max_extent ||
307 src_tex->layout.bo_stride > max_extent)
308 return false;
309
310 cpp = desc->block.bits / 8;
311 xscale = 1;
312
313 /* accommodate for larger cpp */
314 if (cpp > 4) {
315 if (cpp % 2 == 1)
316 return false;
317
318 cpp = (cpp % 4 == 0) ? 4 : 2;
319 xscale = (desc->block.bits / 8) / cpp;
320 }
321
322 if (src_box->width * cpp * xscale > gen6_blt_max_bytes_per_scanline)
323 return false;
324
325 switch (cpp) {
326 case 1:
327 mask = GEN6_BLT_MASK_8;
328 break;
329 case 2:
330 mask = GEN6_BLT_MASK_16;
331 break;
332 case 4:
333 mask = GEN6_BLT_MASK_32;
334 break;
335 default:
336 return false;
337 break;
338 }
339
340 dst.bo = dst_tex->bo;
341 dst.offset = 0;
342 dst.pitch = dst_tex->layout.bo_stride;
343 dst.tiling = dst_tex->layout.tiling;
344
345 src.bo = src_tex->bo;
346 src.offset = 0;
347 src.pitch = src_tex->layout.bo_stride;
348 src.tiling = src_tex->layout.tiling;
349
350 swctrl = ilo_blitter_blt_begin(blitter, src_box->depth * 8,
351 dst.bo, dst.tiling, src.bo, src.tiling);
352
353 for (slice = 0; slice < src_box->depth; slice++) {
354 unsigned dx, dy, sx, sy, width, height;
355
356 ilo_layout_get_slice_pos(&dst_tex->layout,
357 dst_level, dst_z + slice, &dx, &dy);
358 ilo_layout_get_slice_pos(&src_tex->layout,
359 src_level, src_box->z + slice, &sx, &sy);
360
361 dst.x = (dx + dst_x) * xscale;
362 dst.y = dy + dst_y;
363 src.x = (sx + src_box->x) * xscale;
364 src.y = sy + src_box->y;
365 width = src_box->width * xscale;
366 height = src_box->height;
367
368 /* in blocks */
369 dst.x /= desc->block.width;
370 dst.y /= desc->block.height;
371 src.x /= desc->block.width;
372 src.y /= desc->block.height;
373 width /= desc->block.width;
374 height /= desc->block.height;
375
376 if (src.x + width > max_extent || src.y + height > max_extent ||
377 dst.x + width > max_extent || dst.y + height > max_extent)
378 break;
379
380 gen6_XY_SRC_COPY_BLT(&ilo->cp->builder, &dst, &src,
381 width, height, rop, mask, mask);
382 }
383
384 ilo_blitter_blt_end(blitter, swctrl);
385
386 return (slice == src_box->depth);
387 }
388
389 bool
390 ilo_blitter_blt_copy_resource(struct ilo_blitter *blitter,
391 struct pipe_resource *dst, unsigned dst_level,
392 unsigned dst_x, unsigned dst_y, unsigned dst_z,
393 struct pipe_resource *src, unsigned src_level,
394 const struct pipe_box *src_box)
395 {
396 bool success;
397
398 ilo_blit_resolve_slices(blitter->ilo, src, src_level,
399 src_box->z, src_box->depth, ILO_TEXTURE_BLT_READ);
400 ilo_blit_resolve_slices(blitter->ilo, dst, dst_level,
401 dst_z, src_box->depth, ILO_TEXTURE_BLT_WRITE);
402
403 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
404 const unsigned dst_offset = dst_x;
405 const unsigned src_offset = src_box->x;
406 const unsigned size = src_box->width;
407
408 assert(dst_level == 0 && dst_y == 0 && dst_z == 0);
409 assert(src_level == 0 &&
410 src_box->y == 0 &&
411 src_box->z == 0 &&
412 src_box->height == 1 &&
413 src_box->depth == 1);
414
415 success = buf_copy_region(blitter,
416 ilo_buffer(dst), dst_offset, ilo_buffer(src), src_offset, size);
417 }
418 else if (dst->target != PIPE_BUFFER && src->target != PIPE_BUFFER) {
419 success = tex_copy_region(blitter,
420 ilo_texture(dst), dst_level, dst_x, dst_y, dst_z,
421 ilo_texture(src), src_level, src_box);
422 }
423 else {
424 success = false;
425 }
426
427 return success;
428 }
429
430 bool
431 ilo_blitter_blt_clear_rt(struct ilo_blitter *blitter,
432 struct pipe_surface *rt,
433 const union pipe_color_union *color,
434 unsigned x, unsigned y,
435 unsigned width, unsigned height)
436 {
437 const int cpp = util_format_get_blocksize(rt->format);
438 enum gen6_blt_mask mask;
439 union util_color packed;
440 bool success;
441
442 if (!ilo_3d_pass_render_condition(blitter->ilo))
443 return true;
444
445 switch (cpp) {
446 case 1:
447 mask = GEN6_BLT_MASK_8;
448 break;
449 case 2:
450 mask = GEN6_BLT_MASK_16;
451 break;
452 case 4:
453 mask = GEN6_BLT_MASK_32;
454 break;
455 default:
456 return false;
457 break;
458 }
459
460 if (util_format_is_pure_integer(rt->format) ||
461 util_format_is_compressed(rt->format))
462 return false;
463
464 ilo_blit_resolve_surface(blitter->ilo, rt, ILO_TEXTURE_BLT_WRITE);
465
466 util_pack_color(color->f, rt->format, &packed);
467
468 if (rt->texture->target == PIPE_BUFFER) {
469 unsigned offset, end, size;
470
471 assert(y == 0 && height == 1);
472
473 offset = (rt->u.buf.first_element + x) * cpp;
474 end = (rt->u.buf.last_element + 1) * cpp;
475
476 size = width * cpp;
477 if (offset + size > end)
478 size = end - offset;
479
480 success = buf_clear_region(blitter, ilo_buffer(rt->texture),
481 offset, packed.ui[0], size, mask, mask);
482 }
483 else {
484 struct pipe_box box;
485
486 u_box_3d(x, y, rt->u.tex.first_layer, width, height,
487 rt->u.tex.last_layer - rt->u.tex.first_layer + 1, &box);
488
489 success = tex_clear_region(blitter, ilo_texture(rt->texture),
490 rt->u.tex.level, &box, packed.ui[0], mask, mask);
491 }
492
493 return success;
494 }
495
496 bool
497 ilo_blitter_blt_clear_zs(struct ilo_blitter *blitter,
498 struct pipe_surface *zs,
499 unsigned clear_flags,
500 double depth, unsigned stencil,
501 unsigned x, unsigned y,
502 unsigned width, unsigned height)
503 {
504 enum gen6_blt_mask value_mask, write_mask;
505 struct pipe_box box;
506 uint32_t val;
507
508 if (!ilo_3d_pass_render_condition(blitter->ilo))
509 return true;
510
511 switch (zs->format) {
512 case PIPE_FORMAT_Z16_UNORM:
513 if (!(clear_flags & PIPE_CLEAR_DEPTH))
514 return true;
515
516 value_mask = GEN6_BLT_MASK_16;
517 write_mask = GEN6_BLT_MASK_16;
518 break;
519 case PIPE_FORMAT_Z32_FLOAT:
520 if (!(clear_flags & PIPE_CLEAR_DEPTH))
521 return true;
522
523 value_mask = GEN6_BLT_MASK_32;
524 write_mask = GEN6_BLT_MASK_32;
525 break;
526 case PIPE_FORMAT_Z24X8_UNORM:
527 if (!(clear_flags & PIPE_CLEAR_DEPTH))
528 return true;
529
530 value_mask = GEN6_BLT_MASK_32;
531 write_mask = GEN6_BLT_MASK_32_LO;
532 break;
533 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
534 if (!(clear_flags & PIPE_CLEAR_DEPTHSTENCIL))
535 return true;
536
537 value_mask = GEN6_BLT_MASK_32;
538
539 if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) == PIPE_CLEAR_DEPTHSTENCIL)
540 write_mask = GEN6_BLT_MASK_32;
541 else if (clear_flags & PIPE_CLEAR_DEPTH)
542 write_mask = GEN6_BLT_MASK_32_LO;
543 else
544 write_mask = GEN6_BLT_MASK_32_HI;
545 break;
546 default:
547 return false;
548 break;
549 }
550
551 ilo_blit_resolve_surface(blitter->ilo, zs, ILO_TEXTURE_BLT_WRITE);
552
553 val = util_pack_z_stencil(zs->format, depth, stencil);
554
555 u_box_3d(x, y, zs->u.tex.first_layer, width, height,
556 zs->u.tex.last_layer - zs->u.tex.first_layer + 1, &box);
557
558 assert(zs->texture->target != PIPE_BUFFER);
559
560 return tex_clear_region(blitter, ilo_texture(zs->texture),
561 zs->u.tex.level, &box, val, value_mask, write_mask);
562 }