ilo_resource.c revision 0ac706535a07d003b9a40f8bad5445dd50f6c35b
11452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee/* 21452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Mesa 3-D graphics library 31452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * 41452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Copyright (C) 2012-2013 LunarG, Inc. 51452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * 61452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Permission is hereby granted, free of charge, to any person obtaining a 71452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * copy of this software and associated documentation files (the "Software"), 81452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * to deal in the Software without restriction, including without limitation 91452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * the rights to use, copy, modify, merge, publish, distribute, sublicense, 101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * and/or sell copies of the Software, and to permit persons to whom the 11ace690f5e440930d7bbad97fdbfdc3eb65e230bebuzbee * Software is furnished to do so, subject to the following conditions: 121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * 1350cf600419109c9cbb0686edc6f7456c13ef7f08buzbee * The above copyright notice and this permission notice shall be included 14ace690f5e440930d7bbad97fdbfdc3eb65e230bebuzbee * in all copies or substantial portions of the Software. 151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * 161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * 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 "ilo_layout.h" 29#include "ilo_screen.h" 30#include "ilo_resource.h" 31 32/* 33 * From the Ivy Bridge PRM, volume 1 part 1, page 105: 34 * 35 * "In addition to restrictions on maximum height, width, and depth, 36 * surfaces are also restricted to a maximum size in bytes. This 37 * maximum is 2 GB for all products and all surface types." 38 */ 39static const size_t ilo_max_resource_size = 1u << 31; 40 41static const char * 42resource_get_bo_name(const struct pipe_resource *templ) 43{ 44 static const char *target_names[PIPE_MAX_TEXTURE_TYPES] = { 45 [PIPE_BUFFER] = "buf", 46 [PIPE_TEXTURE_1D] = "tex-1d", 47 [PIPE_TEXTURE_2D] = "tex-2d", 48 [PIPE_TEXTURE_3D] = "tex-3d", 49 [PIPE_TEXTURE_CUBE] = "tex-cube", 50 [PIPE_TEXTURE_RECT] = "tex-rect", 51 [PIPE_TEXTURE_1D_ARRAY] = "tex-1d-array", 52 [PIPE_TEXTURE_2D_ARRAY] = "tex-2d-array", 53 [PIPE_TEXTURE_CUBE_ARRAY] = "tex-cube-array", 54 }; 55 const char *name = target_names[templ->target]; 56 57 if (templ->target == PIPE_BUFFER) { 58 switch (templ->bind) { 59 case PIPE_BIND_VERTEX_BUFFER: 60 name = "buf-vb"; 61 break; 62 case PIPE_BIND_INDEX_BUFFER: 63 name = "buf-ib"; 64 break; 65 case PIPE_BIND_CONSTANT_BUFFER: 66 name = "buf-cb"; 67 break; 68 case PIPE_BIND_STREAM_OUTPUT: 69 name = "buf-so"; 70 break; 71 default: 72 break; 73 } 74 } 75 76 return name; 77} 78 79static bool 80resource_get_cpu_init(const struct pipe_resource *templ) 81{ 82 return (templ->bind & (PIPE_BIND_DEPTH_STENCIL | 83 PIPE_BIND_RENDER_TARGET | 84 PIPE_BIND_STREAM_OUTPUT)) ? false : true; 85} 86 87static enum gen_surface_tiling 88winsys_to_surface_tiling(enum intel_tiling_mode tiling) 89{ 90 switch (tiling) { 91 case INTEL_TILING_NONE: 92 return GEN6_TILING_NONE; 93 case INTEL_TILING_X: 94 return GEN6_TILING_X; 95 case INTEL_TILING_Y: 96 return GEN6_TILING_Y; 97 default: 98 assert(!"unknown tiling"); 99 return GEN6_TILING_NONE; 100 } 101} 102 103static inline enum intel_tiling_mode 104surface_to_winsys_tiling(enum gen_surface_tiling tiling) 105{ 106 switch (tiling) { 107 case GEN6_TILING_NONE: 108 return INTEL_TILING_NONE; 109 case GEN6_TILING_X: 110 return INTEL_TILING_X; 111 case GEN6_TILING_Y: 112 return INTEL_TILING_Y; 113 default: 114 assert(!"unknown tiling"); 115 return GEN6_TILING_NONE; 116 } 117} 118 119static void 120tex_free_slices(struct ilo_texture *tex) 121{ 122 FREE(tex->slices[0]); 123} 124 125static bool 126tex_alloc_slices(struct ilo_texture *tex) 127{ 128 const struct pipe_resource *templ = &tex->base; 129 struct ilo_texture_slice *slices; 130 int depth, lv; 131 132 /* sum the depths of all levels */ 133 depth = 0; 134 for (lv = 0; lv <= templ->last_level; lv++) 135 depth += u_minify(templ->depth0, lv); 136 137 /* 138 * There are (depth * tex->base.array_size) slices in total. Either depth 139 * is one (non-3D) or templ->array_size is one (non-array), but it does 140 * not matter. 141 */ 142 slices = CALLOC(depth * templ->array_size, sizeof(*slices)); 143 if (!slices) 144 return false; 145 146 tex->slices[0] = slices; 147 148 /* point to the respective positions in the buffer */ 149 for (lv = 1; lv <= templ->last_level; lv++) { 150 tex->slices[lv] = tex->slices[lv - 1] + 151 u_minify(templ->depth0, lv - 1) * templ->array_size; 152 } 153 154 return true; 155} 156 157static bool 158tex_import_handle(struct ilo_texture *tex, 159 const struct winsys_handle *handle) 160{ 161 struct ilo_screen *is = ilo_screen(tex->base.screen); 162 const char *name = resource_get_bo_name(&tex->base); 163 enum intel_tiling_mode tiling; 164 unsigned long pitch; 165 166 tex->bo = intel_winsys_import_handle(is->winsys, name, handle, 167 tex->layout.bo_height, &tiling, &pitch); 168 if (!tex->bo) 169 return false; 170 171 if (!ilo_layout_update_for_imported_bo(&tex->layout, 172 winsys_to_surface_tiling(tiling), pitch)) { 173 ilo_err("imported handle has incompatible tiling/pitch\n"); 174 intel_bo_unreference(tex->bo); 175 tex->bo = NULL; 176 return false; 177 } 178 179 return true; 180} 181 182static bool 183tex_create_bo(struct ilo_texture *tex) 184{ 185 struct ilo_screen *is = ilo_screen(tex->base.screen); 186 const char *name = resource_get_bo_name(&tex->base); 187 const bool cpu_init = resource_get_cpu_init(&tex->base); 188 enum intel_tiling_mode tiling; 189 190 /* no native support */ 191 if (tex->layout.tiling == GEN8_TILING_W) 192 tiling = INTEL_TILING_NONE; 193 else 194 tiling = surface_to_winsys_tiling(tex->layout.tiling); 195 196 tex->bo = intel_winsys_alloc_bo(is->winsys, name, tiling, 197 tex->layout.bo_stride, tex->layout.bo_height, cpu_init); 198 199 return (tex->bo != NULL); 200} 201 202static bool 203tex_create_separate_stencil(struct ilo_texture *tex) 204{ 205 struct pipe_resource templ = tex->base; 206 struct pipe_resource *s8; 207 208 /* 209 * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other 210 * tilings. But that should be fine since it will never be bound as the 211 * stencil buffer, and our transfer code can handle all tilings. 212 */ 213 templ.format = PIPE_FORMAT_S8_UINT; 214 215 s8 = tex->base.screen->resource_create(tex->base.screen, &templ); 216 if (!s8) 217 return false; 218 219 tex->separate_s8 = ilo_texture(s8); 220 221 assert(tex->separate_s8->layout.format == PIPE_FORMAT_S8_UINT); 222 223 return true; 224} 225 226static bool 227tex_create_hiz(struct ilo_texture *tex) 228{ 229 const struct pipe_resource *templ = &tex->base; 230 struct ilo_screen *is = ilo_screen(tex->base.screen); 231 unsigned lv; 232 233 tex->aux_bo = intel_winsys_alloc_buffer(is->winsys, "hiz texture", 234 tex->layout.aux_stride * tex->layout.aux_height, false); 235 if (!tex->aux_bo) 236 return false; 237 238 for (lv = 0; lv <= templ->last_level; lv++) { 239 if (tex->layout.aux_enables & (1 << lv)) { 240 const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ? 241 u_minify(templ->depth0, lv) : templ->array_size; 242 unsigned flags = ILO_TEXTURE_HIZ; 243 244 /* this will trigger a HiZ resolve */ 245 if (tex->imported) 246 flags |= ILO_TEXTURE_CPU_WRITE; 247 248 ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags); 249 } 250 } 251 252 return true; 253} 254 255static bool 256tex_create_mcs(struct ilo_texture *tex) 257{ 258 struct ilo_screen *is = ilo_screen(tex->base.screen); 259 260 assert(tex->layout.aux_enables == (1 << (tex->base.last_level + 1)) - 1); 261 262 tex->aux_bo = intel_winsys_alloc_buffer(is->winsys, "mcs texture", 263 tex->layout.aux_stride * tex->layout.aux_height, false); 264 if (!tex->aux_bo) 265 return false; 266 267 return true; 268} 269 270static void 271tex_destroy(struct ilo_texture *tex) 272{ 273 if (tex->aux_bo) 274 intel_bo_unreference(tex->aux_bo); 275 276 if (tex->separate_s8) 277 tex_destroy(tex->separate_s8); 278 279 if (tex->bo) 280 intel_bo_unreference(tex->bo); 281 282 tex_free_slices(tex); 283 FREE(tex); 284} 285 286static bool 287tex_alloc_bos(struct ilo_texture *tex, 288 const struct winsys_handle *handle) 289{ 290 struct ilo_screen *is = ilo_screen(tex->base.screen); 291 292 if (handle) { 293 if (!tex_import_handle(tex, handle)) 294 return false; 295 } else { 296 if (!tex_create_bo(tex)) 297 return false; 298 } 299 300 /* allocate separate stencil resource */ 301 if (tex->layout.separate_stencil && !tex_create_separate_stencil(tex)) 302 return false; 303 304 switch (tex->layout.aux) { 305 case ILO_LAYOUT_AUX_HIZ: 306 if (!tex_create_hiz(tex)) { 307 /* Separate Stencil Buffer requires HiZ to be enabled */ 308 if (ilo_dev_gen(&is->dev) == ILO_GEN(6) && 309 tex->layout.separate_stencil) 310 return false; 311 } 312 break; 313 case ILO_LAYOUT_AUX_MCS: 314 if (!tex_create_mcs(tex)) 315 return false; 316 break; 317 default: 318 break; 319 } 320 321 return true; 322} 323 324static bool 325tex_init_layout(struct ilo_texture *tex) 326{ 327 struct ilo_screen *is = ilo_screen(tex->base.screen); 328 const struct pipe_resource *templ = &tex->base; 329 struct ilo_layout *layout = &tex->layout; 330 331 ilo_layout_init(layout, &is->dev, templ); 332 333 if (layout->bo_height > ilo_max_resource_size / layout->bo_stride) 334 return false; 335 336 if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) { 337 /* require on-the-fly tiling/untiling or format conversion */ 338 if (layout->tiling == GEN8_TILING_W || layout->separate_stencil || 339 layout->format != templ->format) 340 return false; 341 } 342 343 if (!tex_alloc_slices(tex)) 344 return false; 345 346 return true; 347} 348 349static struct pipe_resource * 350tex_create(struct pipe_screen *screen, 351 const struct pipe_resource *templ, 352 const struct winsys_handle *handle) 353{ 354 struct ilo_texture *tex; 355 356 tex = CALLOC_STRUCT(ilo_texture); 357 if (!tex) 358 return NULL; 359 360 tex->base = *templ; 361 tex->base.screen = screen; 362 pipe_reference_init(&tex->base.reference, 1); 363 364 tex->imported = (handle != NULL); 365 366 if (!tex_init_layout(tex)) { 367 FREE(tex); 368 return NULL; 369 } 370 371 if (!tex_alloc_bos(tex, handle)) { 372 tex_destroy(tex); 373 return NULL; 374 } 375 376 return &tex->base; 377} 378 379static bool 380tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle) 381{ 382 struct ilo_screen *is = ilo_screen(tex->base.screen); 383 enum intel_tiling_mode tiling; 384 int err; 385 386 /* no native support */ 387 if (tex->layout.tiling == GEN8_TILING_W) 388 tiling = INTEL_TILING_NONE; 389 else 390 tiling = surface_to_winsys_tiling(tex->layout.tiling); 391 392 err = intel_winsys_export_handle(is->winsys, tex->bo, tiling, 393 tex->layout.bo_stride, tex->layout.bo_height, handle); 394 395 return !err; 396} 397 398static bool 399buf_create_bo(struct ilo_buffer *buf) 400{ 401 struct ilo_screen *is = ilo_screen(buf->base.screen); 402 const char *name = resource_get_bo_name(&buf->base); 403 const bool cpu_init = resource_get_cpu_init(&buf->base); 404 405 buf->bo = intel_winsys_alloc_buffer(is->winsys, name, 406 buf->bo_size, cpu_init); 407 408 return (buf->bo != NULL); 409} 410 411static void 412buf_destroy(struct ilo_buffer *buf) 413{ 414 intel_bo_unreference(buf->bo); 415 FREE(buf); 416} 417 418static struct pipe_resource * 419buf_create(struct pipe_screen *screen, const struct pipe_resource *templ) 420{ 421 const struct ilo_screen *is = ilo_screen(screen); 422 struct ilo_buffer *buf; 423 424 buf = CALLOC_STRUCT(ilo_buffer); 425 if (!buf) 426 return NULL; 427 428 buf->base = *templ; 429 buf->base.screen = screen; 430 pipe_reference_init(&buf->base.reference, 1); 431 432 buf->bo_size = templ->width0; 433 434 /* 435 * From the Sandy Bridge PRM, volume 1 part 1, page 118: 436 * 437 * "For buffers, which have no inherent "height," padding requirements 438 * are different. A buffer must be padded to the next multiple of 256 439 * array elements, with an additional 16 bytes added beyond that to 440 * account for the L1 cache line." 441 */ 442 if (templ->bind & PIPE_BIND_SAMPLER_VIEW) 443 buf->bo_size = align(buf->bo_size, 256) + 16; 444 445 if ((templ->bind & PIPE_BIND_VERTEX_BUFFER) && 446 ilo_dev_gen(&is->dev) < ILO_GEN(7.5)) { 447 /* 448 * As noted in ilo_translate_format(), we treat some 3-component formats 449 * as 4-component formats to work around hardware limitations. Imagine 450 * the case where the vertex buffer holds a single 451 * PIPE_FORMAT_R16G16B16_FLOAT vertex, and buf->bo_size is 6. The 452 * hardware would fail to fetch it at boundary check because the vertex 453 * buffer is expected to hold a PIPE_FORMAT_R16G16B16A16_FLOAT vertex 454 * and that takes at least 8 bytes. 455 * 456 * For the workaround to work, we should add 2 to the bo size. But that 457 * would waste a page when the bo size is already page aligned. Let's 458 * round it to page size for now and revisit this when needed. 459 */ 460 buf->bo_size = align(buf->bo_size, 4096); 461 } 462 463 if (buf->bo_size < templ->width0 || 464 buf->bo_size > ilo_max_resource_size || 465 !buf_create_bo(buf)) { 466 FREE(buf); 467 return NULL; 468 } 469 470 return &buf->base; 471} 472 473static boolean 474ilo_can_create_resource(struct pipe_screen *screen, 475 const struct pipe_resource *templ) 476{ 477 struct ilo_layout layout; 478 479 if (templ->target == PIPE_BUFFER) 480 return (templ->width0 <= ilo_max_resource_size); 481 482 memset(&layout, 0, sizeof(layout)); 483 ilo_layout_init(&layout, &ilo_screen(screen)->dev, templ); 484 485 return (layout.bo_height <= ilo_max_resource_size / layout.bo_stride); 486} 487 488static struct pipe_resource * 489ilo_resource_create(struct pipe_screen *screen, 490 const struct pipe_resource *templ) 491{ 492 if (templ->target == PIPE_BUFFER) 493 return buf_create(screen, templ); 494 else 495 return tex_create(screen, templ, NULL); 496} 497 498static struct pipe_resource * 499ilo_resource_from_handle(struct pipe_screen *screen, 500 const struct pipe_resource *templ, 501 struct winsys_handle *handle) 502{ 503 if (templ->target == PIPE_BUFFER) 504 return NULL; 505 else 506 return tex_create(screen, templ, handle); 507} 508 509static boolean 510ilo_resource_get_handle(struct pipe_screen *screen, 511 struct pipe_resource *res, 512 struct winsys_handle *handle) 513{ 514 if (res->target == PIPE_BUFFER) 515 return false; 516 else 517 return tex_get_handle(ilo_texture(res), handle); 518 519} 520 521static void 522ilo_resource_destroy(struct pipe_screen *screen, 523 struct pipe_resource *res) 524{ 525 if (res->target == PIPE_BUFFER) 526 buf_destroy(ilo_buffer(res)); 527 else 528 tex_destroy(ilo_texture(res)); 529} 530 531/** 532 * Initialize resource-related functions. 533 */ 534void 535ilo_init_resource_functions(struct ilo_screen *is) 536{ 537 is->base.can_create_resource = ilo_can_create_resource; 538 is->base.resource_create = ilo_resource_create; 539 is->base.resource_from_handle = ilo_resource_from_handle; 540 is->base.resource_get_handle = ilo_resource_get_handle; 541 is->base.resource_destroy = ilo_resource_destroy; 542} 543 544bool 545ilo_buffer_rename_bo(struct ilo_buffer *buf) 546{ 547 struct intel_bo *old_bo = buf->bo; 548 549 if (buf_create_bo(buf)) { 550 intel_bo_unreference(old_bo); 551 return true; 552 } 553 else { 554 buf->bo = old_bo; 555 return false; 556 } 557} 558 559bool 560ilo_texture_rename_bo(struct ilo_texture *tex) 561{ 562 struct intel_bo *old_bo = tex->bo; 563 564 /* an imported texture cannot be renamed */ 565 if (tex->imported) 566 return false; 567 568 if (tex_create_bo(tex)) { 569 intel_bo_unreference(old_bo); 570 return true; 571 } 572 else { 573 tex->bo = old_bo; 574 return false; 575 } 576} 577