intel_regions.c revision 2d57e9640819c7889304d1de9dd5500a1a0f66de
1/************************************************************************** 2 * 3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/* Provide additional functionality on top of bufmgr buffers: 29 * - 2d semantics and blit operations 30 * - refcounting of buffers for multiple images in a buffer. 31 * - refcounting of buffer mappings. 32 * - some logic for moving the buffers to the best memory pools for 33 * given operations. 34 * 35 * Most of this is to make it easier to implement the fixed-layout 36 * mipmap tree required by intel hardware in the face of GL's 37 * programming interface where each image can be specifed in random 38 * order and it isn't clear what layout the tree should have until the 39 * last moment. 40 */ 41 42#include <sys/ioctl.h> 43#include <errno.h> 44 45#include "intel_context.h" 46#include "intel_regions.h" 47#include "intel_blit.h" 48#include "intel_buffer_objects.h" 49#include "intel_bufmgr.h" 50#include "intel_batchbuffer.h" 51#include "intel_chipset.h" 52 53#define FILE_DEBUG_FLAG DEBUG_REGION 54 55/* This should be set to the maximum backtrace size desired. 56 * Set it to 0 to disable backtrace debugging. 57 */ 58#define DEBUG_BACKTRACE_SIZE 0 59 60#if DEBUG_BACKTRACE_SIZE == 0 61/* Use the standard debug output */ 62#define _DBG(...) DBG(__VA_ARGS__) 63#else 64/* Use backtracing debug output */ 65#define _DBG(...) {debug_backtrace(); DBG(__VA_ARGS__);} 66 67/* Backtracing debug support */ 68#include <execinfo.h> 69 70static void 71debug_backtrace(void) 72{ 73 void *trace[DEBUG_BACKTRACE_SIZE]; 74 char **strings = NULL; 75 int traceSize; 76 register int i; 77 78 traceSize = backtrace(trace, DEBUG_BACKTRACE_SIZE); 79 strings = backtrace_symbols(trace, traceSize); 80 if (strings == NULL) { 81 DBG("no backtrace:"); 82 return; 83 } 84 85 /* Spit out all the strings with a colon separator. Ignore 86 * the first, since we don't really care about the call 87 * to debug_backtrace() itself. Skip until the final "/" in 88 * the trace to avoid really long lines. 89 */ 90 for (i = 1; i < traceSize; i++) { 91 char *p = strings[i], *slash = strings[i]; 92 while (*p) { 93 if (*p++ == '/') { 94 slash = p; 95 } 96 } 97 98 DBG("%s:", slash); 99 } 100 101 /* Free up the memory, and we're done */ 102 free(strings); 103} 104 105#endif 106 107 108 109/* XXX: Thread safety? 110 */ 111GLubyte * 112intel_region_map(struct intel_context *intel, struct intel_region *region) 113{ 114 _DBG("%s %p\n", __FUNCTION__, region); 115 if (!region->map_refcount++) { 116 if (region->pbo) 117 intel_region_cow(intel, region); 118 119 if (intel->intelScreen->kernel_exec_fencing) 120 drm_intel_gem_bo_map_gtt(region->buffer); 121 else 122 dri_bo_map(region->buffer, GL_TRUE); 123 region->map = region->buffer->virtual; 124 } 125 126 return region->map; 127} 128 129void 130intel_region_unmap(struct intel_context *intel, struct intel_region *region) 131{ 132 _DBG("%s %p\n", __FUNCTION__, region); 133 if (!--region->map_refcount) { 134 if (intel->intelScreen->kernel_exec_fencing) 135 drm_intel_gem_bo_unmap_gtt(region->buffer); 136 else 137 dri_bo_unmap(region->buffer); 138 region->map = NULL; 139 } 140} 141 142static struct intel_region * 143intel_region_alloc_internal(struct intel_context *intel, 144 GLuint cpp, 145 GLuint width, GLuint height, GLuint pitch, 146 dri_bo *buffer) 147{ 148 struct intel_region *region; 149 150 if (buffer == NULL) { 151 _DBG("%s <-- NULL\n", __FUNCTION__); 152 return NULL; 153 } 154 155 region = calloc(sizeof(*region), 1); 156 region->cpp = cpp; 157 region->width = width; 158 region->height = height; 159 region->pitch = pitch; 160 region->refcount = 1; 161 region->buffer = buffer; 162 163 /* Default to no tiling */ 164 region->tiling = I915_TILING_NONE; 165 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; 166 167 _DBG("%s <-- %p\n", __FUNCTION__, region); 168 return region; 169} 170 171struct intel_region * 172intel_region_alloc(struct intel_context *intel, 173 uint32_t tiling, 174 GLuint cpp, GLuint width, GLuint height, GLuint pitch, 175 GLboolean expect_accelerated_upload) 176{ 177 dri_bo *buffer; 178 struct intel_region *region; 179 180 if (expect_accelerated_upload) { 181 buffer = drm_intel_bo_alloc_for_render(intel->bufmgr, "region", 182 pitch * cpp * height, 64); 183 } else { 184 buffer = drm_intel_bo_alloc(intel->bufmgr, "region", 185 pitch * cpp * height, 64); 186 } 187 188 region = intel_region_alloc_internal(intel, cpp, width, height, 189 pitch, buffer); 190 191 if (tiling != I915_TILING_NONE) { 192 assert(((pitch * cpp) & 511) == 0); 193 drm_intel_bo_set_tiling(buffer, &tiling, pitch * cpp); 194 drm_intel_bo_get_tiling(buffer, ®ion->tiling, ®ion->bit_6_swizzle); 195 } 196 197 return region; 198} 199 200struct intel_region * 201intel_region_alloc_for_handle(struct intel_context *intel, 202 GLuint cpp, 203 GLuint width, GLuint height, GLuint pitch, 204 GLuint handle, const char *name) 205{ 206 struct intel_region *region; 207 dri_bo *buffer; 208 int ret; 209 210 buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle); 211 212 region = intel_region_alloc_internal(intel, cpp, 213 width, height, pitch, buffer); 214 if (region == NULL) 215 return region; 216 217 ret = dri_bo_get_tiling(region->buffer, ®ion->tiling, 218 ®ion->bit_6_swizzle); 219 if (ret != 0) { 220 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 221 handle, name, strerror(-ret)); 222 intel_region_release(®ion); 223 return NULL; 224 } 225 226 return region; 227} 228 229void 230intel_region_reference(struct intel_region **dst, struct intel_region *src) 231{ 232 if (src) 233 _DBG("%s %p %d\n", __FUNCTION__, src, src->refcount); 234 235 assert(*dst == NULL); 236 if (src) { 237 src->refcount++; 238 *dst = src; 239 } 240} 241 242void 243intel_region_release(struct intel_region **region_handle) 244{ 245 struct intel_region *region = *region_handle; 246 247 if (region == NULL) { 248 _DBG("%s NULL\n", __FUNCTION__); 249 return; 250 } 251 252 _DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1); 253 254 ASSERT(region->refcount > 0); 255 region->refcount--; 256 257 if (region->refcount == 0) { 258 assert(region->map_refcount == 0); 259 260 if (region->pbo) 261 region->pbo->region = NULL; 262 region->pbo = NULL; 263 dri_bo_unreference(region->buffer); 264 265 if (region->classic_map != NULL) { 266 drmUnmap(region->classic_map, 267 region->pitch * region->cpp * region->height); 268 } 269 270 free(region); 271 } 272 *region_handle = NULL; 273} 274 275/* 276 * XXX Move this into core Mesa? 277 */ 278void 279_mesa_copy_rect(GLubyte * dst, 280 GLuint cpp, 281 GLuint dst_pitch, 282 GLuint dst_x, 283 GLuint dst_y, 284 GLuint width, 285 GLuint height, 286 const GLubyte * src, 287 GLuint src_pitch, GLuint src_x, GLuint src_y) 288{ 289 GLuint i; 290 291 dst_pitch *= cpp; 292 src_pitch *= cpp; 293 dst += dst_x * cpp; 294 src += src_x * cpp; 295 dst += dst_y * dst_pitch; 296 src += src_y * dst_pitch; 297 width *= cpp; 298 299 if (width == dst_pitch && width == src_pitch) 300 memcpy(dst, src, height * width); 301 else { 302 for (i = 0; i < height; i++) { 303 memcpy(dst, src, width); 304 dst += dst_pitch; 305 src += src_pitch; 306 } 307 } 308} 309 310 311/* Upload data to a rectangular sub-region. Lots of choices how to do this: 312 * 313 * - memcpy by span to current destination 314 * - upload data as new buffer and blit 315 * 316 * Currently always memcpy. 317 */ 318void 319intel_region_data(struct intel_context *intel, 320 struct intel_region *dst, 321 GLuint dst_offset, 322 GLuint dstx, GLuint dsty, 323 const void *src, GLuint src_pitch, 324 GLuint srcx, GLuint srcy, GLuint width, GLuint height) 325{ 326 GLboolean locked = GL_FALSE; 327 328 _DBG("%s\n", __FUNCTION__); 329 330 if (intel == NULL) 331 return; 332 333 if (dst->pbo) { 334 if (dstx == 0 && 335 dsty == 0 && width == dst->pitch && height == dst->height) 336 intel_region_release_pbo(intel, dst); 337 else 338 intel_region_cow(intel, dst); 339 } 340 341 if (!intel->locked) { 342 LOCK_HARDWARE(intel); 343 locked = GL_TRUE; 344 } 345 346 _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset, 347 dst->cpp, 348 dst->pitch, 349 dstx, dsty, width, height, src, src_pitch, srcx, srcy); 350 351 intel_region_unmap(intel, dst); 352 353 if (locked) 354 UNLOCK_HARDWARE(intel); 355 356} 357 358/* Copy rectangular sub-regions. Need better logic about when to 359 * push buffers into AGP - will currently do so whenever possible. 360 */ 361void 362intel_region_copy(struct intel_context *intel, 363 struct intel_region *dst, 364 GLuint dst_offset, 365 GLuint dstx, GLuint dsty, 366 struct intel_region *src, 367 GLuint src_offset, 368 GLuint srcx, GLuint srcy, GLuint width, GLuint height) 369{ 370 _DBG("%s\n", __FUNCTION__); 371 372 if (intel == NULL) 373 return; 374 375 if (dst->pbo) { 376 if (dstx == 0 && 377 dsty == 0 && width == dst->pitch && height == dst->height) 378 intel_region_release_pbo(intel, dst); 379 else 380 intel_region_cow(intel, dst); 381 } 382 383 assert(src->cpp == dst->cpp); 384 385 intelEmitCopyBlit(intel, 386 dst->cpp, 387 src->pitch, src->buffer, src_offset, src->tiling, 388 dst->pitch, dst->buffer, dst_offset, dst->tiling, 389 srcx, srcy, dstx, dsty, width, height, 390 GL_COPY); 391} 392 393/* Fill a rectangular sub-region. Need better logic about when to 394 * push buffers into AGP - will currently do so whenever possible. 395 */ 396void 397intel_region_fill(struct intel_context *intel, 398 struct intel_region *dst, 399 GLuint dst_offset, 400 GLuint dstx, GLuint dsty, 401 GLuint width, GLuint height, GLuint color) 402{ 403 _DBG("%s\n", __FUNCTION__); 404 405 if (intel == NULL) 406 return; 407 408 if (dst->pbo) { 409 if (dstx == 0 && 410 dsty == 0 && width == dst->pitch && height == dst->height) 411 intel_region_release_pbo(intel, dst); 412 else 413 intel_region_cow(intel, dst); 414 } 415 416 intelEmitFillBlit(intel, 417 dst->cpp, 418 dst->pitch, dst->buffer, dst_offset, dst->tiling, 419 dstx, dsty, width, height, color); 420} 421 422/* Attach to a pbo, discarding our data. Effectively zero-copy upload 423 * the pbo's data. 424 */ 425void 426intel_region_attach_pbo(struct intel_context *intel, 427 struct intel_region *region, 428 struct intel_buffer_object *pbo) 429{ 430 if (region->pbo == pbo) 431 return; 432 433 _DBG("%s %p %p\n", __FUNCTION__, region, pbo); 434 435 /* If there is already a pbo attached, break the cow tie now. 436 * Don't call intel_region_release_pbo() as that would 437 * unnecessarily allocate a new buffer we would have to immediately 438 * discard. 439 */ 440 if (region->pbo) { 441 region->pbo->region = NULL; 442 region->pbo = NULL; 443 } 444 445 if (region->buffer) { 446 dri_bo_unreference(region->buffer); 447 region->buffer = NULL; 448 } 449 450 region->pbo = pbo; 451 region->pbo->region = region; 452 dri_bo_reference(pbo->buffer); 453 region->buffer = pbo->buffer; 454} 455 456 457/* Break the COW tie to the pbo and allocate a new buffer. 458 * The pbo gets to keep the data. 459 */ 460void 461intel_region_release_pbo(struct intel_context *intel, 462 struct intel_region *region) 463{ 464 _DBG("%s %p\n", __FUNCTION__, region); 465 assert(region->buffer == region->pbo->buffer); 466 region->pbo->region = NULL; 467 region->pbo = NULL; 468 dri_bo_unreference(region->buffer); 469 region->buffer = NULL; 470 471 region->buffer = dri_bo_alloc(intel->bufmgr, "region", 472 region->pitch * region->cpp * region->height, 473 64); 474} 475 476/* Break the COW tie to the pbo. Both the pbo and the region end up 477 * with a copy of the data. 478 */ 479void 480intel_region_cow(struct intel_context *intel, struct intel_region *region) 481{ 482 struct intel_buffer_object *pbo = region->pbo; 483 GLboolean was_locked = intel->locked; 484 485 if (intel == NULL) 486 return; 487 488 intel_region_release_pbo(intel, region); 489 490 assert(region->cpp * region->pitch * region->height == pbo->Base.Size); 491 492 _DBG("%s %p (%d bytes)\n", __FUNCTION__, region, pbo->Base.Size); 493 494 /* Now blit from the texture buffer to the new buffer: 495 */ 496 497 was_locked = intel->locked; 498 if (!was_locked) 499 LOCK_HARDWARE(intel); 500 501 intelEmitCopyBlit(intel, 502 region->cpp, 503 region->pitch, region->buffer, 0, region->tiling, 504 region->pitch, pbo->buffer, 0, region->tiling, 505 0, 0, 0, 0, 506 region->pitch, region->height, 507 GL_COPY); 508 509 if (!was_locked) 510 UNLOCK_HARDWARE(intel); 511} 512 513dri_bo * 514intel_region_buffer(struct intel_context *intel, 515 struct intel_region *region, GLuint flag) 516{ 517 if (region->pbo) { 518 if (flag == INTEL_WRITE_PART) 519 intel_region_cow(intel, region); 520 else if (flag == INTEL_WRITE_FULL) 521 intel_region_release_pbo(intel, region); 522 } 523 524 return region->buffer; 525} 526 527static struct intel_region * 528intel_recreate_static(struct intel_context *intel, 529 const char *name, 530 struct intel_region *region, 531 intelRegion *region_desc) 532{ 533 intelScreenPrivate *intelScreen = intel->intelScreen; 534 int ret; 535 536 if (region == NULL) { 537 region = calloc(sizeof(*region), 1); 538 region->refcount = 1; 539 _DBG("%s creating new region %p\n", __FUNCTION__, region); 540 } 541 else { 542 _DBG("%s %p\n", __FUNCTION__, region); 543 } 544 545 if (intel->ctx.Visual.rgbBits == 24) 546 region->cpp = 4; 547 else 548 region->cpp = intel->ctx.Visual.rgbBits / 8; 549 region->pitch = intelScreen->pitch; 550 region->width = intelScreen->width; 551 region->height = intelScreen->height; 552 553 if (region->buffer != NULL) { 554 dri_bo_unreference(region->buffer); 555 region->buffer = NULL; 556 } 557 558 if (intel->ttm) { 559 assert(region_desc->bo_handle != -1); 560 region->buffer = intel_bo_gem_create_from_name(intel->bufmgr, 561 name, 562 region_desc->bo_handle); 563 564 ret = dri_bo_get_tiling(region->buffer, ®ion->tiling, 565 ®ion->bit_6_swizzle); 566 if (ret != 0) { 567 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 568 region_desc->bo_handle, name, strerror(-ret)); 569 intel_region_release(®ion); 570 return NULL; 571 } 572 } else { 573 if (region->classic_map != NULL) { 574 drmUnmap(region->classic_map, 575 region->pitch * region->cpp * region->height); 576 region->classic_map = NULL; 577 } 578 ret = drmMap(intel->driFd, region_desc->handle, 579 region->pitch * region->cpp * region->height, 580 ®ion->classic_map); 581 if (ret != 0) { 582 fprintf(stderr, "Failed to drmMap %s buffer\n", name); 583 free(region); 584 return NULL; 585 } 586 587 region->buffer = intel_bo_fake_alloc_static(intel->bufmgr, 588 name, 589 region_desc->offset, 590 region->pitch * region->cpp * 591 region->height, 592 region->classic_map); 593 594 /* The sarea just gives us a boolean for whether it's tiled or not, 595 * instead of which tiling mode it is. Guess. 596 */ 597 if (region_desc->tiled) { 598 if (IS_965(intel->intelScreen->deviceID) && 599 region_desc == &intelScreen->depth) 600 region->tiling = I915_TILING_Y; 601 else 602 region->tiling = I915_TILING_X; 603 } else { 604 region->tiling = I915_TILING_NONE; 605 } 606 607 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; 608 } 609 610 assert(region->buffer != NULL); 611 612 return region; 613} 614 615/** 616 * Create intel_region structs to describe the static front, back, and depth 617 * buffers created by the xserver. 618 * 619 * Although FBO's mean we now no longer use these as render targets in 620 * all circumstances, they won't go away until the back and depth 621 * buffers become private, and the front buffer will remain even then. 622 * 623 * Note that these don't allocate video memory, just describe 624 * allocations alread made by the X server. 625 */ 626void 627intel_recreate_static_regions(struct intel_context *intel) 628{ 629 intelScreenPrivate *intelScreen = intel->intelScreen; 630 631 intel->front_region = 632 intel_recreate_static(intel, "front", 633 intel->front_region, 634 &intelScreen->front); 635 636 intel->back_region = 637 intel_recreate_static(intel, "back", 638 intel->back_region, 639 &intelScreen->back); 640 641 /* Still assumes front.cpp == depth.cpp. We can kill this when we move to 642 * private buffers. 643 */ 644 intel->depth_region = 645 intel_recreate_static(intel, "depth", 646 intel->depth_region, 647 &intelScreen->depth); 648} 649