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