1 /* 2 * Copyright 2003 VMware, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 /** 27 * @file intel_buffer_objects.c 28 * 29 * This provides core GL buffer object functionality. 30 */ 31 32 #include "main/imports.h" 33 #include "main/mtypes.h" 34 #include "main/macros.h" 35 #include "main/bufferobj.h" 36 37 #include "brw_context.h" 38 #include "intel_blit.h" 39 #include "intel_buffer_objects.h" 40 #include "intel_batchbuffer.h" 41 42 /** 43 * Map a buffer object; issue performance warnings if mapping causes stalls. 44 * 45 * This matches the drm_intel_bo_map API, but takes an additional human-readable 46 * name for the buffer object to use in the performance debug message. 47 */ 48 int 49 brw_bo_map(struct brw_context *brw, 50 drm_intel_bo *bo, int write_enable, 51 const char *bo_name) 52 { 53 if (likely(!brw->perf_debug) || !drm_intel_bo_busy(bo)) 54 return drm_intel_bo_map(bo, write_enable); 55 56 double start_time = get_time(); 57 58 int ret = drm_intel_bo_map(bo, write_enable); 59 60 perf_debug("CPU mapping a busy %s BO stalled and took %.03f ms.\n", 61 bo_name, (get_time() - start_time) * 1000); 62 63 return ret; 64 } 65 66 int 67 brw_bo_map_gtt(struct brw_context *brw, drm_intel_bo *bo, const char *bo_name) 68 { 69 if (likely(!brw->perf_debug) || !drm_intel_bo_busy(bo)) 70 return drm_intel_gem_bo_map_gtt(bo); 71 72 double start_time = get_time(); 73 74 int ret = drm_intel_gem_bo_map_gtt(bo); 75 76 perf_debug("GTT mapping a busy %s BO stalled and took %.03f ms.\n", 77 bo_name, (get_time() - start_time) * 1000); 78 79 return ret; 80 } 81 82 static void 83 mark_buffer_gpu_usage(struct intel_buffer_object *intel_obj, 84 uint32_t offset, uint32_t size) 85 { 86 intel_obj->gpu_active_start = MIN2(intel_obj->gpu_active_start, offset); 87 intel_obj->gpu_active_end = MAX2(intel_obj->gpu_active_end, offset + size); 88 } 89 90 static void 91 mark_buffer_inactive(struct intel_buffer_object *intel_obj) 92 { 93 intel_obj->gpu_active_start = ~0; 94 intel_obj->gpu_active_end = 0; 95 } 96 97 /** Allocates a new drm_intel_bo to store the data for the buffer object. */ 98 static void 99 alloc_buffer_object(struct brw_context *brw, 100 struct intel_buffer_object *intel_obj) 101 { 102 intel_obj->buffer = drm_intel_bo_alloc(brw->bufmgr, "bufferobj", 103 intel_obj->Base.Size, 64); 104 105 /* the buffer might be bound as a uniform buffer, need to update it 106 */ 107 if (intel_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER) 108 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER; 109 if (intel_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER) 110 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER; 111 if (intel_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER) 112 brw->ctx.NewDriverState |= BRW_NEW_TEXTURE_BUFFER; 113 if (intel_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER) 114 brw->ctx.NewDriverState |= BRW_NEW_ATOMIC_BUFFER; 115 116 mark_buffer_inactive(intel_obj); 117 } 118 119 static void 120 release_buffer(struct intel_buffer_object *intel_obj) 121 { 122 drm_intel_bo_unreference(intel_obj->buffer); 123 intel_obj->buffer = NULL; 124 } 125 126 /** 127 * The NewBufferObject() driver hook. 128 * 129 * Allocates a new intel_buffer_object structure and initializes it. 130 * 131 * There is some duplication between mesa's bufferobjects and our 132 * bufmgr buffers. Both have an integer handle and a hashtable to 133 * lookup an opaque structure. It would be nice if the handles and 134 * internal structure where somehow shared. 135 */ 136 static struct gl_buffer_object * 137 brw_new_buffer_object(struct gl_context * ctx, GLuint name) 138 { 139 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object); 140 if (!obj) { 141 _mesa_error_no_memory(__func__); 142 } 143 144 _mesa_initialize_buffer_object(ctx, &obj->Base, name); 145 146 obj->buffer = NULL; 147 148 return &obj->Base; 149 } 150 151 /** 152 * The DeleteBuffer() driver hook. 153 * 154 * Deletes a single OpenGL buffer object. Used by glDeleteBuffers(). 155 */ 156 static void 157 brw_delete_buffer(struct gl_context * ctx, struct gl_buffer_object *obj) 158 { 159 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 160 161 assert(intel_obj); 162 163 /* Buffer objects are automatically unmapped when deleting according 164 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy 165 * (though it does if you call glDeleteBuffers) 166 */ 167 _mesa_buffer_unmap_all_mappings(ctx, obj); 168 169 drm_intel_bo_unreference(intel_obj->buffer); 170 _mesa_delete_buffer_object(ctx, obj); 171 } 172 173 174 /** 175 * The BufferData() driver hook. 176 * 177 * Implements glBufferData(), which recreates a buffer object's data store 178 * and populates it with the given data, if present. 179 * 180 * Any data that was previously stored in the buffer object is lost. 181 * 182 * \return true for success, false if out of memory 183 */ 184 static GLboolean 185 brw_buffer_data(struct gl_context *ctx, 186 GLenum target, 187 GLsizeiptrARB size, 188 const GLvoid *data, 189 GLenum usage, 190 GLbitfield storageFlags, 191 struct gl_buffer_object *obj) 192 { 193 struct brw_context *brw = brw_context(ctx); 194 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 195 196 /* Part of the ABI, but this function doesn't use it. 197 */ 198 (void) target; 199 200 intel_obj->Base.Size = size; 201 intel_obj->Base.Usage = usage; 202 intel_obj->Base.StorageFlags = storageFlags; 203 204 assert(!obj->Mappings[MAP_USER].Pointer); /* Mesa should have unmapped it */ 205 assert(!obj->Mappings[MAP_INTERNAL].Pointer); 206 207 if (intel_obj->buffer != NULL) 208 release_buffer(intel_obj); 209 210 if (size != 0) { 211 alloc_buffer_object(brw, intel_obj); 212 if (!intel_obj->buffer) 213 return false; 214 215 if (data != NULL) 216 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); 217 } 218 219 return true; 220 } 221 222 223 /** 224 * The BufferSubData() driver hook. 225 * 226 * Implements glBufferSubData(), which replaces a portion of the data in a 227 * buffer object. 228 * 229 * If the data range specified by (size + offset) extends beyond the end of 230 * the buffer or if data is NULL, no copy is performed. 231 */ 232 static void 233 brw_buffer_subdata(struct gl_context *ctx, 234 GLintptrARB offset, 235 GLsizeiptrARB size, 236 const GLvoid *data, 237 struct gl_buffer_object *obj) 238 { 239 struct brw_context *brw = brw_context(ctx); 240 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 241 bool busy; 242 243 if (size == 0) 244 return; 245 246 assert(intel_obj); 247 248 /* See if we can unsynchronized write the data into the user's BO. This 249 * avoids GPU stalls in unfortunately common user patterns (uploading 250 * sequentially into a BO, with draw calls in between each upload). 251 * 252 * Once we've hit this path, we mark this GL BO as preferring stalling to 253 * blits, so that we can hopefully hit this path again in the future 254 * (otherwise, an app that might occasionally stall but mostly not will end 255 * up with blitting all the time, at the cost of bandwidth) 256 */ 257 if (offset + size <= intel_obj->gpu_active_start || 258 intel_obj->gpu_active_end <= offset) { 259 if (brw->has_llc) { 260 drm_intel_gem_bo_map_unsynchronized(intel_obj->buffer); 261 memcpy(intel_obj->buffer->virtual + offset, data, size); 262 drm_intel_bo_unmap(intel_obj->buffer); 263 264 if (intel_obj->gpu_active_end > intel_obj->gpu_active_start) 265 intel_obj->prefer_stall_to_blit = true; 266 return; 267 } else { 268 perf_debug("BufferSubData could be unsynchronized, but !LLC doesn't support it yet\n"); 269 } 270 } 271 272 busy = 273 drm_intel_bo_busy(intel_obj->buffer) || 274 drm_intel_bo_references(brw->batch.bo, intel_obj->buffer); 275 276 if (busy) { 277 if (size == intel_obj->Base.Size) { 278 /* Replace the current busy bo so the subdata doesn't stall. */ 279 drm_intel_bo_unreference(intel_obj->buffer); 280 alloc_buffer_object(brw, intel_obj); 281 } else if (!intel_obj->prefer_stall_to_blit) { 282 perf_debug("Using a blit copy to avoid stalling on " 283 "glBufferSubData(%ld, %ld) (%ldkb) to a busy " 284 "(%d-%d) buffer object.\n", 285 (long)offset, (long)offset + size, (long)(size/1024), 286 intel_obj->gpu_active_start, 287 intel_obj->gpu_active_end); 288 drm_intel_bo *temp_bo = 289 drm_intel_bo_alloc(brw->bufmgr, "subdata temp", size, 64); 290 291 drm_intel_bo_subdata(temp_bo, 0, size, data); 292 293 intel_emit_linear_blit(brw, 294 intel_obj->buffer, offset, 295 temp_bo, 0, 296 size); 297 298 drm_intel_bo_unreference(temp_bo); 299 return; 300 } else { 301 perf_debug("Stalling on glBufferSubData(%ld, %ld) (%ldkb) to a busy " 302 "(%d-%d) buffer object. Use glMapBufferRange() to " 303 "avoid this.\n", 304 (long)offset, (long)offset + size, (long)(size/1024), 305 intel_obj->gpu_active_start, 306 intel_obj->gpu_active_end); 307 intel_batchbuffer_flush(brw); 308 } 309 } 310 311 drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); 312 mark_buffer_inactive(intel_obj); 313 } 314 315 316 /** 317 * The GetBufferSubData() driver hook. 318 * 319 * Implements glGetBufferSubData(), which copies a subrange of a buffer 320 * object into user memory. 321 */ 322 static void 323 brw_get_buffer_subdata(struct gl_context *ctx, 324 GLintptrARB offset, 325 GLsizeiptrARB size, 326 GLvoid *data, 327 struct gl_buffer_object *obj) 328 { 329 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 330 struct brw_context *brw = brw_context(ctx); 331 332 assert(intel_obj); 333 if (drm_intel_bo_references(brw->batch.bo, intel_obj->buffer)) { 334 intel_batchbuffer_flush(brw); 335 } 336 drm_intel_bo_get_subdata(intel_obj->buffer, offset, size, data); 337 338 mark_buffer_inactive(intel_obj); 339 } 340 341 342 /** 343 * The MapBufferRange() driver hook. 344 * 345 * This implements both glMapBufferRange() and glMapBuffer(). 346 * 347 * The goal of this extension is to allow apps to accumulate their rendering 348 * at the same time as they accumulate their buffer object. Without it, 349 * you'd end up blocking on execution of rendering every time you mapped 350 * the buffer to put new data in. 351 * 352 * We support it in 3 ways: If unsynchronized, then don't bother 353 * flushing the batchbuffer before mapping the buffer, which can save blocking 354 * in many cases. If we would still block, and they allow the whole buffer 355 * to be invalidated, then just allocate a new buffer to replace the old one. 356 * If not, and we'd block, and they allow the subrange of the buffer to be 357 * invalidated, then we can make a new little BO, let them write into that, 358 * and blit it into the real BO at unmap time. 359 */ 360 static void * 361 brw_map_buffer_range(struct gl_context *ctx, 362 GLintptr offset, GLsizeiptr length, 363 GLbitfield access, struct gl_buffer_object *obj, 364 gl_map_buffer_index index) 365 { 366 struct brw_context *brw = brw_context(ctx); 367 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 368 369 assert(intel_obj); 370 371 /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also 372 * internally uses our functions directly. 373 */ 374 obj->Mappings[index].Offset = offset; 375 obj->Mappings[index].Length = length; 376 obj->Mappings[index].AccessFlags = access; 377 378 if (intel_obj->buffer == NULL) { 379 obj->Mappings[index].Pointer = NULL; 380 return NULL; 381 } 382 383 /* If the access is synchronized (like a normal buffer mapping), then get 384 * things flushed out so the later mapping syncs appropriately through GEM. 385 * If the user doesn't care about existing buffer contents and mapping would 386 * cause us to block, then throw out the old buffer. 387 * 388 * If they set INVALIDATE_BUFFER, we can pitch the current contents to 389 * achieve the required synchronization. 390 */ 391 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 392 if (drm_intel_bo_references(brw->batch.bo, intel_obj->buffer)) { 393 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) { 394 drm_intel_bo_unreference(intel_obj->buffer); 395 alloc_buffer_object(brw, intel_obj); 396 } else { 397 perf_debug("Stalling on the GPU for mapping a busy buffer " 398 "object\n"); 399 intel_batchbuffer_flush(brw); 400 } 401 } else if (drm_intel_bo_busy(intel_obj->buffer) && 402 (access & GL_MAP_INVALIDATE_BUFFER_BIT)) { 403 drm_intel_bo_unreference(intel_obj->buffer); 404 alloc_buffer_object(brw, intel_obj); 405 } 406 } 407 408 /* If the user is mapping a range of an active buffer object but 409 * doesn't require the current contents of that range, make a new 410 * BO, and we'll copy what they put in there out at unmap or 411 * FlushRange time. 412 * 413 * That is, unless they're looking for a persistent mapping -- we would 414 * need to do blits in the MemoryBarrier call, and it's easier to just do a 415 * GPU stall and do a mapping. 416 */ 417 if (!(access & (GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_PERSISTENT_BIT)) && 418 (access & GL_MAP_INVALIDATE_RANGE_BIT) && 419 drm_intel_bo_busy(intel_obj->buffer)) { 420 /* Ensure that the base alignment of the allocation meets the alignment 421 * guarantees the driver has advertised to the application. 422 */ 423 const unsigned alignment = ctx->Const.MinMapBufferAlignment; 424 425 intel_obj->map_extra[index] = (uintptr_t) offset % alignment; 426 intel_obj->range_map_bo[index] = drm_intel_bo_alloc(brw->bufmgr, 427 "BO blit temp", 428 length + 429 intel_obj->map_extra[index], 430 alignment); 431 if (brw->has_llc) { 432 brw_bo_map(brw, intel_obj->range_map_bo[index], 433 (access & GL_MAP_WRITE_BIT) != 0, "range-map"); 434 } else { 435 drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo[index]); 436 } 437 obj->Mappings[index].Pointer = 438 intel_obj->range_map_bo[index]->virtual + intel_obj->map_extra[index]; 439 return obj->Mappings[index].Pointer; 440 } 441 442 if (access & GL_MAP_UNSYNCHRONIZED_BIT) { 443 if (!brw->has_llc && brw->perf_debug && 444 drm_intel_bo_busy(intel_obj->buffer)) { 445 perf_debug("MapBufferRange with GL_MAP_UNSYNCHRONIZED_BIT stalling (it's actually synchronized on non-LLC platforms)\n"); 446 } 447 drm_intel_gem_bo_map_unsynchronized(intel_obj->buffer); 448 } else if (!brw->has_llc && (!(access & GL_MAP_READ_BIT) || 449 (access & GL_MAP_PERSISTENT_BIT))) { 450 drm_intel_gem_bo_map_gtt(intel_obj->buffer); 451 mark_buffer_inactive(intel_obj); 452 } else { 453 brw_bo_map(brw, intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0, 454 "MapBufferRange"); 455 mark_buffer_inactive(intel_obj); 456 } 457 458 obj->Mappings[index].Pointer = intel_obj->buffer->virtual + offset; 459 return obj->Mappings[index].Pointer; 460 } 461 462 /** 463 * The FlushMappedBufferRange() driver hook. 464 * 465 * Implements glFlushMappedBufferRange(), which signifies that modifications 466 * have been made to a range of a mapped buffer, and it should be flushed. 467 * 468 * This is only used for buffers mapped with GL_MAP_FLUSH_EXPLICIT_BIT. 469 * 470 * Ideally we'd use a BO to avoid taking up cache space for the temporary 471 * data, but FlushMappedBufferRange may be followed by further writes to 472 * the pointer, so we would have to re-map after emitting our blit, which 473 * would defeat the point. 474 */ 475 static void 476 brw_flush_mapped_buffer_range(struct gl_context *ctx, 477 GLintptr offset, GLsizeiptr length, 478 struct gl_buffer_object *obj, 479 gl_map_buffer_index index) 480 { 481 struct brw_context *brw = brw_context(ctx); 482 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 483 484 assert(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT); 485 486 /* If we gave a direct mapping of the buffer instead of using a temporary, 487 * then there's nothing to do. 488 */ 489 if (intel_obj->range_map_bo[index] == NULL) 490 return; 491 492 if (length == 0) 493 return; 494 495 /* Note that we're not unmapping our buffer while executing the blit. We 496 * need to have a mapping still at the end of this call, since the user 497 * gets to make further modifications and glFlushMappedBufferRange() calls. 498 * This is safe, because: 499 * 500 * - On LLC platforms, we're using a CPU mapping that's coherent with the 501 * GPU (except for the render caches), so the kernel doesn't need to do 502 * any flushing work for us except for what happens at batch exec time 503 * anyway. 504 * 505 * - On non-LLC platforms, we're using a GTT mapping that writes directly 506 * to system memory (except for the chipset cache that gets flushed at 507 * batch exec time). 508 * 509 * In both cases we don't need to stall for the previous blit to complete 510 * so we can re-map (and we definitely don't want to, since that would be 511 * slow): If the user edits a part of their buffer that's previously been 512 * blitted, then our lack of synchoronization is fine, because either 513 * they'll get some too-new data in the first blit and not do another blit 514 * of that area (but in that case the results are undefined), or they'll do 515 * another blit of that area and the complete newer data will land the 516 * second time. 517 */ 518 intel_emit_linear_blit(brw, 519 intel_obj->buffer, 520 obj->Mappings[index].Offset + offset, 521 intel_obj->range_map_bo[index], 522 intel_obj->map_extra[index] + offset, 523 length); 524 mark_buffer_gpu_usage(intel_obj, 525 obj->Mappings[index].Offset + offset, 526 length); 527 } 528 529 530 /** 531 * The UnmapBuffer() driver hook. 532 * 533 * Implements glUnmapBuffer(). 534 */ 535 static GLboolean 536 brw_unmap_buffer(struct gl_context *ctx, 537 struct gl_buffer_object *obj, 538 gl_map_buffer_index index) 539 { 540 struct brw_context *brw = brw_context(ctx); 541 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 542 543 assert(intel_obj); 544 assert(obj->Mappings[index].Pointer); 545 if (intel_obj->range_map_bo[index] != NULL) { 546 drm_intel_bo_unmap(intel_obj->range_map_bo[index]); 547 548 if (!(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) { 549 intel_emit_linear_blit(brw, 550 intel_obj->buffer, obj->Mappings[index].Offset, 551 intel_obj->range_map_bo[index], 552 intel_obj->map_extra[index], 553 obj->Mappings[index].Length); 554 mark_buffer_gpu_usage(intel_obj, obj->Mappings[index].Offset, 555 obj->Mappings[index].Length); 556 } 557 558 /* Since we've emitted some blits to buffers that will (likely) be used 559 * in rendering operations in other cache domains in this batch, emit a 560 * flush. Once again, we wish for a domain tracker in libdrm to cover 561 * usage inside of a batchbuffer. 562 */ 563 brw_emit_mi_flush(brw); 564 565 drm_intel_bo_unreference(intel_obj->range_map_bo[index]); 566 intel_obj->range_map_bo[index] = NULL; 567 } else if (intel_obj->buffer != NULL) { 568 drm_intel_bo_unmap(intel_obj->buffer); 569 } 570 obj->Mappings[index].Pointer = NULL; 571 obj->Mappings[index].Offset = 0; 572 obj->Mappings[index].Length = 0; 573 574 return true; 575 } 576 577 /** 578 * Gets a pointer to the object's BO, and marks the given range as being used 579 * on the GPU. 580 * 581 * Anywhere that uses buffer objects in the pipeline should be using this to 582 * mark the range of the buffer that is being accessed by the pipeline. 583 */ 584 drm_intel_bo * 585 intel_bufferobj_buffer(struct brw_context *brw, 586 struct intel_buffer_object *intel_obj, 587 uint32_t offset, uint32_t size) 588 { 589 /* This is needed so that things like transform feedback and texture buffer 590 * objects that need a BO but don't want to check that they exist for 591 * draw-time validation can just always get a BO from a GL buffer object. 592 */ 593 if (intel_obj->buffer == NULL) 594 alloc_buffer_object(brw, intel_obj); 595 596 mark_buffer_gpu_usage(intel_obj, offset, size); 597 598 return intel_obj->buffer; 599 } 600 601 /** 602 * The CopyBufferSubData() driver hook. 603 * 604 * Implements glCopyBufferSubData(), which copies a portion of one buffer 605 * object's data to another. Independent source and destination offsets 606 * are allowed. 607 */ 608 static void 609 brw_copy_buffer_subdata(struct gl_context *ctx, 610 struct gl_buffer_object *src, 611 struct gl_buffer_object *dst, 612 GLintptr read_offset, GLintptr write_offset, 613 GLsizeiptr size) 614 { 615 struct brw_context *brw = brw_context(ctx); 616 struct intel_buffer_object *intel_src = intel_buffer_object(src); 617 struct intel_buffer_object *intel_dst = intel_buffer_object(dst); 618 drm_intel_bo *src_bo, *dst_bo; 619 620 if (size == 0) 621 return; 622 623 dst_bo = intel_bufferobj_buffer(brw, intel_dst, write_offset, size); 624 src_bo = intel_bufferobj_buffer(brw, intel_src, read_offset, size); 625 626 intel_emit_linear_blit(brw, 627 dst_bo, write_offset, 628 src_bo, read_offset, size); 629 630 /* Since we've emitted some blits to buffers that will (likely) be used 631 * in rendering operations in other cache domains in this batch, emit a 632 * flush. Once again, we wish for a domain tracker in libdrm to cover 633 * usage inside of a batchbuffer. 634 */ 635 brw_emit_mi_flush(brw); 636 } 637 638 void 639 intelInitBufferObjectFuncs(struct dd_function_table *functions) 640 { 641 functions->NewBufferObject = brw_new_buffer_object; 642 functions->DeleteBuffer = brw_delete_buffer; 643 functions->BufferData = brw_buffer_data; 644 functions->BufferSubData = brw_buffer_subdata; 645 functions->GetBufferSubData = brw_get_buffer_subdata; 646 functions->MapBufferRange = brw_map_buffer_range; 647 functions->FlushMappedBufferRange = brw_flush_mapped_buffer_range; 648 functions->UnmapBuffer = brw_unmap_buffer; 649 functions->CopyBufferSubData = brw_copy_buffer_subdata; 650 } 651