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