• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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