1 /************************************************************************** 2 * 3 * Copyright 2007 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 29 /** 30 * Functions for pixel buffer objects and vertex/element buffer objects. 31 */ 32 33 34 #include "main/imports.h" 35 #include "main/mtypes.h" 36 #include "main/arrayobj.h" 37 #include "main/bufferobj.h" 38 39 #include "st_context.h" 40 #include "st_cb_bufferobjects.h" 41 42 #include "pipe/p_context.h" 43 #include "pipe/p_defines.h" 44 #include "util/u_inlines.h" 45 46 47 /** 48 * There is some duplication between mesa's bufferobjects and our 49 * bufmgr buffers. Both have an integer handle and a hashtable to 50 * lookup an opaque structure. It would be nice if the handles and 51 * internal structure where somehow shared. 52 */ 53 static struct gl_buffer_object * 54 st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target) 55 { 56 struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object); 57 58 if (!st_obj) 59 return NULL; 60 61 _mesa_initialize_buffer_object(ctx, &st_obj->Base, name, target); 62 63 return &st_obj->Base; 64 } 65 66 67 68 /** 69 * Deallocate/free a vertex/pixel buffer object. 70 * Called via glDeleteBuffersARB(). 71 */ 72 static void 73 st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj) 74 { 75 struct st_buffer_object *st_obj = st_buffer_object(obj); 76 77 assert(obj->RefCount == 0); 78 assert(st_obj->transfer == NULL); 79 80 if (st_obj->buffer) 81 pipe_resource_reference(&st_obj->buffer, NULL); 82 83 free(st_obj); 84 } 85 86 87 88 /** 89 * Replace data in a subrange of buffer object. If the data range 90 * specified by size + offset extends beyond the end of the buffer or 91 * if data is NULL, no copy is performed. 92 * Called via glBufferSubDataARB(). 93 */ 94 static void 95 st_bufferobj_subdata(struct gl_context *ctx, 96 GLintptrARB offset, 97 GLsizeiptrARB size, 98 const GLvoid * data, struct gl_buffer_object *obj) 99 { 100 struct st_buffer_object *st_obj = st_buffer_object(obj); 101 102 /* we may be called from VBO code, so double-check params here */ 103 ASSERT(offset >= 0); 104 ASSERT(size >= 0); 105 ASSERT(offset + size <= obj->Size); 106 107 if (!size) 108 return; 109 110 /* 111 * According to ARB_vertex_buffer_object specification, if data is null, 112 * then the contents of the buffer object's data store is undefined. We just 113 * ignore, and leave it unchanged. 114 */ 115 if (!data) 116 return; 117 118 if (!st_obj->buffer) { 119 /* we probably ran out of memory during buffer allocation */ 120 return; 121 } 122 123 /* Now that transfers are per-context, we don't have to figure out 124 * flushing here. Usually drivers won't need to flush in this case 125 * even if the buffer is currently referenced by hardware - they 126 * just queue the upload as dma rather than mapping the underlying 127 * buffer directly. 128 */ 129 pipe_buffer_write(st_context(ctx)->pipe, 130 st_obj->buffer, 131 offset, size, data); 132 } 133 134 135 /** 136 * Called via glGetBufferSubDataARB(). 137 */ 138 static void 139 st_bufferobj_get_subdata(struct gl_context *ctx, 140 GLintptrARB offset, 141 GLsizeiptrARB size, 142 GLvoid * data, struct gl_buffer_object *obj) 143 { 144 struct st_buffer_object *st_obj = st_buffer_object(obj); 145 146 /* we may be called from VBO code, so double-check params here */ 147 ASSERT(offset >= 0); 148 ASSERT(size >= 0); 149 ASSERT(offset + size <= obj->Size); 150 151 if (!size) 152 return; 153 154 if (!st_obj->buffer) { 155 /* we probably ran out of memory during buffer allocation */ 156 return; 157 } 158 159 pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer, 160 offset, size, data); 161 } 162 163 164 /** 165 * Allocate space for and store data in a buffer object. Any data that was 166 * previously stored in the buffer object is lost. If data is NULL, 167 * memory will be allocated, but no copy will occur. 168 * Called via ctx->Driver.BufferData(). 169 * \return GL_TRUE for success, GL_FALSE if out of memory 170 */ 171 static GLboolean 172 st_bufferobj_data(struct gl_context *ctx, 173 GLenum target, 174 GLsizeiptrARB size, 175 const GLvoid * data, 176 GLenum usage, 177 struct gl_buffer_object *obj) 178 { 179 struct st_context *st = st_context(ctx); 180 struct pipe_context *pipe = st->pipe; 181 struct st_buffer_object *st_obj = st_buffer_object(obj); 182 unsigned bind, pipe_usage; 183 184 st_obj->Base.Size = size; 185 st_obj->Base.Usage = usage; 186 187 switch(target) { 188 case GL_PIXEL_PACK_BUFFER_ARB: 189 case GL_PIXEL_UNPACK_BUFFER_ARB: 190 bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 191 break; 192 case GL_ARRAY_BUFFER_ARB: 193 bind = PIPE_BIND_VERTEX_BUFFER; 194 break; 195 case GL_ELEMENT_ARRAY_BUFFER_ARB: 196 bind = PIPE_BIND_INDEX_BUFFER; 197 break; 198 case GL_TRANSFORM_FEEDBACK_BUFFER: 199 bind = PIPE_BIND_STREAM_OUTPUT; 200 break; 201 default: 202 bind = 0; 203 } 204 205 switch (usage) { 206 case GL_STATIC_DRAW: 207 case GL_STATIC_READ: 208 case GL_STATIC_COPY: 209 pipe_usage = PIPE_USAGE_STATIC; 210 break; 211 case GL_DYNAMIC_DRAW: 212 case GL_DYNAMIC_READ: 213 case GL_DYNAMIC_COPY: 214 pipe_usage = PIPE_USAGE_DYNAMIC; 215 break; 216 case GL_STREAM_DRAW: 217 case GL_STREAM_READ: 218 case GL_STREAM_COPY: 219 pipe_usage = PIPE_USAGE_STREAM; 220 break; 221 default: 222 pipe_usage = PIPE_USAGE_DEFAULT; 223 } 224 225 pipe_resource_reference( &st_obj->buffer, NULL ); 226 227 if (size != 0) { 228 st_obj->buffer = pipe_buffer_create(pipe->screen, bind, 229 pipe_usage, size); 230 231 if (!st_obj->buffer) { 232 /* out of memory */ 233 st_obj->Base.Size = 0; 234 return GL_FALSE; 235 } 236 237 if (data) 238 pipe_buffer_write(pipe, st_obj->buffer, 0, size, data); 239 return GL_TRUE; 240 } 241 242 return GL_TRUE; 243 } 244 245 246 /** 247 * Called via glMapBufferRange(). 248 */ 249 static void * 250 st_bufferobj_map_range(struct gl_context *ctx, 251 GLintptr offset, GLsizeiptr length, GLbitfield access, 252 struct gl_buffer_object *obj) 253 { 254 struct pipe_context *pipe = st_context(ctx)->pipe; 255 struct st_buffer_object *st_obj = st_buffer_object(obj); 256 enum pipe_transfer_usage flags = 0x0; 257 258 if (access & GL_MAP_WRITE_BIT) 259 flags |= PIPE_TRANSFER_WRITE; 260 261 if (access & GL_MAP_READ_BIT) 262 flags |= PIPE_TRANSFER_READ; 263 264 if (access & GL_MAP_FLUSH_EXPLICIT_BIT) 265 flags |= PIPE_TRANSFER_FLUSH_EXPLICIT; 266 267 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) { 268 flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 269 } 270 else if (access & GL_MAP_INVALIDATE_RANGE_BIT) { 271 if (offset == 0 && length == obj->Size) 272 flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 273 else 274 flags |= PIPE_TRANSFER_DISCARD_RANGE; 275 } 276 277 if (access & GL_MAP_UNSYNCHRONIZED_BIT) 278 flags |= PIPE_TRANSFER_UNSYNCHRONIZED; 279 280 /* ... other flags ... 281 */ 282 283 if (access & MESA_MAP_NOWAIT_BIT) 284 flags |= PIPE_TRANSFER_DONTBLOCK; 285 286 assert(offset >= 0); 287 assert(length >= 0); 288 assert(offset < obj->Size); 289 assert(offset + length <= obj->Size); 290 291 obj->Pointer = pipe_buffer_map_range(pipe, 292 st_obj->buffer, 293 offset, length, 294 flags, 295 &st_obj->transfer); 296 if (obj->Pointer) { 297 obj->Offset = offset; 298 obj->Length = length; 299 obj->AccessFlags = access; 300 } 301 302 return obj->Pointer; 303 } 304 305 306 static void 307 st_bufferobj_flush_mapped_range(struct gl_context *ctx, 308 GLintptr offset, GLsizeiptr length, 309 struct gl_buffer_object *obj) 310 { 311 struct pipe_context *pipe = st_context(ctx)->pipe; 312 struct st_buffer_object *st_obj = st_buffer_object(obj); 313 314 /* Subrange is relative to mapped range */ 315 assert(offset >= 0); 316 assert(length >= 0); 317 assert(offset + length <= obj->Length); 318 assert(obj->Pointer); 319 320 if (!length) 321 return; 322 323 pipe_buffer_flush_mapped_range(pipe, st_obj->transfer, 324 obj->Offset + offset, length); 325 } 326 327 328 /** 329 * Called via glUnmapBufferARB(). 330 */ 331 static GLboolean 332 st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj) 333 { 334 struct pipe_context *pipe = st_context(ctx)->pipe; 335 struct st_buffer_object *st_obj = st_buffer_object(obj); 336 337 if (obj->Length) 338 pipe_buffer_unmap(pipe, st_obj->transfer); 339 340 st_obj->transfer = NULL; 341 obj->Pointer = NULL; 342 obj->Offset = 0; 343 obj->Length = 0; 344 return GL_TRUE; 345 } 346 347 348 /** 349 * Called via glCopyBufferSubData(). 350 */ 351 static void 352 st_copy_buffer_subdata(struct gl_context *ctx, 353 struct gl_buffer_object *src, 354 struct gl_buffer_object *dst, 355 GLintptr readOffset, GLintptr writeOffset, 356 GLsizeiptr size) 357 { 358 struct pipe_context *pipe = st_context(ctx)->pipe; 359 struct st_buffer_object *srcObj = st_buffer_object(src); 360 struct st_buffer_object *dstObj = st_buffer_object(dst); 361 struct pipe_box box; 362 363 if(!size) 364 return; 365 366 /* buffer should not already be mapped */ 367 assert(!src->Pointer); 368 assert(!dst->Pointer); 369 370 u_box_1d(readOffset, size, &box); 371 372 pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0, 373 srcObj->buffer, 0, &box); 374 } 375 376 377 /* TODO: if buffer wasn't created with appropriate usage flags, need 378 * to recreate it now and copy contents -- or possibly create a 379 * gallium entrypoint to extend the usage flags and let the driver 380 * decide if a copy is necessary. 381 */ 382 void 383 st_bufferobj_validate_usage(struct st_context *st, 384 struct st_buffer_object *obj, 385 unsigned usage) 386 { 387 } 388 389 390 void 391 st_init_bufferobject_functions(struct dd_function_table *functions) 392 { 393 functions->NewBufferObject = st_bufferobj_alloc; 394 functions->DeleteBuffer = st_bufferobj_free; 395 functions->BufferData = st_bufferobj_data; 396 functions->BufferSubData = st_bufferobj_subdata; 397 functions->GetBufferSubData = st_bufferobj_get_subdata; 398 functions->MapBufferRange = st_bufferobj_map_range; 399 functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range; 400 functions->UnmapBuffer = st_bufferobj_unmap; 401 functions->CopyBufferSubData = st_copy_buffer_subdata; 402 403 /* For GL_APPLE_vertex_array_object */ 404 functions->NewArrayObject = _mesa_new_array_object; 405 functions->DeleteArrayObject = _mesa_delete_array_object; 406 } 407