intel_regions.c revision d449627829e1a4a3250a1a723af2f4e3cd5fd194
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 <main/hash.h> 46#include "intel_context.h" 47#include "intel_regions.h" 48#include "intel_blit.h" 49#include "intel_buffer_objects.h" 50#include "intel_bufmgr.h" 51#include "intel_batchbuffer.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 intelFlush(&intel->ctx); 115 116 _DBG("%s %p\n", __FUNCTION__, region); 117 if (!region->map_refcount++) { 118 if (region->pbo) 119 intel_region_cow(intel, region); 120 121 if (region->tiling != I915_TILING_NONE && 122 intel->intelScreen->kernel_exec_fencing) 123 drm_intel_gem_bo_map_gtt(region->buffer); 124 else 125 dri_bo_map(region->buffer, GL_TRUE); 126 region->map = region->buffer->virtual; 127 } 128 129 return region->map; 130} 131 132void 133intel_region_unmap(struct intel_context *intel, struct intel_region *region) 134{ 135 _DBG("%s %p\n", __FUNCTION__, region); 136 if (!--region->map_refcount) { 137 if (region->tiling != I915_TILING_NONE && 138 intel->intelScreen->kernel_exec_fencing) 139 drm_intel_gem_bo_unmap_gtt(region->buffer); 140 else 141 dri_bo_unmap(region->buffer); 142 region->map = NULL; 143 } 144} 145 146static struct intel_region * 147intel_region_alloc_internal(struct intel_context *intel, 148 GLuint cpp, 149 GLuint width, GLuint height, GLuint pitch, 150 dri_bo *buffer) 151{ 152 struct intel_region *region; 153 154 if (buffer == NULL) { 155 _DBG("%s <-- NULL\n", __FUNCTION__); 156 return NULL; 157 } 158 159 region = calloc(sizeof(*region), 1); 160 region->cpp = cpp; 161 region->width = width; 162 region->height = height; 163 region->pitch = pitch; 164 region->refcount = 1; 165 region->buffer = buffer; 166 167 /* Default to no tiling */ 168 region->tiling = I915_TILING_NONE; 169 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; 170 171 _DBG("%s <-- %p\n", __FUNCTION__, region); 172 return region; 173} 174 175struct intel_region * 176intel_region_alloc(struct intel_context *intel, 177 uint32_t tiling, 178 GLuint cpp, GLuint width, GLuint height, GLuint pitch, 179 GLboolean expect_accelerated_upload) 180{ 181 dri_bo *buffer; 182 struct intel_region *region; 183 184 /* If we're tiled, our allocations are in 8 or 32-row blocks, so 185 * failure to align our height means that we won't allocate enough pages. 186 * 187 * If we're untiled, we still have to align to 2 rows high because the 188 * data port accesses 2x2 blocks even if the bottom row isn't to be 189 * rendered, so failure to align means we could walk off the end of the 190 * GTT and fault. 191 */ 192 if (tiling == I915_TILING_X) 193 height = ALIGN(height, 8); 194 else if (tiling == I915_TILING_Y) 195 height = ALIGN(height, 32); 196 else 197 height = ALIGN(height, 2); 198 199 /* If we're untiled, we have to align to 2 rows high because the 200 * data port accesses 2x2 blocks even if the bottom row isn't to be 201 * rendered, so failure to align means we could walk off the end of the 202 * GTT and fault. 203 */ 204 height = ALIGN(height, 2); 205 206 if (expect_accelerated_upload) { 207 buffer = drm_intel_bo_alloc_for_render(intel->bufmgr, "region", 208 pitch * cpp * height, 64); 209 } else { 210 buffer = drm_intel_bo_alloc(intel->bufmgr, "region", 211 pitch * cpp * height, 64); 212 } 213 214 region = intel_region_alloc_internal(intel, cpp, width, height, 215 pitch, buffer); 216 217 if (tiling != I915_TILING_NONE) { 218 assert(((pitch * cpp) & 127) == 0); 219 drm_intel_bo_set_tiling(buffer, &tiling, pitch * cpp); 220 drm_intel_bo_get_tiling(buffer, ®ion->tiling, ®ion->bit_6_swizzle); 221 } 222 223 return region; 224} 225 226struct intel_region * 227intel_region_alloc_for_handle(struct intel_context *intel, 228 GLuint cpp, 229 GLuint width, GLuint height, GLuint pitch, 230 GLuint handle, const char *name) 231{ 232 struct intel_region *region, *dummy; 233 dri_bo *buffer; 234 int ret; 235 236 region = _mesa_HashLookup(intel->intelScreen->named_regions, handle); 237 if (region != NULL) { 238 dummy = NULL; 239 if (region->width != width || region->height != height || 240 region->cpp != cpp || region->pitch != pitch) { 241 fprintf(stderr, 242 "Region for name %d already exists but is not compatible\n", 243 handle); 244 return NULL; 245 } 246 intel_region_reference(&dummy, region); 247 return dummy; 248 } 249 250 buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle); 251 252 region = intel_region_alloc_internal(intel, cpp, 253 width, height, pitch, buffer); 254 if (region == NULL) 255 return region; 256 257 ret = dri_bo_get_tiling(region->buffer, ®ion->tiling, 258 ®ion->bit_6_swizzle); 259 if (ret != 0) { 260 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 261 handle, name, strerror(-ret)); 262 intel_region_release(®ion); 263 return NULL; 264 } 265 266 region->name = handle; 267 region->screen = intel->intelScreen; 268 _mesa_HashInsert(intel->intelScreen->named_regions, handle, region); 269 270 return region; 271} 272 273void 274intel_region_reference(struct intel_region **dst, struct intel_region *src) 275{ 276 if (src) 277 _DBG("%s %p %d\n", __FUNCTION__, src, src->refcount); 278 279 assert(*dst == NULL); 280 if (src) { 281 src->refcount++; 282 *dst = src; 283 } 284} 285 286void 287intel_region_release(struct intel_region **region_handle) 288{ 289 struct intel_region *region = *region_handle; 290 291 if (region == NULL) { 292 _DBG("%s NULL\n", __FUNCTION__); 293 return; 294 } 295 296 _DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1); 297 298 ASSERT(region->refcount > 0); 299 region->refcount--; 300 301 if (region->refcount == 0) { 302 assert(region->map_refcount == 0); 303 304 if (region->pbo) 305 region->pbo->region = NULL; 306 region->pbo = NULL; 307 dri_bo_unreference(region->buffer); 308 309 if (region->name > 0) 310 _mesa_HashRemove(region->screen->named_regions, region->name); 311 312 free(region); 313 } 314 *region_handle = NULL; 315} 316 317/* 318 * XXX Move this into core Mesa? 319 */ 320void 321_mesa_copy_rect(GLubyte * dst, 322 GLuint cpp, 323 GLuint dst_pitch, 324 GLuint dst_x, 325 GLuint dst_y, 326 GLuint width, 327 GLuint height, 328 const GLubyte * src, 329 GLuint src_pitch, GLuint src_x, GLuint src_y) 330{ 331 GLuint i; 332 333 dst_pitch *= cpp; 334 src_pitch *= cpp; 335 dst += dst_x * cpp; 336 src += src_x * cpp; 337 dst += dst_y * dst_pitch; 338 src += src_y * dst_pitch; 339 width *= cpp; 340 341 if (width == dst_pitch && width == src_pitch) 342 memcpy(dst, src, height * width); 343 else { 344 for (i = 0; i < height; i++) { 345 memcpy(dst, src, width); 346 dst += dst_pitch; 347 src += src_pitch; 348 } 349 } 350} 351 352 353/* Upload data to a rectangular sub-region. Lots of choices how to do this: 354 * 355 * - memcpy by span to current destination 356 * - upload data as new buffer and blit 357 * 358 * Currently always memcpy. 359 */ 360void 361intel_region_data(struct intel_context *intel, 362 struct intel_region *dst, 363 GLuint dst_offset, 364 GLuint dstx, GLuint dsty, 365 const void *src, GLuint src_pitch, 366 GLuint srcx, GLuint srcy, GLuint width, GLuint height) 367{ 368 _DBG("%s\n", __FUNCTION__); 369 370 if (intel == NULL) 371 return; 372 373 if (dst->pbo) { 374 if (dstx == 0 && 375 dsty == 0 && width == dst->pitch && height == dst->height) 376 intel_region_release_pbo(intel, dst); 377 else 378 intel_region_cow(intel, dst); 379 } 380 381 intel_prepare_render(intel); 382 383 _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset, 384 dst->cpp, 385 dst->pitch, 386 dstx, dsty, width, height, src, src_pitch, srcx, srcy); 387 388 intel_region_unmap(intel, dst); 389} 390 391/* Copy rectangular sub-regions. Need better logic about when to 392 * push buffers into AGP - will currently do so whenever possible. 393 */ 394GLboolean 395intel_region_copy(struct intel_context *intel, 396 struct intel_region *dst, 397 GLuint dst_offset, 398 GLuint dstx, GLuint dsty, 399 struct intel_region *src, 400 GLuint src_offset, 401 GLuint srcx, GLuint srcy, GLuint width, GLuint height, 402 GLenum logicop) 403{ 404 _DBG("%s\n", __FUNCTION__); 405 406 if (intel == NULL) 407 return GL_FALSE; 408 409 if (dst->pbo) { 410 if (dstx == 0 && 411 dsty == 0 && width == dst->pitch && height == dst->height) 412 intel_region_release_pbo(intel, dst); 413 else 414 intel_region_cow(intel, dst); 415 } 416 417 assert(src->cpp == dst->cpp); 418 419 return intelEmitCopyBlit(intel, 420 dst->cpp, 421 src->pitch, src->buffer, src_offset, src->tiling, 422 dst->pitch, dst->buffer, dst_offset, dst->tiling, 423 srcx, srcy, dstx, dsty, width, height, 424 logicop); 425} 426 427/* Attach to a pbo, discarding our data. Effectively zero-copy upload 428 * the pbo's data. 429 */ 430void 431intel_region_attach_pbo(struct intel_context *intel, 432 struct intel_region *region, 433 struct intel_buffer_object *pbo) 434{ 435 dri_bo *buffer; 436 437 if (region->pbo == pbo) 438 return; 439 440 _DBG("%s %p %p\n", __FUNCTION__, region, pbo); 441 442 /* If there is already a pbo attached, break the cow tie now. 443 * Don't call intel_region_release_pbo() as that would 444 * unnecessarily allocate a new buffer we would have to immediately 445 * discard. 446 */ 447 if (region->pbo) { 448 region->pbo->region = NULL; 449 region->pbo = NULL; 450 } 451 452 if (region->buffer) { 453 dri_bo_unreference(region->buffer); 454 region->buffer = NULL; 455 } 456 457 /* make sure pbo has a buffer of its own */ 458 buffer = intel_bufferobj_buffer(intel, pbo, INTEL_WRITE_FULL); 459 460 region->pbo = pbo; 461 region->pbo->region = region; 462 dri_bo_reference(buffer); 463 region->buffer = buffer; 464 region->tiling = I915_TILING_NONE; 465} 466 467 468/* Break the COW tie to the pbo and allocate a new buffer. 469 * The pbo gets to keep the data. 470 */ 471void 472intel_region_release_pbo(struct intel_context *intel, 473 struct intel_region *region) 474{ 475 _DBG("%s %p\n", __FUNCTION__, region); 476 assert(region->buffer == region->pbo->buffer); 477 region->pbo->region = NULL; 478 region->pbo = NULL; 479 dri_bo_unreference(region->buffer); 480 region->buffer = NULL; 481 482 region->buffer = dri_bo_alloc(intel->bufmgr, "region", 483 region->pitch * region->cpp * region->height, 484 64); 485} 486 487/* Break the COW tie to the pbo. Both the pbo and the region end up 488 * with a copy of the data. 489 */ 490void 491intel_region_cow(struct intel_context *intel, struct intel_region *region) 492{ 493 struct intel_buffer_object *pbo = region->pbo; 494 GLboolean ok; 495 496 intel_region_release_pbo(intel, region); 497 498 assert(region->cpp * region->pitch * region->height == pbo->Base.Size); 499 500 _DBG("%s %p (%d bytes)\n", __FUNCTION__, region, pbo->Base.Size); 501 502 /* Now blit from the texture buffer to the new buffer: 503 */ 504 505 intel_prepare_render(intel); 506 ok = intelEmitCopyBlit(intel, 507 region->cpp, 508 region->pitch, pbo->buffer, 0, region->tiling, 509 region->pitch, region->buffer, 0, region->tiling, 510 0, 0, 0, 0, 511 region->pitch, region->height, 512 GL_COPY); 513 assert(ok); 514} 515 516dri_bo * 517intel_region_buffer(struct intel_context *intel, 518 struct intel_region *region, GLuint flag) 519{ 520 if (region->pbo) { 521 if (flag == INTEL_WRITE_PART) 522 intel_region_cow(intel, region); 523 else if (flag == INTEL_WRITE_FULL) 524 intel_region_release_pbo(intel, region); 525 } 526 527 return region->buffer; 528} 529