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 "core/ilo_builder_mi.h"
30 #include "core/ilo_builder_blt.h"
31 #include "util/u_pack_color.h"
32
33 #include "ilo_context.h"
34 #include "ilo_cp.h"
35 #include "ilo_blit.h"
36 #include "ilo_resource.h"
37 #include "ilo_blitter.h"
38
39 static uint32_t
ilo_blitter_blt_begin(struct ilo_blitter * blitter,int max_cmd_size,struct intel_bo * dst,enum gen_surface_tiling dst_tiling,struct intel_bo * src,enum gen_surface_tiling src_tiling)40 ilo_blitter_blt_begin(struct ilo_blitter *blitter, int max_cmd_size,
41 struct intel_bo *dst,
42 enum gen_surface_tiling dst_tiling,
43 struct intel_bo *src,
44 enum gen_surface_tiling src_tiling)
45 {
46 struct ilo_cp *cp = blitter->ilo->cp;
47 struct intel_bo *aper_check[2];
48 int count;
49 uint32_t swctrl;
50
51 /* change owner */
52 ilo_cp_set_owner(cp, INTEL_RING_BLT, NULL);
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(&cp->builder, count, aper_check))
64 ilo_cp_submit(cp, "out of aperture");
65
66 /* set BCS_SWCTRL */
67 swctrl = 0x0;
68
69 assert(dst_tiling == GEN6_TILING_NONE ||
70 dst_tiling == GEN6_TILING_X ||
71 dst_tiling == GEN6_TILING_Y);
72 assert(src_tiling == GEN6_TILING_NONE ||
73 src_tiling == GEN6_TILING_X ||
74 src_tiling == GEN6_TILING_Y);
75
76 if (dst_tiling == GEN6_TILING_Y) {
77 swctrl |= GEN6_REG_BCS_SWCTRL_DST_TILING_Y << 16 |
78 GEN6_REG_BCS_SWCTRL_DST_TILING_Y;
79 }
80
81 if (src && src_tiling == GEN6_TILING_Y) {
82 swctrl |= GEN6_REG_BCS_SWCTRL_SRC_TILING_Y << 16 |
83 GEN6_REG_BCS_SWCTRL_SRC_TILING_Y;
84 }
85
86 /*
87 * Most clients expect BLT engine to be stateless. If we have to set
88 * BCS_SWCTRL to a non-default value, we have to set it back in the same
89 * batch buffer.
90 */
91 if (swctrl)
92 max_cmd_size += (4 + 3) * 2;
93
94 if (ilo_cp_space(cp) < max_cmd_size) {
95 ilo_cp_submit(cp, "out of space");
96 assert(ilo_cp_space(cp) >= max_cmd_size);
97 }
98
99 if (swctrl) {
100 /*
101 * From the Ivy Bridge PRM, volume 1 part 4, page 133:
102 *
103 * "SW is required to flush the HW before changing the polarity of
104 * this bit (Tile Y Destination/Source)."
105 */
106 gen6_MI_FLUSH_DW(&cp->builder);
107 gen6_MI_LOAD_REGISTER_IMM(&cp->builder, GEN6_REG_BCS_SWCTRL, swctrl);
108
109 swctrl &= ~(GEN6_REG_BCS_SWCTRL_DST_TILING_Y |
110 GEN6_REG_BCS_SWCTRL_SRC_TILING_Y);
111 }
112
113 return swctrl;
114 }
115
116 static void
ilo_blitter_blt_end(struct ilo_blitter * blitter,uint32_t swctrl)117 ilo_blitter_blt_end(struct ilo_blitter *blitter, uint32_t swctrl)
118 {
119 struct ilo_builder *builder = &blitter->ilo->cp->builder;
120
121 /* set BCS_SWCTRL back */
122 if (swctrl) {
123 gen6_MI_FLUSH_DW(builder);
124 gen6_MI_LOAD_REGISTER_IMM(builder, GEN6_REG_BCS_SWCTRL, swctrl);
125 }
126 }
127
128 static bool
buf_clear_region(struct ilo_blitter * blitter,struct ilo_buffer_resource * buf,unsigned offset,uint32_t val,unsigned size,enum gen6_blt_mask value_mask,enum gen6_blt_mask write_mask)129 buf_clear_region(struct ilo_blitter *blitter,
130 struct ilo_buffer_resource *buf, unsigned offset,
131 uint32_t val, unsigned size,
132 enum gen6_blt_mask value_mask,
133 enum gen6_blt_mask write_mask)
134 {
135 const uint8_t rop = 0xf0; /* PATCOPY */
136 const int cpp = gen6_blt_translate_value_cpp(value_mask);
137 struct ilo_builder *builder = &blitter->ilo->cp->builder;
138 struct gen6_blt_bo dst;
139
140 if (offset % cpp || size % cpp)
141 return false;
142
143 dst.bo = buf->vma.bo;
144 dst.offset = buf->vma.bo_offset + offset;
145
146 ilo_blitter_blt_begin(blitter, GEN6_COLOR_BLT__SIZE *
147 (1 + size / 32764 / gen6_blt_max_scanlines),
148 dst.bo, GEN6_TILING_NONE, NULL, GEN6_TILING_NONE);
149
150 while (size) {
151 unsigned width, height;
152
153 width = size;
154 height = 1;
155
156 if (width > gen6_blt_max_bytes_per_scanline) {
157 /* less than INT16_MAX and dword-aligned */
158 width = 32764;
159 height = size / width;
160 if (height > gen6_blt_max_scanlines)
161 height = gen6_blt_max_scanlines;
162
163 dst.pitch = width;
164 } else {
165 dst.pitch = 0;
166 }
167
168 gen6_COLOR_BLT(builder, &dst, val,
169 width, height, rop, value_mask, write_mask);
170
171 dst.offset += dst.pitch * height;
172 size -= width * height;
173 }
174
175 ilo_blitter_blt_end(blitter, 0);
176
177 return true;
178 }
179
180 static bool
buf_copy_region(struct ilo_blitter * blitter,struct ilo_buffer_resource * dst_buf,unsigned dst_offset,struct ilo_buffer_resource * src_buf,unsigned src_offset,unsigned size)181 buf_copy_region(struct ilo_blitter *blitter,
182 struct ilo_buffer_resource *dst_buf, unsigned dst_offset,
183 struct ilo_buffer_resource *src_buf, unsigned src_offset,
184 unsigned size)
185 {
186 const uint8_t rop = 0xcc; /* SRCCOPY */
187 struct ilo_builder *builder = &blitter->ilo->cp->builder;
188 struct gen6_blt_bo dst, src;
189
190 dst.bo = dst_buf->vma.bo;
191 dst.offset = dst_buf->vma.bo_offset + dst_offset;
192 dst.pitch = 0;
193
194 src.bo = src_buf->vma.bo;
195 src.offset = src_buf->vma.bo_offset + src_offset;
196 src.pitch = 0;
197
198 ilo_blitter_blt_begin(blitter, GEN6_SRC_COPY_BLT__SIZE *
199 (1 + size / 32764 / gen6_blt_max_scanlines),
200 dst_buf->vma.bo, GEN6_TILING_NONE,
201 src_buf->vma.bo, GEN6_TILING_NONE);
202
203 while (size) {
204 unsigned width, height;
205
206 width = size;
207 height = 1;
208
209 if (width > gen6_blt_max_bytes_per_scanline) {
210 /* less than INT16_MAX and dword-aligned */
211 width = 32764;
212 height = size / width;
213 if (height > gen6_blt_max_scanlines)
214 height = gen6_blt_max_scanlines;
215
216 dst.pitch = width;
217 src.pitch = width;
218 } else {
219 dst.pitch = 0;
220 src.pitch = 0;
221 }
222
223 gen6_SRC_COPY_BLT(builder, &dst, &src,
224 width, height, rop, GEN6_BLT_MASK_8, GEN6_BLT_MASK_8);
225
226 dst.offset += dst.pitch * height;
227 src.offset += src.pitch * height;
228 size -= width * height;
229 }
230
231 ilo_blitter_blt_end(blitter, 0);
232
233 return true;
234 }
235
236 static bool
tex_clear_region(struct ilo_blitter * blitter,struct ilo_texture * dst_tex,unsigned dst_level,const struct pipe_box * dst_box,uint32_t val,enum gen6_blt_mask value_mask,enum gen6_blt_mask write_mask)237 tex_clear_region(struct ilo_blitter *blitter,
238 struct ilo_texture *dst_tex, unsigned dst_level,
239 const struct pipe_box *dst_box,
240 uint32_t val,
241 enum gen6_blt_mask value_mask,
242 enum gen6_blt_mask write_mask)
243 {
244 const int cpp = gen6_blt_translate_value_cpp(value_mask);
245 const unsigned max_extent = 32767; /* INT16_MAX */
246 const uint8_t rop = 0xf0; /* PATCOPY */
247 struct ilo_builder *builder = &blitter->ilo->cp->builder;
248 struct gen6_blt_xy_bo dst;
249 uint32_t swctrl;
250 int slice;
251
252 /* no W-tiling nor separate stencil support */
253 if (dst_tex->image.tiling == GEN8_TILING_W || dst_tex->separate_s8)
254 return false;
255
256 if (dst_tex->image.bo_stride > max_extent)
257 return false;
258
259 if (dst_box->width * cpp > gen6_blt_max_bytes_per_scanline)
260 return false;
261
262 dst.bo = dst_tex->vma.bo;
263 dst.offset = dst_tex->vma.bo_offset;
264 dst.pitch = dst_tex->image.bo_stride;
265 dst.tiling = dst_tex->image.tiling;
266
267 swctrl = ilo_blitter_blt_begin(blitter,
268 GEN6_XY_COLOR_BLT__SIZE * dst_box->depth,
269 dst_tex->vma.bo, dst_tex->image.tiling, NULL, GEN6_TILING_NONE);
270
271 for (slice = 0; slice < dst_box->depth; slice++) {
272 unsigned x, y;
273
274 ilo_image_get_slice_pos(&dst_tex->image,
275 dst_level, dst_box->z + slice, &x, &y);
276
277 dst.x = x + dst_box->x;
278 dst.y = y + dst_box->y;
279
280 if (dst.x + dst_box->width > max_extent ||
281 dst.y + dst_box->height > max_extent)
282 break;
283
284 gen6_XY_COLOR_BLT(builder, &dst, val,
285 dst_box->width, dst_box->height, rop, value_mask, write_mask);
286 }
287
288 ilo_blitter_blt_end(blitter, swctrl);
289
290 return (slice == dst_box->depth);
291 }
292
293 static bool
tex_copy_region(struct ilo_blitter * blitter,struct ilo_texture * dst_tex,unsigned dst_level,unsigned dst_x,unsigned dst_y,unsigned dst_z,struct ilo_texture * src_tex,unsigned src_level,const struct pipe_box * src_box)294 tex_copy_region(struct ilo_blitter *blitter,
295 struct ilo_texture *dst_tex,
296 unsigned dst_level,
297 unsigned dst_x, unsigned dst_y, unsigned dst_z,
298 struct ilo_texture *src_tex,
299 unsigned src_level,
300 const struct pipe_box *src_box)
301 {
302 const struct util_format_description *desc =
303 util_format_description(dst_tex->image_format);
304 const unsigned max_extent = 32767; /* INT16_MAX */
305 const uint8_t rop = 0xcc; /* SRCCOPY */
306 struct ilo_builder *builder = &blitter->ilo->cp->builder;
307 enum gen6_blt_mask mask;
308 struct gen6_blt_xy_bo dst, src;
309 uint32_t swctrl;
310 int cpp, xscale, slice;
311
312 /* no W-tiling nor separate stencil support */
313 if (dst_tex->image.tiling == GEN8_TILING_W || dst_tex->separate_s8 ||
314 src_tex->image.tiling == GEN8_TILING_W || src_tex->separate_s8)
315 return false;
316
317 if (dst_tex->image.bo_stride > max_extent ||
318 src_tex->image.bo_stride > max_extent)
319 return false;
320
321 cpp = desc->block.bits / 8;
322 xscale = 1;
323
324 /* accommodate for larger cpp */
325 if (cpp > 4) {
326 if (cpp % 2 == 1)
327 return false;
328
329 cpp = (cpp % 4 == 0) ? 4 : 2;
330 xscale = (desc->block.bits / 8) / cpp;
331 }
332
333 if (src_box->width * cpp * xscale > gen6_blt_max_bytes_per_scanline)
334 return false;
335
336 switch (cpp) {
337 case 1:
338 mask = GEN6_BLT_MASK_8;
339 break;
340 case 2:
341 mask = GEN6_BLT_MASK_16;
342 break;
343 case 4:
344 mask = GEN6_BLT_MASK_32;
345 break;
346 default:
347 return false;
348 break;
349 }
350
351 dst.bo = dst_tex->vma.bo;
352 dst.offset = dst_tex->vma.bo_offset;
353 dst.pitch = dst_tex->image.bo_stride;
354 dst.tiling = dst_tex->image.tiling;
355
356 src.bo = src_tex->vma.bo;
357 src.offset = src_tex->vma.bo_offset;
358 src.pitch = src_tex->image.bo_stride;
359 src.tiling = src_tex->image.tiling;
360
361 swctrl = ilo_blitter_blt_begin(blitter,
362 GEN6_XY_SRC_COPY_BLT__SIZE * src_box->depth,
363 dst.bo, dst.tiling, src.bo, src.tiling);
364
365 for (slice = 0; slice < src_box->depth; slice++) {
366 unsigned dx, dy, sx, sy, width, height;
367
368 ilo_image_get_slice_pos(&dst_tex->image,
369 dst_level, dst_z + slice, &dx, &dy);
370 ilo_image_get_slice_pos(&src_tex->image,
371 src_level, src_box->z + slice, &sx, &sy);
372
373 dst.x = (dx + dst_x) * xscale;
374 dst.y = dy + dst_y;
375 src.x = (sx + src_box->x) * xscale;
376 src.y = sy + src_box->y;
377 width = src_box->width * xscale;
378 height = src_box->height;
379
380 /* in blocks */
381 dst.x /= desc->block.width;
382 dst.y /= desc->block.height;
383 src.x /= desc->block.width;
384 src.y /= desc->block.height;
385 width /= desc->block.width;
386 height /= desc->block.height;
387
388 if (src.x + width > max_extent || src.y + height > max_extent ||
389 dst.x + width > max_extent || dst.y + height > max_extent)
390 break;
391
392 gen6_XY_SRC_COPY_BLT(builder, &dst, &src,
393 width, height, rop, mask, mask);
394 }
395
396 ilo_blitter_blt_end(blitter, swctrl);
397
398 return (slice == src_box->depth);
399 }
400
401 bool
ilo_blitter_blt_copy_resource(struct ilo_blitter * blitter,struct pipe_resource * dst,unsigned dst_level,unsigned dst_x,unsigned dst_y,unsigned dst_z,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box)402 ilo_blitter_blt_copy_resource(struct ilo_blitter *blitter,
403 struct pipe_resource *dst, unsigned dst_level,
404 unsigned dst_x, unsigned dst_y, unsigned dst_z,
405 struct pipe_resource *src, unsigned src_level,
406 const struct pipe_box *src_box)
407 {
408 bool success;
409
410 ilo_blit_resolve_slices(blitter->ilo, src, src_level,
411 src_box->z, src_box->depth, ILO_TEXTURE_BLT_READ);
412 ilo_blit_resolve_slices(blitter->ilo, dst, dst_level,
413 dst_z, src_box->depth, ILO_TEXTURE_BLT_WRITE);
414
415 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
416 const unsigned dst_offset = dst_x;
417 const unsigned src_offset = src_box->x;
418 const unsigned size = src_box->width;
419
420 assert(dst_level == 0 && dst_y == 0 && dst_z == 0);
421 assert(src_level == 0 &&
422 src_box->y == 0 &&
423 src_box->z == 0 &&
424 src_box->height == 1 &&
425 src_box->depth == 1);
426
427 success = buf_copy_region(blitter, ilo_buffer_resource(dst), dst_offset,
428 ilo_buffer_resource(src), src_offset, size);
429 }
430 else if (dst->target != PIPE_BUFFER && src->target != PIPE_BUFFER) {
431 success = tex_copy_region(blitter,
432 ilo_texture(dst), dst_level, dst_x, dst_y, dst_z,
433 ilo_texture(src), src_level, src_box);
434 }
435 else {
436 success = false;
437 }
438
439 return success;
440 }
441
442 bool
ilo_blitter_blt_clear_rt(struct ilo_blitter * blitter,struct pipe_surface * rt,const union pipe_color_union * color,unsigned x,unsigned y,unsigned width,unsigned height)443 ilo_blitter_blt_clear_rt(struct ilo_blitter *blitter,
444 struct pipe_surface *rt,
445 const union pipe_color_union *color,
446 unsigned x, unsigned y,
447 unsigned width, unsigned height)
448 {
449 const int cpp = util_format_get_blocksize(rt->format);
450 enum gen6_blt_mask mask;
451 union util_color packed;
452 bool success;
453
454 if (ilo_skip_rendering(blitter->ilo))
455 return true;
456
457 switch (cpp) {
458 case 1:
459 mask = GEN6_BLT_MASK_8;
460 break;
461 case 2:
462 mask = GEN6_BLT_MASK_16;
463 break;
464 case 4:
465 mask = GEN6_BLT_MASK_32;
466 break;
467 default:
468 return false;
469 break;
470 }
471
472 if (util_format_is_pure_integer(rt->format) ||
473 util_format_is_compressed(rt->format))
474 return false;
475
476 ilo_blit_resolve_surface(blitter->ilo, rt, ILO_TEXTURE_BLT_WRITE);
477
478 util_pack_color(color->f, rt->format, &packed);
479
480 if (rt->texture->target == PIPE_BUFFER) {
481 unsigned offset, end, size;
482
483 assert(y == 0 && height == 1);
484
485 offset = (rt->u.buf.first_element + x) * cpp;
486 end = (rt->u.buf.last_element + 1) * cpp;
487
488 size = width * cpp;
489 if (offset + size > end)
490 size = end - offset;
491
492 success = buf_clear_region(blitter, ilo_buffer_resource(rt->texture),
493 offset, packed.ui[0], size, mask, mask);
494 }
495 else {
496 struct pipe_box box;
497
498 u_box_3d(x, y, rt->u.tex.first_layer, width, height,
499 rt->u.tex.last_layer - rt->u.tex.first_layer + 1, &box);
500
501 success = tex_clear_region(blitter, ilo_texture(rt->texture),
502 rt->u.tex.level, &box, packed.ui[0], mask, mask);
503 }
504
505 return success;
506 }
507
508 bool
ilo_blitter_blt_clear_zs(struct ilo_blitter * blitter,struct pipe_surface * zs,unsigned clear_flags,double depth,unsigned stencil,unsigned x,unsigned y,unsigned width,unsigned height)509 ilo_blitter_blt_clear_zs(struct ilo_blitter *blitter,
510 struct pipe_surface *zs,
511 unsigned clear_flags,
512 double depth, unsigned stencil,
513 unsigned x, unsigned y,
514 unsigned width, unsigned height)
515 {
516 enum gen6_blt_mask value_mask, write_mask;
517 struct pipe_box box;
518 uint32_t val;
519
520 if (ilo_skip_rendering(blitter->ilo))
521 return true;
522
523 switch (zs->format) {
524 case PIPE_FORMAT_Z16_UNORM:
525 if (!(clear_flags & PIPE_CLEAR_DEPTH))
526 return true;
527
528 value_mask = GEN6_BLT_MASK_16;
529 write_mask = GEN6_BLT_MASK_16;
530 break;
531 case PIPE_FORMAT_Z32_FLOAT:
532 if (!(clear_flags & PIPE_CLEAR_DEPTH))
533 return true;
534
535 value_mask = GEN6_BLT_MASK_32;
536 write_mask = GEN6_BLT_MASK_32;
537 break;
538 case PIPE_FORMAT_Z24X8_UNORM:
539 if (!(clear_flags & PIPE_CLEAR_DEPTH))
540 return true;
541
542 value_mask = GEN6_BLT_MASK_32;
543 write_mask = GEN6_BLT_MASK_32_LO;
544 break;
545 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
546 if (!(clear_flags & PIPE_CLEAR_DEPTHSTENCIL))
547 return true;
548
549 value_mask = GEN6_BLT_MASK_32;
550
551 if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) == PIPE_CLEAR_DEPTHSTENCIL)
552 write_mask = GEN6_BLT_MASK_32;
553 else if (clear_flags & PIPE_CLEAR_DEPTH)
554 write_mask = GEN6_BLT_MASK_32_LO;
555 else
556 write_mask = GEN6_BLT_MASK_32_HI;
557 break;
558 default:
559 return false;
560 break;
561 }
562
563 ilo_blit_resolve_surface(blitter->ilo, zs, ILO_TEXTURE_BLT_WRITE);
564
565 val = util_pack_z_stencil(zs->format, depth, stencil);
566
567 u_box_3d(x, y, zs->u.tex.first_layer, width, height,
568 zs->u.tex.last_layer - zs->u.tex.first_layer + 1, &box);
569
570 assert(zs->texture->target != PIPE_BUFFER);
571
572 return tex_clear_region(blitter, ilo_texture(zs->texture),
573 zs->u.tex.level, &box, val, value_mask, write_mask);
574 }
575