4e67bc225c40683593ed540bae908e5fffef62b5
[mesa.git] / src / mesa / main / bufferobj.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions 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 MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file bufferobj.c
28 * \brief Functions for the GL_ARB_vertex_buffer_object extension.
29 * \author Brian Paul
30 */
31
32
33 #include "glheader.h"
34 #include "hash.h"
35 #include "imports.h"
36 #include "context.h"
37 #include "bufferobj.h"
38
39 struct gl_buffer_object {
40 GLint RefCount;
41 GLuint Name;
42 GLenum Target;
43
44 GLenum usage;
45 GLenum access;
46 GLvoid * pointer;
47 GLuint size;
48
49 void * data;
50 };
51
52 void _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
53 GLuint name, GLenum target );
54
55
56 /**
57 * Get the buffer object bound to the specified target in a GL context.
58 *
59 * \param ctx GL context
60 * \param target Buffer object target to be retrieved. Currently this must
61 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
62 * \param str Name of caller for logging errors.
63 * \return A pointer to the buffer object bound to \c target in the
64 * specified context or \c NULL if \c target is invalid or no
65 * buffer object is bound.
66 */
67
68 static __inline struct gl_buffer_object *
69 _mesa_buffer_object_get_target( GLcontext *ctx, GLenum target,
70 const char * str )
71 {
72 struct gl_buffer_object * bufObj = NULL;
73
74 switch (target) {
75 case GL_ARRAY_BUFFER_ARB:
76 bufObj = ctx->ArrayBuffer;
77 break;
78 case GL_ELEMENT_ARRAY_BUFFER_ARB:
79 bufObj = ctx->ElementArrayBuffer;
80 break;
81 default:
82 _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(target)", str);
83 break;
84 }
85
86 return bufObj;
87 }
88
89
90 /**
91 * Tests the subdata range parameters and sets the GL error code for
92 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
93 *
94 * \param ctx GL context.
95 * \param target Buffer object target on which to operate.
96 * \param offset Offset of the first byte of the subdata range.
97 * \param size Size, in bytes, of the subdata range.
98 * \param str Name of caller for logging errors.
99 * \return A pointer to the buffer object bound to \c target in the
100 * specified context or \c NULL if any of the parameter or state
101 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
102 * are invalid.
103 *
104 * \sa glBufferSubDataARB, glGetBufferSubDataARB
105 */
106
107 static struct gl_buffer_object *
108 _mesa_buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
109 GLintptrARB offset, GLsizeiptrARB size,
110 const char * str )
111 {
112 struct gl_buffer_object *bufObj;
113
114 if (size < 0) {
115 _mesa_error(ctx, GL_INVALID_VALUE, "gl%s(size < 0)", str);
116 return NULL;
117 }
118
119 if (offset < 0) {
120 _mesa_error(ctx, GL_INVALID_VALUE, "gl%s(offset < 0)", str);
121 return NULL;
122 }
123
124 bufObj = _mesa_buffer_object_get_target( ctx, target, str );
125 if ( bufObj == NULL ) {
126 return NULL;
127 }
128
129 if ( (offset + size) > bufObj->size ) {
130 _mesa_error(ctx, GL_INVALID_VALUE,
131 "gl%s(size + offset > buffer size)", str);
132 return NULL;
133 }
134
135 if ( bufObj->pointer != NULL ) {
136 _mesa_error(ctx, GL_INVALID_OPERATION, "gl%s", str);
137 return NULL;
138 }
139
140 return bufObj;
141 }
142
143
144 /**
145 * Allocate and initialize a new buffer object.
146 *
147 * This function is intended to be called via
148 * \c dd_function_table::NewBufferObject.
149 */
150
151 struct gl_buffer_object *
152 _mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
153 {
154 struct gl_buffer_object *obj;
155 obj = CALLOC_STRUCT(gl_buffer_object);
156 _mesa_initialize_buffer_object(obj, name, target);
157 return obj;
158 }
159
160
161 /**
162 * Initialize a buffer object to default values.
163 */
164
165 void
166 _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
167 GLuint name, GLenum target )
168 {
169 obj->RefCount = 1;
170 obj->Name = name;
171 }
172
173
174 /**
175 * Add the given buffer object to the buffer object pool.
176 */
177
178 void
179 _mesa_save_buffer_object( GLcontext *ctx, struct gl_buffer_object *obj )
180 {
181 if (obj->Name > 0) {
182 /* insert into hash table */
183 _mesa_HashInsert(ctx->Shared->BufferObjects, obj->Name, obj);
184 }
185 }
186
187
188 /**
189 * Remove the given buffer object from the buffer object pool.
190 * Do not deallocate the buffer object though.
191 */
192
193 void
194 _mesa_remove_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
195 {
196 if (bufObj->Name > 0) {
197 /* remove from hash table */
198 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
199 }
200 }
201
202
203 /**
204 * Allocate space for and store data in a buffer object. Any data that was
205 * previously stored in the buffer object is lost. If \c data is \c NULL,
206 * memory will be allocated, but no copy will occur.
207 *
208 * This function is intended to be called via
209 * \c dd_function_table::BufferData. This function need not set GL error
210 * codes. The input parameters will have been tested before calling.
211 *
212 * \param ctx GL context.
213 * \param target Buffer object target on which to operate.
214 * \param size Size, in bytes, of the new data store.
215 * \param data Pointer to the data to store in the buffer object. This
216 * pointer may be \c NULL.
217 * \param usage Hints about how the data will be used.
218 * \param bufObj Object to be used.
219 *
220 * \sa glBufferDataARB, dd_function_table::BufferData.
221 */
222
223 void
224 _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
225 const GLvoid * data, GLenum usage,
226 struct gl_buffer_object * bufObj )
227 {
228 void * new_data;
229
230 (void) target;
231
232 new_data = _mesa_realloc( bufObj->data, bufObj->size, size );
233 if ( new_data != NULL ) {
234 bufObj->data = new_data;
235 bufObj->size = size;
236 bufObj->usage = usage;
237
238 if ( data != NULL ) {
239 memcpy( bufObj->data, data, size );
240 }
241 }
242 }
243
244
245 /**
246 * Replace data in a subrange of buffer object. If the data range
247 * specified by \c size + \c offset extends beyond the end of the buffer or
248 * if \c data is \c NULL, no copy is performed.
249 *
250 * This function is intended to be called by
251 * \c dd_function_table::BufferSubData. This function need not set GL error
252 * codes. The input parameters will have been tested before calling.
253 *
254 * \param ctx GL context.
255 * \param target Buffer object target on which to operate.
256 * \param offset Offset of the first byte to be modified.
257 * \param size Size, in bytes, of the data range.
258 * \param data Pointer to the data to store in the buffer object.
259 * \param bufObj Object to be used.
260 *
261 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
262 */
263
264 void
265 _mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
266 GLsizeiptrARB size, const GLvoid * data,
267 struct gl_buffer_object * bufObj )
268 {
269 if ( (bufObj->data != NULL)
270 && ((size + offset) <= bufObj->size) ) {
271 memcpy( (GLubyte *) bufObj->data + offset, data, size );
272 }
273 }
274
275
276 /**
277 * Retrieve data from a subrange of buffer object. If the data range
278 * specified by \c size + \c offset extends beyond the end of the buffer or
279 * if \c data is \c NULL, no copy is performed.
280 *
281 * This function is intended to be called by
282 * \c dd_function_table::BufferGetSubData. This function need not set GL error
283 * codes. The input parameters will have been tested before calling.
284 *
285 * \param ctx GL context.
286 * \param target Buffer object target on which to operate.
287 * \param offset Offset of the first byte to be modified.
288 * \param size Size, in bytes, of the data range.
289 * \param data Pointer to the data to store in the buffer object.
290 * \param bufObj Object to be used.
291 *
292 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
293 */
294
295 void
296 _mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
297 GLsizeiptrARB size, GLvoid * data,
298 struct gl_buffer_object * bufObj )
299 {
300 if ( (bufObj->data != NULL)
301 && ((size + offset) <= bufObj->size) ) {
302 memcpy( data, (GLubyte *) bufObj->data + offset, size );
303 }
304 }
305
306
307 /**
308 * Maps the private data buffer into the processor's address space.
309 *
310 * This function is intended to be called by \c dd_function_table::MapBuffer.
311 * This function need not set GL error codes. The input parameters will have
312 * been tested before calling.
313 *
314 * \param ctx GL context.
315 * \param target Buffer object target on which to operate.
316 * \param access Information about how the buffer will be accessed.
317 * \param bufObj Object to be used.
318 * \return A pointer to the object's internal data store that can be accessed
319 * by the processor
320 *
321 * \sa glMapBufferARB, dd_function_table::MapBuffer
322 */
323
324 void *
325 _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
326 struct gl_buffer_object * bufObj )
327 {
328 return bufObj->data;
329 }
330
331
332 void
333 _mesa_BindBufferARB(GLenum target, GLuint buffer)
334 {
335 GET_CURRENT_CONTEXT(ctx);
336 struct gl_buffer_object *oldBufObj;
337 struct gl_buffer_object *newBufObj = 0;
338 ASSERT_OUTSIDE_BEGIN_END(ctx);
339
340 oldBufObj = _mesa_buffer_object_get_target( ctx, target, "BindBufferARB" );
341 if ( (oldBufObj != NULL) && (oldBufObj->Name == buffer) )
342 return; /* rebinding the same buffer object- no change */
343
344 /*
345 * Get pointer to new buffer object (newBufObj)
346 */
347 if ( buffer == 0 ) {
348 newBufObj = NULL;
349 }
350 else {
351 /* non-default buffer object */
352 const struct _mesa_HashTable *hash = ctx->Shared->BufferObjects;
353 newBufObj = (struct gl_buffer_object *) _mesa_HashLookup(hash, buffer);
354 if ( newBufObj != NULL ) {
355 /* error checking */
356 if (newBufObj->Target != 0 && newBufObj->Target != target) {
357 /* the named buffer object's target doesn't match the target */
358 _mesa_error( ctx, GL_INVALID_OPERATION,
359 "glBindBufferARB(wrong target)" );
360 return;
361 }
362 }
363 else {
364 /* if this is a new buffer object id, allocate a buffer object now */
365 newBufObj = (*ctx->Driver.NewBufferObject)(ctx, buffer, target);
366 if (!newBufObj) {
367 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
368 return;
369 }
370 _mesa_save_buffer_object(ctx, newBufObj);
371 }
372 newBufObj->Target = target;
373 newBufObj->RefCount++;
374 }
375
376 switch (target) {
377 case GL_ARRAY_BUFFER_ARB:
378 ctx->ArrayBuffer = newBufObj;
379 break;
380 case GL_ELEMENT_ARRAY_BUFFER_ARB:
381 ctx->ElementArrayBuffer = newBufObj;
382 break;
383 }
384
385 /* Pass BindBuffer call to device driver */
386 if ( (ctx->Driver.BindBuffer != NULL) && (newBufObj != NULL) )
387 (*ctx->Driver.BindBuffer)( ctx, target, newBufObj );
388
389 if ( oldBufObj != NULL ) {
390 oldBufObj->RefCount--;
391 assert(oldBufObj->RefCount >= 0);
392 if (oldBufObj->RefCount == 0) {
393 assert(oldBufObj->Name != 0);
394 _mesa_remove_buffer_object(ctx, oldBufObj);
395 ASSERT(ctx->Driver.DeleteBuffer);
396 (*ctx->Driver.DeleteBuffer)( ctx, oldBufObj );
397 }
398 }
399 }
400
401
402 /**
403 * Delete a set of buffer objects.
404 *
405 * \param n Number of buffer objects to delete.
406 * \param buffer Array of \c n buffer object IDs.
407 */
408
409 void
410 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
411 {
412 GET_CURRENT_CONTEXT(ctx);
413 unsigned i;
414 ASSERT_OUTSIDE_BEGIN_END(ctx);
415
416 if (n < 0) {
417 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
418 return;
419 }
420
421 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
422
423 for (i = 0; i < n; i++) {
424 if (ids[i] != 0) {
425 struct gl_buffer_object *bufObj = (struct gl_buffer_object *)
426 _mesa_HashLookup(ctx->Shared->BufferObjects, ids[i]);
427 if (bufObj) {
428 if ( (bufObj->Target == GL_ARRAY_BUFFER_ARB)
429 || (bufObj->Target == GL_ELEMENT_ARRAY_BUFFER_ARB) ) {
430 _mesa_BindBufferARB( bufObj->Target, 0 );
431 }
432 else if (bufObj->Target == 0) {
433 /* The buffer object is not bound.
434 */
435 }
436 else {
437 _mesa_problem(ctx, "bad target in glDeleteBufferARB");
438 return;
439 }
440 bufObj->RefCount--;
441 if (bufObj->RefCount <= 0) {
442 ASSERT(bufObj->Name != 0);
443 _mesa_remove_buffer_object(ctx, bufObj);
444 ASSERT(ctx->Driver.DeleteBuffer);
445 (*ctx->Driver.DeleteBuffer)(ctx, bufObj);
446 }
447 }
448 }
449 }
450
451 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
452 }
453
454
455 /**
456 * Generate a set of unique buffer object IDs and store them in \c buffer.
457 *
458 * \param n Number of IDs to generate.
459 * \param buffer Array of \c n locations to store the IDs.
460 */
461
462 void
463 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
464 {
465 GET_CURRENT_CONTEXT(ctx);
466 GLuint first;
467 GLint i;
468 ASSERT_OUTSIDE_BEGIN_END(ctx);
469
470 if (n < 0) {
471 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
472 return;
473 }
474
475 if ( buffer == NULL ) {
476 return;
477 }
478
479 /*
480 * This must be atomic (generation and allocation of buffer object IDs)
481 */
482 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
483
484 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
485
486 /* Return the buffer names */
487 for (i=0;i<n;i++) {
488 buffer[i] = first + i;
489 }
490
491 /* Allocate new, empty buffer objects */
492 for (i = 0; i < n; i++) {
493 struct gl_buffer_object *bufObj;
494 GLuint name = first + i;
495 GLenum target = 0;
496 bufObj = (*ctx->Driver.NewBufferObject)( ctx, name, target );
497 if ( bufObj != NULL ) {
498 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
499 return;
500 }
501 _mesa_save_buffer_object(ctx, bufObj);
502 }
503
504 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
505 }
506
507
508 /**
509 * Determine if ID is the name of a buffer object.
510 *
511 * \param id ID of the potential buffer object.
512 * \return \c GL_TRUE if \c id is the name of a buffer object,
513 * \c GL_FALSE otherwise.
514 */
515
516 GLboolean
517 _mesa_IsBufferARB(GLuint id)
518 {
519 struct gl_buffer_object * bufObj;
520 GET_CURRENT_CONTEXT(ctx);
521 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
522
523 if (id == 0)
524 return GL_FALSE;
525
526 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
527 bufObj = (struct gl_buffer_object *) _mesa_HashLookup(ctx->Shared->BufferObjects, id);
528 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
529
530 return (bufObj != NULL);
531 }
532
533
534 void
535 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
536 const GLvoid * data, GLenum usage)
537 {
538 GET_CURRENT_CONTEXT(ctx);
539 struct gl_buffer_object *bufObj;
540 ASSERT_OUTSIDE_BEGIN_END(ctx);
541
542 if (size < 0) {
543 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
544 return;
545 }
546
547 switch (usage) {
548 case GL_STREAM_DRAW_ARB:
549 case GL_STREAM_READ_ARB:
550 case GL_STREAM_COPY_ARB:
551 case GL_STATIC_DRAW_ARB:
552 case GL_STATIC_READ_ARB:
553 case GL_STATIC_COPY_ARB:
554 case GL_DYNAMIC_DRAW_ARB:
555 case GL_DYNAMIC_READ_ARB:
556 case GL_DYNAMIC_COPY_ARB:
557 /* OK */
558 break;
559 default:
560 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
561 return;
562 }
563
564 bufObj = _mesa_buffer_object_get_target( ctx, target, "BufferDataARB" );
565 if ( bufObj == NULL ) {
566 return;
567 }
568
569 ASSERT(ctx->Driver.BufferData);
570
571 /* Give the buffer object to the driver! <data> may be null! */
572 (*ctx->Driver.BufferData)( ctx, target, size, data, usage, bufObj );
573 }
574
575 void
576 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
577 GLsizeiptrARB size, const GLvoid * data)
578 {
579 GET_CURRENT_CONTEXT(ctx);
580 struct gl_buffer_object *bufObj;
581 ASSERT_OUTSIDE_BEGIN_END(ctx);
582
583 bufObj = _mesa_buffer_object_subdata_range_good( ctx, target, offset, size,
584 "BufferSubDataARB" );
585 if ( bufObj != NULL ) {
586 ASSERT(ctx->Driver.BufferSubData);
587 (*ctx->Driver.BufferSubData)( ctx, target, offset, size, data, bufObj );
588 }
589 }
590
591 void
592 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
593 GLsizeiptrARB size, void * data)
594 {
595 GET_CURRENT_CONTEXT(ctx);
596 struct gl_buffer_object *bufObj;
597 ASSERT_OUTSIDE_BEGIN_END(ctx);
598
599 bufObj = _mesa_buffer_object_subdata_range_good( ctx, target, offset, size,
600 "GetBufferSubDataARB" );
601 if ( bufObj != NULL ) {
602 ASSERT(ctx->Driver.GetBufferSubData);
603 (*ctx->Driver.GetBufferSubData)( ctx, target, offset, size, data, bufObj );
604 }
605 }
606
607 void *
608 _mesa_MapBufferARB(GLenum target, GLenum access)
609 {
610 GET_CURRENT_CONTEXT(ctx);
611 struct gl_buffer_object * bufObj;
612 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
613
614 switch (access) {
615 case GL_READ_ONLY_ARB:
616 case GL_WRITE_ONLY_ARB:
617 case GL_READ_WRITE_ARB:
618 /* OK */
619 break;
620 default:
621 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
622 return NULL;
623 }
624
625 bufObj = _mesa_buffer_object_get_target( ctx, target,
626 "MapBufferARB" );
627 if ( bufObj == NULL ) {
628 return NULL;
629 }
630
631 if ( bufObj->pointer != NULL ) {
632 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB");
633 return NULL;
634 }
635
636 ASSERT(ctx->Driver.MapBuffer);
637 bufObj->pointer = (*ctx->Driver.MapBuffer)( ctx, target, access, bufObj );
638 if ( bufObj->pointer == NULL ) {
639 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
640 }
641
642 return bufObj->pointer;
643 }
644
645 GLboolean
646 _mesa_UnmapBufferARB(GLenum target)
647 {
648 GET_CURRENT_CONTEXT(ctx);
649 struct gl_buffer_object *bufObj;
650 GLboolean status = GL_TRUE;
651 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
652
653
654 bufObj = _mesa_buffer_object_get_target( ctx, target,
655 "UnmapBufferARB" );
656 if ( bufObj == NULL ) {
657 return GL_FALSE;
658 }
659
660 if ( bufObj->pointer == NULL ) {
661 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
662 return GL_FALSE;
663 }
664
665 if ( ctx->Driver.UnmapBuffer != NULL ) {
666 status = (*ctx->Driver.UnmapBuffer)( ctx, target, bufObj );
667 }
668
669 bufObj->pointer = NULL;
670
671 return status;
672 }
673
674 void
675 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
676 {
677 GET_CURRENT_CONTEXT(ctx);
678 struct gl_buffer_object *bufObj;
679 ASSERT_OUTSIDE_BEGIN_END(ctx);
680
681 bufObj = _mesa_buffer_object_get_target( ctx, target,
682 "GetBufferParameterivARB" );
683 if ( bufObj == NULL ) {
684 return;
685 }
686
687 switch (pname) {
688 case GL_BUFFER_SIZE_ARB:
689 *params = bufObj->size;
690 break;
691 case GL_BUFFER_USAGE_ARB:
692 *params = bufObj->usage;
693 break;
694 case GL_BUFFER_ACCESS_ARB:
695 *params = bufObj->access;
696 break;
697 case GL_BUFFER_MAPPED_ARB:
698 *params = (bufObj->pointer != NULL);
699 break;
700 default:
701 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
702 return;
703 }
704 }
705
706 void
707 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
708 {
709 GET_CURRENT_CONTEXT(ctx);
710 struct gl_buffer_object * bufObj;
711 ASSERT_OUTSIDE_BEGIN_END(ctx);
712
713 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
714 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
715 return;
716 }
717
718 bufObj = _mesa_buffer_object_get_target( ctx, target,
719 "GetBufferPointervARB" );
720 if ( bufObj == NULL ) {
721 return;
722 }
723
724 *params = bufObj->pointer;
725 }