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/streaming-load-memcpy.h" 36#include "main/bufferobj.h" 37#include "x86/common_x86_asm.h" 38 39#include "brw_context.h" 40#include "brw_blorp.h" 41#include "intel_buffer_objects.h" 42#include "intel_batchbuffer.h" 43 44static void 45mark_buffer_gpu_usage(struct intel_buffer_object *intel_obj, 46 uint32_t offset, uint32_t size) 47{ 48 intel_obj->gpu_active_start = MIN2(intel_obj->gpu_active_start, offset); 49 intel_obj->gpu_active_end = MAX2(intel_obj->gpu_active_end, offset + size); 50} 51 52static void 53mark_buffer_inactive(struct intel_buffer_object *intel_obj) 54{ 55 intel_obj->gpu_active_start = ~0; 56 intel_obj->gpu_active_end = 0; 57} 58 59static void 60mark_buffer_valid_data(struct intel_buffer_object *intel_obj, 61 uint32_t offset, uint32_t size) 62{ 63 intel_obj->valid_data_start = MIN2(intel_obj->valid_data_start, offset); 64 intel_obj->valid_data_end = MAX2(intel_obj->valid_data_end, offset + size); 65} 66 67static void 68mark_buffer_invalid(struct intel_buffer_object *intel_obj) 69{ 70 intel_obj->valid_data_start = ~0; 71 intel_obj->valid_data_end = 0; 72} 73 74/** Allocates a new brw_bo to store the data for the buffer object. */ 75static void 76alloc_buffer_object(struct brw_context *brw, 77 struct intel_buffer_object *intel_obj) 78{ 79 const struct gl_context *ctx = &brw->ctx; 80 81 uint64_t size = intel_obj->Base.Size; 82 if (ctx->Const.RobustAccess) { 83 /* Pad out buffer objects with an extra 2kB (half a page). 84 * 85 * When pushing UBOs, we need to safeguard against 3DSTATE_CONSTANT_* 86 * reading out of bounds memory. The application might bind a UBO that's 87 * smaller than what the program expects. Ideally, we'd bind an extra 88 * push buffer containing zeros, but we have a limited number of those, 89 * so it's not always viable. Our only safe option is to pad all buffer 90 * objects by the maximum push data length, so that it will never read 91 * past the end of a BO. 92 * 93 * This is unfortunate, but it should result in at most 1 extra page, 94 * which probably isn't too terrible. 95 */ 96 size += 64 * 32; /* max read length of 64 256-bit units */ 97 } 98 intel_obj->buffer = 99 brw_bo_alloc(brw->bufmgr, "bufferobj", size, BRW_MEMZONE_OTHER); 100 101 /* the buffer might be bound as a uniform buffer, need to update it 102 */ 103 if (intel_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER) 104 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER; 105 if (intel_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER) 106 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER; 107 if (intel_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER) 108 brw->ctx.NewDriverState |= BRW_NEW_TEXTURE_BUFFER; 109 if (intel_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER) 110 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER; 111 112 mark_buffer_inactive(intel_obj); 113 mark_buffer_invalid(intel_obj); 114} 115 116static void 117release_buffer(struct intel_buffer_object *intel_obj) 118{ 119 brw_bo_unreference(intel_obj->buffer); 120 intel_obj->buffer = NULL; 121} 122 123/** 124 * The NewBufferObject() driver hook. 125 * 126 * Allocates a new intel_buffer_object structure and initializes it. 127 * 128 * There is some duplication between mesa's bufferobjects and our 129 * bufmgr buffers. Both have an integer handle and a hashtable to 130 * lookup an opaque structure. It would be nice if the handles and 131 * internal structure where somehow shared. 132 */ 133static struct gl_buffer_object * 134brw_new_buffer_object(struct gl_context * ctx, GLuint name) 135{ 136 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object); 137 if (!obj) { 138 _mesa_error_no_memory(__func__); 139 return NULL; 140 } 141 142 _mesa_initialize_buffer_object(ctx, &obj->Base, name); 143 144 obj->buffer = NULL; 145 146 return &obj->Base; 147} 148 149/** 150 * The DeleteBuffer() driver hook. 151 * 152 * Deletes a single OpenGL buffer object. Used by glDeleteBuffers(). 153 */ 154static void 155brw_delete_buffer(struct gl_context * ctx, struct gl_buffer_object *obj) 156{ 157 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 158 159 assert(intel_obj); 160 161 /* Buffer objects are automatically unmapped when deleting according 162 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy 163 * (though it does if you call glDeleteBuffers) 164 */ 165 _mesa_buffer_unmap_all_mappings(ctx, obj); 166 167 brw_bo_unreference(intel_obj->buffer); 168 _mesa_delete_buffer_object(ctx, obj); 169} 170 171 172/** 173 * The BufferData() driver hook. 174 * 175 * Implements glBufferData(), which recreates a buffer object's data store 176 * and populates it with the given data, if present. 177 * 178 * Any data that was previously stored in the buffer object is lost. 179 * 180 * \return true for success, false if out of memory 181 */ 182static GLboolean 183brw_buffer_data(struct gl_context *ctx, 184 GLenum target, 185 GLsizeiptrARB size, 186 const GLvoid *data, 187 GLenum usage, 188 GLbitfield storageFlags, 189 struct gl_buffer_object *obj) 190{ 191 struct brw_context *brw = brw_context(ctx); 192 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 193 194 /* Part of the ABI, but this function doesn't use it. 195 */ 196 (void) target; 197 198 intel_obj->Base.Size = size; 199 intel_obj->Base.Usage = usage; 200 intel_obj->Base.StorageFlags = storageFlags; 201 202 assert(!obj->Mappings[MAP_USER].Pointer); /* Mesa should have unmapped it */ 203 assert(!obj->Mappings[MAP_INTERNAL].Pointer); 204 205 if (intel_obj->buffer != NULL) 206 release_buffer(intel_obj); 207 208 if (size != 0) { 209 alloc_buffer_object(brw, intel_obj); 210 if (!intel_obj->buffer) 211 return false; 212 213 if (data != NULL) { 214 brw_bo_subdata(intel_obj->buffer, 0, size, data); 215 mark_buffer_valid_data(intel_obj, 0, size); 216 } 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 */ 232static void 233brw_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 offset + size <= intel_obj->valid_data_start || 260 intel_obj->valid_data_end <= offset) { 261 void *map = brw_bo_map(brw, intel_obj->buffer, MAP_WRITE | MAP_ASYNC); 262 memcpy(map + offset, data, size); 263 brw_bo_unmap(intel_obj->buffer); 264 265 if (intel_obj->gpu_active_end > intel_obj->gpu_active_start) 266 intel_obj->prefer_stall_to_blit = true; 267 268 mark_buffer_valid_data(intel_obj, offset, size); 269 return; 270 } 271 272 busy = 273 brw_bo_busy(intel_obj->buffer) || 274 brw_batch_references(&brw->batch, intel_obj->buffer); 275 276 if (busy) { 277 if (size == intel_obj->Base.Size || 278 (intel_obj->valid_data_start >= offset && 279 intel_obj->valid_data_end <= offset + size)) { 280 /* Replace the current busy bo so the subdata doesn't stall. */ 281 brw_bo_unreference(intel_obj->buffer); 282 alloc_buffer_object(brw, intel_obj); 283 } else if (!intel_obj->prefer_stall_to_blit) { 284 perf_debug("Using a blit copy to avoid stalling on " 285 "glBufferSubData(%ld, %ld) (%ldkb) to a busy " 286 "(%d-%d) / valid (%d-%d) buffer object.\n", 287 (long)offset, (long)offset + size, (long)(size/1024), 288 intel_obj->gpu_active_start, 289 intel_obj->gpu_active_end, 290 intel_obj->valid_data_start, 291 intel_obj->valid_data_end); 292 struct brw_bo *temp_bo = 293 brw_bo_alloc(brw->bufmgr, "subdata temp", size, BRW_MEMZONE_OTHER); 294 295 brw_bo_subdata(temp_bo, 0, size, data); 296 297 brw_blorp_copy_buffers(brw, 298 temp_bo, 0, 299 intel_obj->buffer, offset, 300 size); 301 brw_emit_mi_flush(brw); 302 303 brw_bo_unreference(temp_bo); 304 mark_buffer_valid_data(intel_obj, offset, size); 305 return; 306 } else { 307 perf_debug("Stalling on glBufferSubData(%ld, %ld) (%ldkb) to a busy " 308 "(%d-%d) buffer object. Use glMapBufferRange() to " 309 "avoid this.\n", 310 (long)offset, (long)offset + size, (long)(size/1024), 311 intel_obj->gpu_active_start, 312 intel_obj->gpu_active_end); 313 intel_batchbuffer_flush(brw); 314 } 315 } 316 317 brw_bo_subdata(intel_obj->buffer, offset, size, data); 318 mark_buffer_inactive(intel_obj); 319 mark_buffer_valid_data(intel_obj, offset, size); 320} 321 322/* Typedef for memcpy function (used in brw_get_buffer_subdata below). */ 323typedef void *(*mem_copy_fn)(void *dest, const void *src, size_t n); 324 325/** 326 * The GetBufferSubData() driver hook. 327 * 328 * Implements glGetBufferSubData(), which copies a subrange of a buffer 329 * object into user memory. 330 */ 331static void 332brw_get_buffer_subdata(struct gl_context *ctx, 333 GLintptrARB offset, 334 GLsizeiptrARB size, 335 GLvoid *data, 336 struct gl_buffer_object *obj) 337{ 338 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 339 struct brw_context *brw = brw_context(ctx); 340 341 assert(intel_obj); 342 if (brw_batch_references(&brw->batch, intel_obj->buffer)) { 343 intel_batchbuffer_flush(brw); 344 } 345 346 unsigned int map_flags = MAP_READ; 347 mem_copy_fn memcpy_fn = memcpy; 348#ifdef USE_SSE41 349 if (!intel_obj->buffer->cache_coherent && cpu_has_sse4_1) { 350 /* Rather than acquire a new WB mmaping of the buffer object and pull 351 * it into the CPU cache, keep using the WC mmap that we have for writes, 352 * and use the magic movntd instructions instead. 353 */ 354 map_flags |= MAP_COHERENT; 355 memcpy_fn = (mem_copy_fn) _mesa_streaming_load_memcpy; 356 } 357#endif 358 359 void *map = brw_bo_map(brw, intel_obj->buffer, map_flags); 360 if (unlikely(!map)) { 361 _mesa_error_no_memory(__func__); 362 return; 363 } 364 memcpy_fn(data, map + offset, size); 365 brw_bo_unmap(intel_obj->buffer); 366 367 mark_buffer_inactive(intel_obj); 368} 369 370 371/** 372 * The MapBufferRange() driver hook. 373 * 374 * This implements both glMapBufferRange() and glMapBuffer(). 375 * 376 * The goal of this extension is to allow apps to accumulate their rendering 377 * at the same time as they accumulate their buffer object. Without it, 378 * you'd end up blocking on execution of rendering every time you mapped 379 * the buffer to put new data in. 380 * 381 * We support it in 3 ways: If unsynchronized, then don't bother 382 * flushing the batchbuffer before mapping the buffer, which can save blocking 383 * in many cases. If we would still block, and they allow the whole buffer 384 * to be invalidated, then just allocate a new buffer to replace the old one. 385 * If not, and we'd block, and they allow the subrange of the buffer to be 386 * invalidated, then we can make a new little BO, let them write into that, 387 * and blit it into the real BO at unmap time. 388 */ 389static void * 390brw_map_buffer_range(struct gl_context *ctx, 391 GLintptr offset, GLsizeiptr length, 392 GLbitfield access, struct gl_buffer_object *obj, 393 gl_map_buffer_index index) 394{ 395 struct brw_context *brw = brw_context(ctx); 396 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 397 398 assert(intel_obj); 399 400 STATIC_ASSERT(GL_MAP_UNSYNCHRONIZED_BIT == MAP_ASYNC); 401 STATIC_ASSERT(GL_MAP_WRITE_BIT == MAP_WRITE); 402 STATIC_ASSERT(GL_MAP_READ_BIT == MAP_READ); 403 STATIC_ASSERT(GL_MAP_PERSISTENT_BIT == MAP_PERSISTENT); 404 STATIC_ASSERT(GL_MAP_COHERENT_BIT == MAP_COHERENT); 405 assert((access & MAP_INTERNAL_MASK) == 0); 406 407 /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also 408 * internally uses our functions directly. 409 */ 410 obj->Mappings[index].Offset = offset; 411 obj->Mappings[index].Length = length; 412 obj->Mappings[index].AccessFlags = access; 413 414 if (intel_obj->buffer == NULL) { 415 obj->Mappings[index].Pointer = NULL; 416 return NULL; 417 } 418 419 /* If the access is synchronized (like a normal buffer mapping), then get 420 * things flushed out so the later mapping syncs appropriately through GEM. 421 * If the user doesn't care about existing buffer contents and mapping would 422 * cause us to block, then throw out the old buffer. 423 * 424 * If they set INVALIDATE_BUFFER, we can pitch the current contents to 425 * achieve the required synchronization. 426 */ 427 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 428 if (brw_batch_references(&brw->batch, intel_obj->buffer)) { 429 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) { 430 brw_bo_unreference(intel_obj->buffer); 431 alloc_buffer_object(brw, intel_obj); 432 } else { 433 perf_debug("Stalling on the GPU for mapping a busy buffer " 434 "object\n"); 435 intel_batchbuffer_flush(brw); 436 } 437 } else if (brw_bo_busy(intel_obj->buffer) && 438 (access & GL_MAP_INVALIDATE_BUFFER_BIT)) { 439 brw_bo_unreference(intel_obj->buffer); 440 alloc_buffer_object(brw, intel_obj); 441 } 442 } 443 444 if (access & MAP_WRITE) 445 mark_buffer_valid_data(intel_obj, offset, length); 446 447 /* If the user is mapping a range of an active buffer object but 448 * doesn't require the current contents of that range, make a new 449 * BO, and we'll copy what they put in there out at unmap or 450 * FlushRange time. 451 * 452 * That is, unless they're looking for a persistent mapping -- we would 453 * need to do blits in the MemoryBarrier call, and it's easier to just do a 454 * GPU stall and do a mapping. 455 */ 456 if (!(access & (GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_PERSISTENT_BIT)) && 457 (access & GL_MAP_INVALIDATE_RANGE_BIT) && 458 brw_bo_busy(intel_obj->buffer)) { 459 /* Ensure that the base alignment of the allocation meets the alignment 460 * guarantees the driver has advertised to the application. 461 */ 462 const unsigned alignment = ctx->Const.MinMapBufferAlignment; 463 464 intel_obj->map_extra[index] = (uintptr_t) offset % alignment; 465 intel_obj->range_map_bo[index] = 466 brw_bo_alloc(brw->bufmgr, "BO blit temp", 467 length + intel_obj->map_extra[index], 468 BRW_MEMZONE_OTHER); 469 void *map = brw_bo_map(brw, intel_obj->range_map_bo[index], access); 470 obj->Mappings[index].Pointer = map + intel_obj->map_extra[index]; 471 return obj->Mappings[index].Pointer; 472 } 473 474 void *map = brw_bo_map(brw, intel_obj->buffer, access); 475 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 476 mark_buffer_inactive(intel_obj); 477 } 478 479 obj->Mappings[index].Pointer = map + offset; 480 return obj->Mappings[index].Pointer; 481} 482 483/** 484 * The FlushMappedBufferRange() driver hook. 485 * 486 * Implements glFlushMappedBufferRange(), which signifies that modifications 487 * have been made to a range of a mapped buffer, and it should be flushed. 488 * 489 * This is only used for buffers mapped with GL_MAP_FLUSH_EXPLICIT_BIT. 490 * 491 * Ideally we'd use a BO to avoid taking up cache space for the temporary 492 * data, but FlushMappedBufferRange may be followed by further writes to 493 * the pointer, so we would have to re-map after emitting our blit, which 494 * would defeat the point. 495 */ 496static void 497brw_flush_mapped_buffer_range(struct gl_context *ctx, 498 GLintptr offset, GLsizeiptr length, 499 struct gl_buffer_object *obj, 500 gl_map_buffer_index index) 501{ 502 struct brw_context *brw = brw_context(ctx); 503 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 504 505 assert(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT); 506 507 /* If we gave a direct mapping of the buffer instead of using a temporary, 508 * then there's nothing to do. 509 */ 510 if (intel_obj->range_map_bo[index] == NULL) 511 return; 512 513 if (length == 0) 514 return; 515 516 /* Note that we're not unmapping our buffer while executing the blit. We 517 * need to have a mapping still at the end of this call, since the user 518 * gets to make further modifications and glFlushMappedBufferRange() calls. 519 * This is safe, because: 520 * 521 * - On LLC platforms, we're using a CPU mapping that's coherent with the 522 * GPU (except for the render caches), so the kernel doesn't need to do 523 * any flushing work for us except for what happens at batch exec time 524 * anyway. 525 * 526 * - On non-LLC platforms, we're using a GTT mapping that writes directly 527 * to system memory (except for the chipset cache that gets flushed at 528 * batch exec time). 529 * 530 * In both cases we don't need to stall for the previous blit to complete 531 * so we can re-map (and we definitely don't want to, since that would be 532 * slow): If the user edits a part of their buffer that's previously been 533 * blitted, then our lack of synchoronization is fine, because either 534 * they'll get some too-new data in the first blit and not do another blit 535 * of that area (but in that case the results are undefined), or they'll do 536 * another blit of that area and the complete newer data will land the 537 * second time. 538 */ 539 brw_blorp_copy_buffers(brw, 540 intel_obj->range_map_bo[index], 541 intel_obj->map_extra[index] + offset, 542 intel_obj->buffer, 543 obj->Mappings[index].Offset + offset, 544 length); 545 mark_buffer_gpu_usage(intel_obj, 546 obj->Mappings[index].Offset + offset, 547 length); 548 brw_emit_mi_flush(brw); 549} 550 551 552/** 553 * The UnmapBuffer() driver hook. 554 * 555 * Implements glUnmapBuffer(). 556 */ 557static GLboolean 558brw_unmap_buffer(struct gl_context *ctx, 559 struct gl_buffer_object *obj, 560 gl_map_buffer_index index) 561{ 562 struct brw_context *brw = brw_context(ctx); 563 struct intel_buffer_object *intel_obj = intel_buffer_object(obj); 564 565 assert(intel_obj); 566 assert(obj->Mappings[index].Pointer); 567 if (intel_obj->range_map_bo[index] != NULL) { 568 brw_bo_unmap(intel_obj->range_map_bo[index]); 569 570 if (!(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) { 571 brw_blorp_copy_buffers(brw, 572 intel_obj->range_map_bo[index], 573 intel_obj->map_extra[index], 574 intel_obj->buffer, obj->Mappings[index].Offset, 575 obj->Mappings[index].Length); 576 mark_buffer_gpu_usage(intel_obj, obj->Mappings[index].Offset, 577 obj->Mappings[index].Length); 578 brw_emit_mi_flush(brw); 579 } 580 581 /* Since we've emitted some blits to buffers that will (likely) be used 582 * in rendering operations in other cache domains in this batch, emit a 583 * flush. Once again, we wish for a domain tracker in libdrm to cover 584 * usage inside of a batchbuffer. 585 */ 586 587 brw_bo_unreference(intel_obj->range_map_bo[index]); 588 intel_obj->range_map_bo[index] = NULL; 589 } else if (intel_obj->buffer != NULL) { 590 brw_bo_unmap(intel_obj->buffer); 591 } 592 obj->Mappings[index].Pointer = NULL; 593 obj->Mappings[index].Offset = 0; 594 obj->Mappings[index].Length = 0; 595 596 return true; 597} 598 599/** 600 * Gets a pointer to the object's BO, and marks the given range as being used 601 * on the GPU. 602 * 603 * Anywhere that uses buffer objects in the pipeline should be using this to 604 * mark the range of the buffer that is being accessed by the pipeline. 605 */ 606struct brw_bo * 607intel_bufferobj_buffer(struct brw_context *brw, 608 struct intel_buffer_object *intel_obj, 609 uint32_t offset, uint32_t size, bool write) 610{ 611 /* This is needed so that things like transform feedback and texture buffer 612 * objects that need a BO but don't want to check that they exist for 613 * draw-time validation can just always get a BO from a GL buffer object. 614 */ 615 if (intel_obj->buffer == NULL) 616 alloc_buffer_object(brw, intel_obj); 617 618 mark_buffer_gpu_usage(intel_obj, offset, size); 619 620 /* If writing, (conservatively) mark this section as having valid data. */ 621 if (write) 622 mark_buffer_valid_data(intel_obj, offset, size); 623 624 return intel_obj->buffer; 625} 626 627/** 628 * The CopyBufferSubData() driver hook. 629 * 630 * Implements glCopyBufferSubData(), which copies a portion of one buffer 631 * object's data to another. Independent source and destination offsets 632 * are allowed. 633 */ 634static void 635brw_copy_buffer_subdata(struct gl_context *ctx, 636 struct gl_buffer_object *src, 637 struct gl_buffer_object *dst, 638 GLintptr read_offset, GLintptr write_offset, 639 GLsizeiptr size) 640{ 641 struct brw_context *brw = brw_context(ctx); 642 struct intel_buffer_object *intel_src = intel_buffer_object(src); 643 struct intel_buffer_object *intel_dst = intel_buffer_object(dst); 644 struct brw_bo *src_bo, *dst_bo; 645 646 if (size == 0) 647 return; 648 649 dst_bo = intel_bufferobj_buffer(brw, intel_dst, write_offset, size, true); 650 src_bo = intel_bufferobj_buffer(brw, intel_src, read_offset, size, false); 651 652 brw_blorp_copy_buffers(brw, 653 src_bo, read_offset, 654 dst_bo, write_offset, size); 655 656 /* Since we've emitted some blits to buffers that will (likely) be used 657 * in rendering operations in other cache domains in this batch, emit a 658 * flush. Once again, we wish for a domain tracker in libdrm to cover 659 * usage inside of a batchbuffer. 660 */ 661 brw_emit_mi_flush(brw); 662} 663 664void 665intelInitBufferObjectFuncs(struct dd_function_table *functions) 666{ 667 functions->NewBufferObject = brw_new_buffer_object; 668 functions->DeleteBuffer = brw_delete_buffer; 669 functions->BufferData = brw_buffer_data; 670 functions->BufferSubData = brw_buffer_subdata; 671 functions->GetBufferSubData = brw_get_buffer_subdata; 672 functions->MapBufferRange = brw_map_buffer_range; 673 functions->FlushMappedBufferRange = brw_flush_mapped_buffer_range; 674 functions->UnmapBuffer = brw_unmap_buffer; 675 functions->CopyBufferSubData = brw_copy_buffer_subdata; 676} 677