intel_regions.c revision 6a49473ab5797b1e6ce021e396902f9cb77674ef
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 (region->tiling != I915_TILING_NONE && 120 intel->intelScreen->kernel_exec_fencing) 121 drm_intel_gem_bo_map_gtt(region->buffer); 122 else 123 dri_bo_map(region->buffer, GL_TRUE); 124 region->map = region->buffer->virtual; 125 } 126 127 return region->map; 128} 129 130void 131intel_region_unmap(struct intel_context *intel, struct intel_region *region) 132{ 133 _DBG("%s %p\n", __FUNCTION__, region); 134 if (!--region->map_refcount) { 135 if (region->tiling != I915_TILING_NONE && 136 intel->intelScreen->kernel_exec_fencing) 137 drm_intel_gem_bo_unmap_gtt(region->buffer); 138 else 139 dri_bo_unmap(region->buffer); 140 region->map = NULL; 141 } 142} 143 144static struct intel_region * 145intel_region_alloc_internal(struct intel_context *intel, 146 GLuint cpp, 147 GLuint width, GLuint height, GLuint pitch, 148 dri_bo *buffer) 149{ 150 struct intel_region *region; 151 152 if (buffer == NULL) { 153 _DBG("%s <-- NULL\n", __FUNCTION__); 154 return NULL; 155 } 156 157 region = calloc(sizeof(*region), 1); 158 region->cpp = cpp; 159 region->width = width; 160 region->height = height; 161 region->pitch = pitch; 162 region->refcount = 1; 163 region->buffer = buffer; 164 165 /* Default to no tiling */ 166 region->tiling = I915_TILING_NONE; 167 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; 168 169 _DBG("%s <-- %p\n", __FUNCTION__, region); 170 return region; 171} 172 173struct intel_region * 174intel_region_alloc(struct intel_context *intel, 175 uint32_t tiling, 176 GLuint cpp, GLuint width, GLuint height, GLuint pitch, 177 GLboolean expect_accelerated_upload) 178{ 179 dri_bo *buffer; 180 struct intel_region *region; 181 182 if (expect_accelerated_upload) { 183 buffer = drm_intel_bo_alloc_for_render(intel->bufmgr, "region", 184 pitch * cpp * height, 64); 185 } else { 186 buffer = drm_intel_bo_alloc(intel->bufmgr, "region", 187 pitch * cpp * height, 64); 188 } 189 190 region = intel_region_alloc_internal(intel, cpp, width, height, 191 pitch, buffer); 192 193 if (tiling != I915_TILING_NONE) { 194 assert(((pitch * cpp) & 127) == 0); 195 drm_intel_bo_set_tiling(buffer, &tiling, pitch * cpp); 196 drm_intel_bo_get_tiling(buffer, ®ion->tiling, ®ion->bit_6_swizzle); 197 } 198 199 return region; 200} 201 202struct intel_region * 203intel_region_alloc_for_handle(struct intel_context *intel, 204 GLuint cpp, 205 GLuint width, GLuint height, GLuint pitch, 206 GLuint handle, const char *name) 207{ 208 struct intel_region *region; 209 dri_bo *buffer; 210 int ret; 211 212 buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle); 213 214 region = intel_region_alloc_internal(intel, cpp, 215 width, height, pitch, buffer); 216 if (region == NULL) 217 return region; 218 219 ret = dri_bo_get_tiling(region->buffer, ®ion->tiling, 220 ®ion->bit_6_swizzle); 221 if (ret != 0) { 222 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 223 handle, name, strerror(-ret)); 224 intel_region_release(®ion); 225 return NULL; 226 } 227 228 return region; 229} 230 231void 232intel_region_reference(struct intel_region **dst, struct intel_region *src) 233{ 234 if (src) 235 _DBG("%s %p %d\n", __FUNCTION__, src, src->refcount); 236 237 assert(*dst == NULL); 238 if (src) { 239 src->refcount++; 240 *dst = src; 241 } 242} 243 244void 245intel_region_release(struct intel_region **region_handle) 246{ 247 struct intel_region *region = *region_handle; 248 249 if (region == NULL) { 250 _DBG("%s NULL\n", __FUNCTION__); 251 return; 252 } 253 254 _DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1); 255 256 ASSERT(region->refcount > 0); 257 region->refcount--; 258 259 if (region->refcount == 0) { 260 assert(region->map_refcount == 0); 261 262 if (region->pbo) 263 region->pbo->region = NULL; 264 region->pbo = NULL; 265 dri_bo_unreference(region->buffer); 266 267 if (region->classic_map != NULL) { 268 drmUnmap(region->classic_map, 269 region->pitch * region->cpp * region->height); 270 } 271 272 free(region); 273 } 274 *region_handle = NULL; 275} 276 277/* 278 * XXX Move this into core Mesa? 279 */ 280void 281_mesa_copy_rect(GLubyte * dst, 282 GLuint cpp, 283 GLuint dst_pitch, 284 GLuint dst_x, 285 GLuint dst_y, 286 GLuint width, 287 GLuint height, 288 const GLubyte * src, 289 GLuint src_pitch, GLuint src_x, GLuint src_y) 290{ 291 GLuint i; 292 293 dst_pitch *= cpp; 294 src_pitch *= cpp; 295 dst += dst_x * cpp; 296 src += src_x * cpp; 297 dst += dst_y * dst_pitch; 298 src += src_y * dst_pitch; 299 width *= cpp; 300 301 if (width == dst_pitch && width == src_pitch) 302 memcpy(dst, src, height * width); 303 else { 304 for (i = 0; i < height; i++) { 305 memcpy(dst, src, width); 306 dst += dst_pitch; 307 src += src_pitch; 308 } 309 } 310} 311 312 313/* Upload data to a rectangular sub-region. Lots of choices how to do this: 314 * 315 * - memcpy by span to current destination 316 * - upload data as new buffer and blit 317 * 318 * Currently always memcpy. 319 */ 320void 321intel_region_data(struct intel_context *intel, 322 struct intel_region *dst, 323 GLuint dst_offset, 324 GLuint dstx, GLuint dsty, 325 const void *src, GLuint src_pitch, 326 GLuint srcx, GLuint srcy, GLuint width, GLuint height) 327{ 328 GLboolean locked = GL_FALSE; 329 330 _DBG("%s\n", __FUNCTION__); 331 332 if (intel == NULL) 333 return; 334 335 if (dst->pbo) { 336 if (dstx == 0 && 337 dsty == 0 && width == dst->pitch && height == dst->height) 338 intel_region_release_pbo(intel, dst); 339 else 340 intel_region_cow(intel, dst); 341 } 342 343 if (!intel->locked) { 344 LOCK_HARDWARE(intel); 345 locked = GL_TRUE; 346 } 347 348 _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset, 349 dst->cpp, 350 dst->pitch, 351 dstx, dsty, width, height, src, src_pitch, srcx, srcy); 352 353 intel_region_unmap(intel, dst); 354 355 if (locked) 356 UNLOCK_HARDWARE(intel); 357 358} 359 360/* Copy rectangular sub-regions. Need better logic about when to 361 * push buffers into AGP - will currently do so whenever possible. 362 */ 363void 364intel_region_copy(struct intel_context *intel, 365 struct intel_region *dst, 366 GLuint dst_offset, 367 GLuint dstx, GLuint dsty, 368 struct intel_region *src, 369 GLuint src_offset, 370 GLuint srcx, GLuint srcy, GLuint width, GLuint height) 371{ 372 _DBG("%s\n", __FUNCTION__); 373 374 if (intel == NULL) 375 return; 376 377 if (dst->pbo) { 378 if (dstx == 0 && 379 dsty == 0 && width == dst->pitch && height == dst->height) 380 intel_region_release_pbo(intel, dst); 381 else 382 intel_region_cow(intel, dst); 383 } 384 385 assert(src->cpp == dst->cpp); 386 387 intelEmitCopyBlit(intel, 388 dst->cpp, 389 src->pitch, src->buffer, src_offset, src->tiling, 390 dst->pitch, dst->buffer, dst_offset, dst->tiling, 391 srcx, srcy, dstx, dsty, width, height, 392 GL_COPY); 393} 394 395/* Attach to a pbo, discarding our data. Effectively zero-copy upload 396 * the pbo's data. 397 */ 398void 399intel_region_attach_pbo(struct intel_context *intel, 400 struct intel_region *region, 401 struct intel_buffer_object *pbo) 402{ 403 dri_bo *buffer; 404 405 if (region->pbo == pbo) 406 return; 407 408 _DBG("%s %p %p\n", __FUNCTION__, region, pbo); 409 410 /* If there is already a pbo attached, break the cow tie now. 411 * Don't call intel_region_release_pbo() as that would 412 * unnecessarily allocate a new buffer we would have to immediately 413 * discard. 414 */ 415 if (region->pbo) { 416 region->pbo->region = NULL; 417 region->pbo = NULL; 418 } 419 420 if (region->buffer) { 421 dri_bo_unreference(region->buffer); 422 region->buffer = NULL; 423 } 424 425 /* make sure pbo has a buffer of its own */ 426 buffer = intel_bufferobj_buffer(intel, pbo, INTEL_WRITE_FULL); 427 428 region->pbo = pbo; 429 region->pbo->region = region; 430 dri_bo_reference(buffer); 431 region->buffer = buffer; 432} 433 434 435/* Break the COW tie to the pbo and allocate a new buffer. 436 * The pbo gets to keep the data. 437 */ 438void 439intel_region_release_pbo(struct intel_context *intel, 440 struct intel_region *region) 441{ 442 _DBG("%s %p\n", __FUNCTION__, region); 443 assert(region->buffer == region->pbo->buffer); 444 region->pbo->region = NULL; 445 region->pbo = NULL; 446 dri_bo_unreference(region->buffer); 447 region->buffer = NULL; 448 449 region->buffer = dri_bo_alloc(intel->bufmgr, "region", 450 region->pitch * region->cpp * region->height, 451 64); 452} 453 454/* Break the COW tie to the pbo. Both the pbo and the region end up 455 * with a copy of the data. 456 */ 457void 458intel_region_cow(struct intel_context *intel, struct intel_region *region) 459{ 460 struct intel_buffer_object *pbo = region->pbo; 461 GLboolean was_locked = intel->locked; 462 463 if (intel == NULL) 464 return; 465 466 intel_region_release_pbo(intel, region); 467 468 assert(region->cpp * region->pitch * region->height == pbo->Base.Size); 469 470 _DBG("%s %p (%d bytes)\n", __FUNCTION__, region, pbo->Base.Size); 471 472 /* Now blit from the texture buffer to the new buffer: 473 */ 474 475 was_locked = intel->locked; 476 if (!was_locked) 477 LOCK_HARDWARE(intel); 478 479 intelEmitCopyBlit(intel, 480 region->cpp, 481 region->pitch, pbo->buffer, 0, region->tiling, 482 region->pitch, region->buffer, 0, region->tiling, 483 0, 0, 0, 0, 484 region->pitch, region->height, 485 GL_COPY); 486 487 if (!was_locked) 488 UNLOCK_HARDWARE(intel); 489} 490 491dri_bo * 492intel_region_buffer(struct intel_context *intel, 493 struct intel_region *region, GLuint flag) 494{ 495 if (region->pbo) { 496 if (flag == INTEL_WRITE_PART) 497 intel_region_cow(intel, region); 498 else if (flag == INTEL_WRITE_FULL) 499 intel_region_release_pbo(intel, region); 500 } 501 502 return region->buffer; 503} 504 505static struct intel_region * 506intel_recreate_static(struct intel_context *intel, 507 const char *name, 508 struct intel_region *region, 509 intelRegion *region_desc) 510{ 511 intelScreenPrivate *intelScreen = intel->intelScreen; 512 int ret; 513 514 if (region == NULL) { 515 region = calloc(sizeof(*region), 1); 516 region->refcount = 1; 517 _DBG("%s creating new region %p\n", __FUNCTION__, region); 518 } 519 else { 520 _DBG("%s %p\n", __FUNCTION__, region); 521 } 522 523 if (intel->ctx.Visual.rgbBits == 24) 524 region->cpp = 4; 525 else 526 region->cpp = intel->ctx.Visual.rgbBits / 8; 527 region->pitch = intelScreen->pitch; 528 region->width = intelScreen->width; 529 region->height = intelScreen->height; 530 531 if (region->buffer != NULL) { 532 dri_bo_unreference(region->buffer); 533 region->buffer = NULL; 534 } 535 536 if (intel->ttm) { 537 assert(region_desc->bo_handle != -1); 538 region->buffer = intel_bo_gem_create_from_name(intel->bufmgr, 539 name, 540 region_desc->bo_handle); 541 542 ret = dri_bo_get_tiling(region->buffer, ®ion->tiling, 543 ®ion->bit_6_swizzle); 544 if (ret != 0) { 545 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 546 region_desc->bo_handle, name, strerror(-ret)); 547 intel_region_release(®ion); 548 return NULL; 549 } 550 } else { 551 if (region->classic_map != NULL) { 552 drmUnmap(region->classic_map, 553 region->pitch * region->cpp * region->height); 554 region->classic_map = NULL; 555 } 556 ret = drmMap(intel->driFd, region_desc->handle, 557 region->pitch * region->cpp * region->height, 558 ®ion->classic_map); 559 if (ret != 0) { 560 fprintf(stderr, "Failed to drmMap %s buffer\n", name); 561 free(region); 562 return NULL; 563 } 564 565 region->buffer = intel_bo_fake_alloc_static(intel->bufmgr, 566 name, 567 region_desc->offset, 568 region->pitch * region->cpp * 569 region->height, 570 region->classic_map); 571 572 /* The sarea just gives us a boolean for whether it's tiled or not, 573 * instead of which tiling mode it is. Guess. 574 */ 575 if (region_desc->tiled) { 576 if (IS_965(intel->intelScreen->deviceID) && 577 region_desc == &intelScreen->depth) 578 region->tiling = I915_TILING_Y; 579 else 580 region->tiling = I915_TILING_X; 581 } else { 582 region->tiling = I915_TILING_NONE; 583 } 584 585 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; 586 } 587 588 assert(region->buffer != NULL); 589 590 return region; 591} 592 593/** 594 * Create intel_region structs to describe the static front, back, and depth 595 * buffers created by the xserver. 596 * 597 * Although FBO's mean we now no longer use these as render targets in 598 * all circumstances, they won't go away until the back and depth 599 * buffers become private, and the front buffer will remain even then. 600 * 601 * Note that these don't allocate video memory, just describe 602 * allocations alread made by the X server. 603 */ 604void 605intel_recreate_static_regions(struct intel_context *intel) 606{ 607 intelScreenPrivate *intelScreen = intel->intelScreen; 608 609 intel->front_region = 610 intel_recreate_static(intel, "front", 611 intel->front_region, 612 &intelScreen->front); 613 614 intel->back_region = 615 intel_recreate_static(intel, "back", 616 intel->back_region, 617 &intelScreen->back); 618 619 /* Still assumes front.cpp == depth.cpp. We can kill this when we move to 620 * private buffers. 621 */ 622 intel->depth_region = 623 intel_recreate_static(intel, "depth", 624 intel->depth_region, 625 &intelScreen->depth); 626} 627