st_cb_bufferobjects.c revision 28486880ca3ec39419ccee0cb1a3bedc9ef7117c
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_inlines.h" 40#include "st_context.h" 41#include "st_cb_bufferobjects.h" 42 43#include "pipe/p_context.h" 44#include "pipe/p_defines.h" 45#include "util/u_inlines.h" 46 47 48/** 49 * There is some duplication between mesa's bufferobjects and our 50 * bufmgr buffers. Both have an integer handle and a hashtable to 51 * lookup an opaque structure. It would be nice if the handles and 52 * internal structure where somehow shared. 53 */ 54static struct gl_buffer_object * 55st_bufferobj_alloc(GLcontext *ctx, GLuint name, GLenum target) 56{ 57 struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object); 58 59 if (!st_obj) 60 return NULL; 61 62 _mesa_initialize_buffer_object(&st_obj->Base, name, target); 63 64 return &st_obj->Base; 65} 66 67 68 69/** 70 * Deallocate/free a vertex/pixel buffer object. 71 * Called via glDeleteBuffersARB(). 72 */ 73static void 74st_bufferobj_free(GLcontext *ctx, struct gl_buffer_object *obj) 75{ 76 struct st_buffer_object *st_obj = st_buffer_object(obj); 77 78 if (st_obj->buffer) 79 pipe_buffer_reference(&st_obj->buffer, NULL); 80 81 _mesa_free(st_obj); 82} 83 84 85 86/** 87 * Replace data in a subrange of buffer object. If the data range 88 * specified by size + offset extends beyond the end of the buffer or 89 * if data is NULL, no copy is performed. 90 * Called via glBufferSubDataARB(). 91 */ 92static void 93st_bufferobj_subdata(GLcontext *ctx, 94 GLenum target, 95 GLintptrARB offset, 96 GLsizeiptrARB size, 97 const GLvoid * data, struct gl_buffer_object *obj) 98{ 99 struct st_buffer_object *st_obj = st_buffer_object(obj); 100 101 /* we may be called from VBO code, so double-check params here */ 102 ASSERT(offset >= 0); 103 ASSERT(size >= 0); 104 ASSERT(offset + size <= obj->Size); 105 106 if (!size) 107 return; 108 109 /* 110 * According to ARB_vertex_buffer_object specification, if data is null, 111 * then the contents of the buffer object's data store is undefined. We just 112 * ignore, and leave it unchanged. 113 */ 114 if (!data) 115 return; 116 117 st_cond_flush_pipe_buffer_write(st_context(ctx), st_obj->buffer, 118 offset, size, data); 119} 120 121 122/** 123 * Called via glGetBufferSubDataARB(). 124 */ 125static void 126st_bufferobj_get_subdata(GLcontext *ctx, 127 GLenum target, 128 GLintptrARB offset, 129 GLsizeiptrARB size, 130 GLvoid * data, struct gl_buffer_object *obj) 131{ 132 struct st_buffer_object *st_obj = st_buffer_object(obj); 133 134 /* we may be called from VBO code, so double-check params here */ 135 ASSERT(offset >= 0); 136 ASSERT(size >= 0); 137 ASSERT(offset + size <= obj->Size); 138 139 if (!size) 140 return; 141 142 st_cond_flush_pipe_buffer_read(st_context(ctx), st_obj->buffer, 143 offset, size, data); 144} 145 146 147/** 148 * Allocate space for and store data in a buffer object. Any data that was 149 * previously stored in the buffer object is lost. If data is NULL, 150 * memory will be allocated, but no copy will occur. 151 * Called via ctx->Driver.BufferData(). 152 * \return GL_TRUE for success, GL_FALSE if out of memory 153 */ 154static GLboolean 155st_bufferobj_data(GLcontext *ctx, 156 GLenum target, 157 GLsizeiptrARB size, 158 const GLvoid * data, 159 GLenum usage, 160 struct gl_buffer_object *obj) 161{ 162 struct st_context *st = st_context(ctx); 163 struct pipe_context *pipe = st->pipe; 164 struct st_buffer_object *st_obj = st_buffer_object(obj); 165 unsigned buffer_usage; 166 167 st_obj->Base.Size = size; 168 st_obj->Base.Usage = usage; 169 170 switch(target) { 171 case GL_PIXEL_PACK_BUFFER_ARB: 172 case GL_PIXEL_UNPACK_BUFFER_ARB: 173 buffer_usage = PIPE_BUFFER_USAGE_PIXEL; 174 break; 175 case GL_ARRAY_BUFFER_ARB: 176 buffer_usage = PIPE_BUFFER_USAGE_VERTEX; 177 break; 178 case GL_ELEMENT_ARRAY_BUFFER_ARB: 179 buffer_usage = PIPE_BUFFER_USAGE_INDEX; 180 break; 181 default: 182 buffer_usage = 0; 183 } 184 185 pipe_buffer_reference( &st_obj->buffer, NULL ); 186 187 if (size != 0) { 188 st_obj->buffer = pipe_buffer_create(pipe->screen, 32, buffer_usage, size); 189 190 if (!st_obj->buffer) { 191 return GL_FALSE; 192 } 193 194 if (data) 195 st_no_flush_pipe_buffer_write(st_context(ctx), st_obj->buffer, 0, 196 size, data); 197 return GL_TRUE; 198 } 199 200 return GL_TRUE; 201} 202 203 204/** 205 * Called via glMapBufferARB(). 206 */ 207static void * 208st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access, 209 struct gl_buffer_object *obj) 210{ 211 struct st_buffer_object *st_obj = st_buffer_object(obj); 212 uint flags; 213 214 switch (access) { 215 case GL_WRITE_ONLY: 216 flags = PIPE_BUFFER_USAGE_CPU_WRITE; 217 break; 218 case GL_READ_ONLY: 219 flags = PIPE_BUFFER_USAGE_CPU_READ; 220 break; 221 case GL_READ_WRITE: 222 /* fall-through */ 223 default: 224 flags = PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE; 225 break; 226 } 227 228 obj->Pointer = st_cond_flush_pipe_buffer_map(st_context(ctx), 229 st_obj->buffer, 230 flags); 231 if (obj->Pointer) { 232 obj->Offset = 0; 233 obj->Length = obj->Size; 234 } 235 return obj->Pointer; 236} 237 238 239/** 240 * Dummy data whose's pointer is used for zero length ranges. 241 */ 242static long 243st_bufferobj_zero_length_range = 0; 244 245 246/** 247 * Called via glMapBufferRange(). 248 */ 249static void * 250st_bufferobj_map_range(GLcontext *ctx, GLenum target, 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 uint flags = 0x0; 257 258 if (access & GL_MAP_WRITE_BIT) 259 flags |= PIPE_BUFFER_USAGE_CPU_WRITE; 260 261 if (access & GL_MAP_READ_BIT) 262 flags |= PIPE_BUFFER_USAGE_CPU_READ; 263 264 if (access & GL_MAP_FLUSH_EXPLICIT_BIT) 265 flags |= PIPE_BUFFER_USAGE_FLUSH_EXPLICIT; 266 267 if (access & GL_MAP_UNSYNCHRONIZED_BIT) 268 flags |= PIPE_BUFFER_USAGE_UNSYNCHRONIZED; 269 270 /* ... other flags ... 271 */ 272 273 if (access & MESA_MAP_NOWAIT_BIT) 274 flags |= PIPE_BUFFER_USAGE_DONTBLOCK; 275 276 assert(offset >= 0); 277 assert(length >= 0); 278 assert(offset < obj->Size); 279 assert(offset + length <= obj->Size); 280 281 /* 282 * We go out of way here to hide the degenerate yet valid case of zero 283 * length range from the pipe driver. 284 */ 285 if (!length) { 286 obj->Pointer = &st_bufferobj_zero_length_range; 287 } 288 else { 289 obj->Pointer = pipe_buffer_map_range(pipe->screen, st_obj->buffer, offset, length, flags); 290 if (obj->Pointer) { 291 obj->Pointer = (ubyte *) obj->Pointer + offset; 292 } 293 } 294 295 if (obj->Pointer) { 296 obj->Offset = offset; 297 obj->Length = length; 298 obj->AccessFlags = access; 299 } 300 301 return obj->Pointer; 302} 303 304 305static void 306st_bufferobj_flush_mapped_range(GLcontext *ctx, GLenum target, 307 GLintptr offset, GLsizeiptr length, 308 struct gl_buffer_object *obj) 309{ 310 struct pipe_context *pipe = st_context(ctx)->pipe; 311 struct st_buffer_object *st_obj = st_buffer_object(obj); 312 313 /* Subrange is relative to mapped range */ 314 assert(offset >= 0); 315 assert(length >= 0); 316 assert(offset + length <= obj->Length); 317 318 if (!length) 319 return; 320 321 pipe_buffer_flush_mapped_range(pipe->screen, st_obj->buffer, 322 obj->Offset + offset, length); 323} 324 325 326/** 327 * Called via glUnmapBufferARB(). 328 */ 329static GLboolean 330st_bufferobj_unmap(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) 331{ 332 struct pipe_context *pipe = st_context(ctx)->pipe; 333 struct st_buffer_object *st_obj = st_buffer_object(obj); 334 335 if(obj->Length) 336 pipe_buffer_unmap(pipe->screen, st_obj->buffer); 337 338 obj->Pointer = NULL; 339 obj->Offset = 0; 340 obj->Length = 0; 341 return GL_TRUE; 342} 343 344 345/** 346 * Called via glCopyBufferSubData(). 347 */ 348static void 349st_copy_buffer_subdata(GLcontext *ctx, 350 struct gl_buffer_object *src, 351 struct gl_buffer_object *dst, 352 GLintptr readOffset, GLintptr writeOffset, 353 GLsizeiptr size) 354{ 355 struct pipe_context *pipe = st_context(ctx)->pipe; 356 struct st_buffer_object *srcObj = st_buffer_object(src); 357 struct st_buffer_object *dstObj = st_buffer_object(dst); 358 ubyte *srcPtr, *dstPtr; 359 360 if(!size) 361 return; 362 363 /* buffer should not already be mapped */ 364 assert(!src->Pointer); 365 assert(!dst->Pointer); 366 367 srcPtr = (ubyte *) pipe_buffer_map_range(pipe->screen, 368 srcObj->buffer, 369 readOffset, size, 370 PIPE_BUFFER_USAGE_CPU_READ); 371 372 dstPtr = (ubyte *) pipe_buffer_map_range(pipe->screen, 373 dstObj->buffer, 374 writeOffset, size, 375 PIPE_BUFFER_USAGE_CPU_WRITE); 376 377 if (srcPtr && dstPtr) 378 _mesa_memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); 379 380 pipe_buffer_unmap(pipe->screen, srcObj->buffer); 381 pipe_buffer_unmap(pipe->screen, dstObj->buffer); 382} 383 384 385void 386st_init_bufferobject_functions(struct dd_function_table *functions) 387{ 388 functions->NewBufferObject = st_bufferobj_alloc; 389 functions->DeleteBuffer = st_bufferobj_free; 390 functions->BufferData = st_bufferobj_data; 391 functions->BufferSubData = st_bufferobj_subdata; 392 functions->GetBufferSubData = st_bufferobj_get_subdata; 393 functions->MapBuffer = st_bufferobj_map; 394 functions->MapBufferRange = st_bufferobj_map_range; 395 functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range; 396 functions->UnmapBuffer = st_bufferobj_unmap; 397 functions->CopyBufferSubData = st_copy_buffer_subdata; 398 399 /* For GL_APPLE_vertex_array_object */ 400 functions->NewArrayObject = _mesa_new_array_object; 401 functions->DeleteArrayObject = _mesa_delete_array_object; 402} 403