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 (at) 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 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 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 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 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 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 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 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 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 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