1/************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 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 VMWARE 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 29/** 30 * Functions for pixel buffer objects and vertex/element buffer objects. 31 */ 32 33 34#include <inttypes.h> /* for PRId64 macro */ 35 36#include "main/errors.h" 37 38#include "main/mtypes.h" 39#include "main/arrayobj.h" 40#include "main/bufferobj.h" 41 42#include "st_context.h" 43#include "st_cb_bufferobjects.h" 44#include "st_cb_memoryobjects.h" 45#include "st_debug.h" 46#include "st_util.h" 47 48#include "pipe/p_context.h" 49#include "pipe/p_defines.h" 50#include "util/u_inlines.h" 51 52 53/** 54 * There is some duplication between mesa's bufferobjects and our 55 * bufmgr buffers. Both have an integer handle and a hashtable to 56 * lookup an opaque structure. It would be nice if the handles and 57 * internal structure where somehow shared. 58 */ 59static struct gl_buffer_object * 60st_bufferobj_alloc(struct gl_context *ctx, GLuint name) 61{ 62 struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object); 63 64 if (!st_obj) 65 return NULL; 66 67 _mesa_initialize_buffer_object(ctx, &st_obj->Base, name); 68 69 return &st_obj->Base; 70} 71 72 73static void 74release_buffer(struct gl_buffer_object *obj) 75{ 76 struct st_buffer_object *st_obj = st_buffer_object(obj); 77 78 if (!st_obj->buffer) 79 return; 80 81 /* Subtract the remaining private references before unreferencing 82 * the buffer. See the header file for explanation. 83 */ 84 if (st_obj->private_refcount) { 85 assert(st_obj->private_refcount > 0); 86 p_atomic_add(&st_obj->buffer->reference.count, 87 -st_obj->private_refcount); 88 st_obj->private_refcount = 0; 89 } 90 st_obj->ctx = NULL; 91 92 pipe_resource_reference(&st_obj->buffer, NULL); 93} 94 95 96/** 97 * Deallocate/free a vertex/pixel buffer object. 98 * Called via glDeleteBuffersARB(). 99 */ 100static void 101st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj) 102{ 103 assert(obj->RefCount == 0); 104 _mesa_buffer_unmap_all_mappings(ctx, obj); 105 release_buffer(obj); 106 _mesa_delete_buffer_object(ctx, obj); 107} 108 109 110 111/** 112 * Replace data in a subrange of buffer object. If the data range 113 * specified by size + offset extends beyond the end of the buffer or 114 * if data is NULL, no copy is performed. 115 * Called via glBufferSubDataARB(). 116 */ 117static void 118st_bufferobj_subdata(struct gl_context *ctx, 119 GLintptrARB offset, 120 GLsizeiptrARB size, 121 const void * data, struct gl_buffer_object *obj) 122{ 123 struct st_buffer_object *st_obj = st_buffer_object(obj); 124 125 /* we may be called from VBO code, so double-check params here */ 126 assert(offset >= 0); 127 assert(size >= 0); 128 assert(offset + size <= obj->Size); 129 130 if (!size) 131 return; 132 133 /* 134 * According to ARB_vertex_buffer_object specification, if data is null, 135 * then the contents of the buffer object's data store is undefined. We just 136 * ignore, and leave it unchanged. 137 */ 138 if (!data) 139 return; 140 141 if (!st_obj->buffer) { 142 /* we probably ran out of memory during buffer allocation */ 143 return; 144 } 145 146 /* Now that transfers are per-context, we don't have to figure out 147 * flushing here. Usually drivers won't need to flush in this case 148 * even if the buffer is currently referenced by hardware - they 149 * just queue the upload as dma rather than mapping the underlying 150 * buffer directly. 151 * 152 * If the buffer is mapped, suppress implicit buffer range invalidation 153 * by using PIPE_MAP_DIRECTLY. 154 */ 155 struct pipe_context *pipe = st_context(ctx)->pipe; 156 157 pipe->buffer_subdata(pipe, st_obj->buffer, 158 _mesa_bufferobj_mapped(obj, MAP_USER) ? 159 PIPE_MAP_DIRECTLY : 0, 160 offset, size, data); 161} 162 163 164/** 165 * Called via glGetBufferSubDataARB(). 166 */ 167static void 168st_bufferobj_get_subdata(struct gl_context *ctx, 169 GLintptrARB offset, 170 GLsizeiptrARB size, 171 void * data, struct gl_buffer_object *obj) 172{ 173 struct st_buffer_object *st_obj = st_buffer_object(obj); 174 175 /* we may be called from VBO code, so double-check params here */ 176 assert(offset >= 0); 177 assert(size >= 0); 178 assert(offset + size <= obj->Size); 179 180 if (!size) 181 return; 182 183 if (!st_obj->buffer) { 184 /* we probably ran out of memory during buffer allocation */ 185 return; 186 } 187 188 pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer, 189 offset, size, data); 190} 191 192 193/** 194 * Return bitmask of PIPE_BIND_x flags corresponding a GL buffer target. 195 */ 196static unsigned 197buffer_target_to_bind_flags(GLenum target) 198{ 199 switch (target) { 200 case GL_PIXEL_PACK_BUFFER_ARB: 201 case GL_PIXEL_UNPACK_BUFFER_ARB: 202 return PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 203 case GL_ARRAY_BUFFER_ARB: 204 return PIPE_BIND_VERTEX_BUFFER; 205 case GL_ELEMENT_ARRAY_BUFFER_ARB: 206 return PIPE_BIND_INDEX_BUFFER; 207 case GL_TEXTURE_BUFFER: 208 return PIPE_BIND_SAMPLER_VIEW; 209 case GL_TRANSFORM_FEEDBACK_BUFFER: 210 return PIPE_BIND_STREAM_OUTPUT; 211 case GL_UNIFORM_BUFFER: 212 return PIPE_BIND_CONSTANT_BUFFER; 213 case GL_DRAW_INDIRECT_BUFFER: 214 case GL_PARAMETER_BUFFER_ARB: 215 return PIPE_BIND_COMMAND_ARGS_BUFFER; 216 case GL_ATOMIC_COUNTER_BUFFER: 217 case GL_SHADER_STORAGE_BUFFER: 218 return PIPE_BIND_SHADER_BUFFER; 219 case GL_QUERY_BUFFER: 220 return PIPE_BIND_QUERY_BUFFER; 221 default: 222 return 0; 223 } 224} 225 226 227/** 228 * Return bitmask of PIPE_RESOURCE_x flags corresponding to GL_MAP_x flags. 229 */ 230static unsigned 231storage_flags_to_buffer_flags(GLbitfield storageFlags) 232{ 233 unsigned flags = 0; 234 if (storageFlags & GL_MAP_PERSISTENT_BIT) 235 flags |= PIPE_RESOURCE_FLAG_MAP_PERSISTENT; 236 if (storageFlags & GL_MAP_COHERENT_BIT) 237 flags |= PIPE_RESOURCE_FLAG_MAP_COHERENT; 238 if (storageFlags & GL_SPARSE_STORAGE_BIT_ARB) 239 flags |= PIPE_RESOURCE_FLAG_SPARSE; 240 return flags; 241} 242 243 244/** 245 * From a buffer object's target, immutability flag, storage flags and 246 * usage hint, return a pipe_resource_usage value (PIPE_USAGE_DYNAMIC, 247 * STREAM, etc). 248 */ 249static enum pipe_resource_usage 250buffer_usage(GLenum target, GLboolean immutable, 251 GLbitfield storageFlags, GLenum usage) 252{ 253 /* "immutable" means that "storageFlags" was set by the user and "usage" 254 * was guessed by Mesa. Otherwise, "usage" was set by the user and 255 * storageFlags was guessed by Mesa. 256 * 257 * Therefore, use storageFlags with immutable, else use "usage". 258 */ 259 if (immutable) { 260 /* BufferStorage */ 261 if (storageFlags & GL_MAP_READ_BIT) 262 return PIPE_USAGE_STAGING; 263 else if (storageFlags & GL_CLIENT_STORAGE_BIT) 264 return PIPE_USAGE_STREAM; 265 else 266 return PIPE_USAGE_DEFAULT; 267 } 268 else { 269 /* These are often read by the CPU, so enable CPU caches. */ 270 if (target == GL_PIXEL_PACK_BUFFER || 271 target == GL_PIXEL_UNPACK_BUFFER) 272 return PIPE_USAGE_STAGING; 273 274 /* BufferData */ 275 switch (usage) { 276 case GL_DYNAMIC_DRAW: 277 case GL_DYNAMIC_COPY: 278 return PIPE_USAGE_DYNAMIC; 279 case GL_STREAM_DRAW: 280 case GL_STREAM_COPY: 281 return PIPE_USAGE_STREAM; 282 case GL_STATIC_READ: 283 case GL_DYNAMIC_READ: 284 case GL_STREAM_READ: 285 return PIPE_USAGE_STAGING; 286 case GL_STATIC_DRAW: 287 case GL_STATIC_COPY: 288 default: 289 return PIPE_USAGE_DEFAULT; 290 } 291 } 292} 293 294 295static ALWAYS_INLINE GLboolean 296bufferobj_data(struct gl_context *ctx, 297 GLenum target, 298 GLsizeiptrARB size, 299 const void *data, 300 struct gl_memory_object *memObj, 301 GLuint64 offset, 302 GLenum usage, 303 GLbitfield storageFlags, 304 struct gl_buffer_object *obj) 305{ 306 struct st_context *st = st_context(ctx); 307 struct pipe_context *pipe = st->pipe; 308 struct pipe_screen *screen = st->screen; 309 struct st_buffer_object *st_obj = st_buffer_object(obj); 310 struct st_memory_object *st_mem_obj = st_memory_object(memObj); 311 bool is_mapped = _mesa_bufferobj_mapped(obj, MAP_USER); 312 313 if (size > UINT32_MAX || offset > UINT32_MAX) { 314 /* pipe_resource.width0 is 32 bits only and increasing it 315 * to 64 bits doesn't make much sense since hw support 316 * for > 4GB resources is limited. 317 */ 318 st_obj->Base.Size = 0; 319 return GL_FALSE; 320 } 321 322 if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD && 323 size && st_obj->buffer && 324 st_obj->Base.Size == size && 325 st_obj->Base.Usage == usage && 326 st_obj->Base.StorageFlags == storageFlags) { 327 if (data) { 328 /* Just discard the old contents and write new data. 329 * This should be the same as creating a new buffer, but we avoid 330 * a lot of validation in Mesa. 331 * 332 * If the buffer is mapped, we can't discard it. 333 * 334 * PIPE_MAP_DIRECTLY supresses implicit buffer range 335 * invalidation. 336 */ 337 pipe->buffer_subdata(pipe, st_obj->buffer, 338 is_mapped ? PIPE_MAP_DIRECTLY : 339 PIPE_MAP_DISCARD_WHOLE_RESOURCE, 340 0, size, data); 341 return GL_TRUE; 342 } else if (is_mapped) { 343 return GL_TRUE; /* can't reallocate, nothing to do */ 344 } else if (screen->get_param(screen, PIPE_CAP_INVALIDATE_BUFFER)) { 345 pipe->invalidate_resource(pipe, st_obj->buffer); 346 return GL_TRUE; 347 } 348 } 349 350 st_obj->Base.Size = size; 351 st_obj->Base.Usage = usage; 352 st_obj->Base.StorageFlags = storageFlags; 353 354 release_buffer(obj); 355 356 const unsigned bindings = buffer_target_to_bind_flags(target); 357 358 if (ST_DEBUG & DEBUG_BUFFER) { 359 debug_printf("Create buffer size %" PRId64 " bind 0x%x\n", 360 (int64_t) size, bindings); 361 } 362 363 if (size != 0) { 364 struct pipe_resource buffer; 365 366 memset(&buffer, 0, sizeof buffer); 367 buffer.target = PIPE_BUFFER; 368 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ 369 buffer.bind = bindings; 370 buffer.usage = 371 buffer_usage(target, st_obj->Base.Immutable, storageFlags, usage); 372 buffer.flags = storage_flags_to_buffer_flags(storageFlags); 373 buffer.width0 = size; 374 buffer.height0 = 1; 375 buffer.depth0 = 1; 376 buffer.array_size = 1; 377 378 if (st_mem_obj) { 379 st_obj->buffer = screen->resource_from_memobj(screen, &buffer, 380 st_mem_obj->memory, 381 offset); 382 } 383 else if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) { 384 st_obj->buffer = 385 screen->resource_from_user_memory(screen, &buffer, (void*)data); 386 } 387 else { 388 st_obj->buffer = screen->resource_create(screen, &buffer); 389 390 if (st_obj->buffer && data) 391 pipe_buffer_write(pipe, st_obj->buffer, 0, size, data); 392 } 393 394 if (!st_obj->buffer) { 395 /* out of memory */ 396 st_obj->Base.Size = 0; 397 return GL_FALSE; 398 } 399 400 st_obj->ctx = ctx; 401 } 402 403 /* The current buffer may be bound, so we have to revalidate all atoms that 404 * might be using it. 405 */ 406 if (st_obj->Base.UsageHistory & USAGE_ARRAY_BUFFER) 407 ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS; 408 /* if (st_obj->Base.UsageHistory & USAGE_ELEMENT_ARRAY_BUFFER) */ 409 /* ctx->NewDriverState |= TODO: Handle indices as gallium state; */ 410 if (st_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER) 411 ctx->NewDriverState |= ST_NEW_UNIFORM_BUFFER; 412 if (st_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER) 413 ctx->NewDriverState |= ST_NEW_STORAGE_BUFFER; 414 if (st_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER) 415 ctx->NewDriverState |= ST_NEW_SAMPLER_VIEWS | ST_NEW_IMAGE_UNITS; 416 if (st_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER) 417 ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 418 419 return GL_TRUE; 420} 421 422/** 423 * Allocate space for and store data in a buffer object. Any data that was 424 * previously stored in the buffer object is lost. If data is NULL, 425 * memory will be allocated, but no copy will occur. 426 * Called via ctx->Driver.BufferData(). 427 * \return GL_TRUE for success, GL_FALSE if out of memory 428 */ 429static GLboolean 430st_bufferobj_data(struct gl_context *ctx, 431 GLenum target, 432 GLsizeiptrARB size, 433 const void *data, 434 GLenum usage, 435 GLbitfield storageFlags, 436 struct gl_buffer_object *obj) 437{ 438 return bufferobj_data(ctx, target, size, data, NULL, 0, usage, storageFlags, obj); 439} 440 441static GLboolean 442st_bufferobj_data_mem(struct gl_context *ctx, 443 GLenum target, 444 GLsizeiptrARB size, 445 struct gl_memory_object *memObj, 446 GLuint64 offset, 447 GLenum usage, 448 struct gl_buffer_object *bufObj) 449{ 450 return bufferobj_data(ctx, target, size, NULL, memObj, offset, usage, 0, bufObj); 451} 452 453/** 454 * Called via glInvalidateBuffer(Sub)Data. 455 */ 456static void 457st_bufferobj_invalidate(struct gl_context *ctx, 458 struct gl_buffer_object *obj, 459 GLintptr offset, 460 GLsizeiptr size) 461{ 462 struct st_context *st = st_context(ctx); 463 struct pipe_context *pipe = st->pipe; 464 struct st_buffer_object *st_obj = st_buffer_object(obj); 465 466 /* We ignore partial invalidates. */ 467 if (offset != 0 || size != obj->Size) 468 return; 469 470 /* If the buffer is mapped, we can't invalidate it. */ 471 if (!st_obj->buffer || _mesa_bufferobj_mapped(obj, MAP_USER)) 472 return; 473 474 pipe->invalidate_resource(pipe, st_obj->buffer); 475} 476 477 478/** 479 * Convert GLbitfield of GL_MAP_x flags to gallium pipe_map_flags flags. 480 * \param wholeBuffer is the whole buffer being mapped? 481 */ 482enum pipe_map_flags 483st_access_flags_to_transfer_flags(GLbitfield access, bool wholeBuffer) 484{ 485 enum pipe_map_flags flags = 0; 486 487 if (access & GL_MAP_WRITE_BIT) 488 flags |= PIPE_MAP_WRITE; 489 490 if (access & GL_MAP_READ_BIT) 491 flags |= PIPE_MAP_READ; 492 493 if (access & GL_MAP_FLUSH_EXPLICIT_BIT) 494 flags |= PIPE_MAP_FLUSH_EXPLICIT; 495 496 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) { 497 flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 498 } 499 else if (access & GL_MAP_INVALIDATE_RANGE_BIT) { 500 if (wholeBuffer) 501 flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 502 else 503 flags |= PIPE_MAP_DISCARD_RANGE; 504 } 505 506 if (access & GL_MAP_UNSYNCHRONIZED_BIT) 507 flags |= PIPE_MAP_UNSYNCHRONIZED; 508 509 if (access & GL_MAP_PERSISTENT_BIT) 510 flags |= PIPE_MAP_PERSISTENT; 511 512 if (access & GL_MAP_COHERENT_BIT) 513 flags |= PIPE_MAP_COHERENT; 514 515 /* ... other flags ... 516 */ 517 518 if (access & MESA_MAP_NOWAIT_BIT) 519 flags |= PIPE_MAP_DONTBLOCK; 520 if (access & MESA_MAP_THREAD_SAFE_BIT) 521 flags |= PIPE_MAP_THREAD_SAFE; 522 if (access & MESA_MAP_ONCE) 523 flags |= PIPE_MAP_ONCE; 524 525 return flags; 526} 527 528 529/** 530 * Called via glMapBufferRange(). 531 */ 532static void * 533st_bufferobj_map_range(struct gl_context *ctx, 534 GLintptr offset, GLsizeiptr length, GLbitfield access, 535 struct gl_buffer_object *obj, 536 gl_map_buffer_index index) 537{ 538 struct pipe_context *pipe = st_context(ctx)->pipe; 539 struct st_buffer_object *st_obj = st_buffer_object(obj); 540 541 assert(offset >= 0); 542 assert(length >= 0); 543 assert(offset < obj->Size); 544 assert(offset + length <= obj->Size); 545 546 enum pipe_map_flags transfer_flags = 547 st_access_flags_to_transfer_flags(access, 548 offset == 0 && length == obj->Size); 549 550 /* Sometimes games do silly things like MapBufferRange(UNSYNC|DISCARD_RANGE) 551 * In this case, the the UNSYNC is a bit redundant, but the games rely 552 * on the driver rebinding/replacing the backing storage rather than 553 * going down the UNSYNC path (ie. honoring DISCARD_x first before UNSYNC). 554 */ 555 if (unlikely(st_context(ctx)->options.ignore_map_unsynchronized)) { 556 if (transfer_flags & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE)) 557 transfer_flags &= ~PIPE_MAP_UNSYNCHRONIZED; 558 } 559 560 obj->Mappings[index].Pointer = pipe_buffer_map_range(pipe, 561 st_obj->buffer, 562 offset, length, 563 transfer_flags, 564 &st_obj->transfer[index]); 565 if (obj->Mappings[index].Pointer) { 566 obj->Mappings[index].Offset = offset; 567 obj->Mappings[index].Length = length; 568 obj->Mappings[index].AccessFlags = access; 569 } 570 else { 571 st_obj->transfer[index] = NULL; 572 } 573 574 return obj->Mappings[index].Pointer; 575} 576 577 578static void 579st_bufferobj_flush_mapped_range(struct gl_context *ctx, 580 GLintptr offset, GLsizeiptr length, 581 struct gl_buffer_object *obj, 582 gl_map_buffer_index index) 583{ 584 struct pipe_context *pipe = st_context(ctx)->pipe; 585 struct st_buffer_object *st_obj = st_buffer_object(obj); 586 587 /* Subrange is relative to mapped range */ 588 assert(offset >= 0); 589 assert(length >= 0); 590 assert(offset + length <= obj->Mappings[index].Length); 591 assert(obj->Mappings[index].Pointer); 592 593 if (!length) 594 return; 595 596 pipe_buffer_flush_mapped_range(pipe, st_obj->transfer[index], 597 obj->Mappings[index].Offset + offset, 598 length); 599} 600 601 602/** 603 * Called via glUnmapBufferARB(). 604 */ 605static GLboolean 606st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj, 607 gl_map_buffer_index index) 608{ 609 struct pipe_context *pipe = st_context(ctx)->pipe; 610 struct st_buffer_object *st_obj = st_buffer_object(obj); 611 612 if (obj->Mappings[index].Length) 613 pipe_buffer_unmap(pipe, st_obj->transfer[index]); 614 615 st_obj->transfer[index] = NULL; 616 obj->Mappings[index].Pointer = NULL; 617 obj->Mappings[index].Offset = 0; 618 obj->Mappings[index].Length = 0; 619 return GL_TRUE; 620} 621 622 623/** 624 * Called via glCopyBufferSubData(). 625 */ 626static void 627st_copy_buffer_subdata(struct gl_context *ctx, 628 struct gl_buffer_object *src, 629 struct gl_buffer_object *dst, 630 GLintptr readOffset, GLintptr writeOffset, 631 GLsizeiptr size) 632{ 633 struct pipe_context *pipe = st_context(ctx)->pipe; 634 struct st_buffer_object *srcObj = st_buffer_object(src); 635 struct st_buffer_object *dstObj = st_buffer_object(dst); 636 struct pipe_box box; 637 638 if (!size) 639 return; 640 641 /* buffer should not already be mapped */ 642 assert(!_mesa_check_disallowed_mapping(src)); 643 /* dst can be mapped, just not the same range as the target range */ 644 645 u_box_1d(readOffset, size, &box); 646 647 pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0, 648 srcObj->buffer, 0, &box); 649} 650 651/** 652 * Called via glClearBufferSubData(). 653 */ 654static void 655st_clear_buffer_subdata(struct gl_context *ctx, 656 GLintptr offset, GLsizeiptr size, 657 const void *clearValue, 658 GLsizeiptr clearValueSize, 659 struct gl_buffer_object *bufObj) 660{ 661 struct pipe_context *pipe = st_context(ctx)->pipe; 662 struct st_buffer_object *buf = st_buffer_object(bufObj); 663 static const char zeros[16] = {0}; 664 665 if (!pipe->clear_buffer) { 666 _mesa_ClearBufferSubData_sw(ctx, offset, size, 667 clearValue, clearValueSize, bufObj); 668 return; 669 } 670 671 if (!clearValue) 672 clearValue = zeros; 673 674 pipe->clear_buffer(pipe, buf->buffer, offset, size, 675 clearValue, clearValueSize); 676} 677 678static void 679st_bufferobj_page_commitment(struct gl_context *ctx, 680 struct gl_buffer_object *bufferObj, 681 GLintptr offset, GLsizeiptr size, 682 GLboolean commit) 683{ 684 struct pipe_context *pipe = st_context(ctx)->pipe; 685 struct st_buffer_object *buf = st_buffer_object(bufferObj); 686 struct pipe_box box; 687 688 u_box_1d(offset, size, &box); 689 690 if (!pipe->resource_commit(pipe, buf->buffer, 0, &box, commit)) { 691 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferPageCommitmentARB(out of memory)"); 692 return; 693 } 694} 695 696void 697st_init_bufferobject_functions(struct pipe_screen *screen, 698 struct dd_function_table *functions) 699{ 700 functions->NewBufferObject = st_bufferobj_alloc; 701 functions->DeleteBuffer = st_bufferobj_free; 702 functions->BufferData = st_bufferobj_data; 703 functions->BufferDataMem = st_bufferobj_data_mem; 704 functions->BufferSubData = st_bufferobj_subdata; 705 functions->GetBufferSubData = st_bufferobj_get_subdata; 706 functions->MapBufferRange = st_bufferobj_map_range; 707 functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range; 708 functions->UnmapBuffer = st_bufferobj_unmap; 709 functions->CopyBufferSubData = st_copy_buffer_subdata; 710 functions->ClearBufferSubData = st_clear_buffer_subdata; 711 functions->BufferPageCommitment = st_bufferobj_page_commitment; 712 713 if (screen->get_param(screen, PIPE_CAP_INVALIDATE_BUFFER)) 714 functions->InvalidateBufferSubData = st_bufferobj_invalidate; 715} 716