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 *
st_bufferobj_alloc(struct gl_context * ctx,GLuint name,GLenum target)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
st_bufferobj_free(struct gl_context * ctx,struct gl_buffer_object * obj)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
st_bufferobj_subdata(struct gl_context * ctx,GLintptrARB offset,GLsizeiptrARB size,const GLvoid * data,struct gl_buffer_object * obj)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
st_bufferobj_get_subdata(struct gl_context * ctx,GLintptrARB offset,GLsizeiptrARB size,GLvoid * data,struct gl_buffer_object * obj)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
st_bufferobj_data(struct gl_context * ctx,GLenum target,GLsizeiptrARB size,const GLvoid * data,GLenum usage,struct gl_buffer_object * obj)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 *
st_bufferobj_map_range(struct gl_context * ctx,GLintptr offset,GLsizeiptr length,GLbitfield access,struct gl_buffer_object * obj)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
st_bufferobj_flush_mapped_range(struct gl_context * ctx,GLintptr offset,GLsizeiptr length,struct gl_buffer_object * obj)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
st_bufferobj_unmap(struct gl_context * ctx,struct gl_buffer_object * obj)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
st_copy_buffer_subdata(struct gl_context * ctx,struct gl_buffer_object * src,struct gl_buffer_object * dst,GLintptr readOffset,GLintptr writeOffset,GLsizeiptr size)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
st_bufferobj_validate_usage(struct st_context * st,struct st_buffer_object * obj,unsigned usage)383 st_bufferobj_validate_usage(struct st_context *st,
384 			    struct st_buffer_object *obj,
385 			    unsigned usage)
386 {
387 }
388 
389 
390 void
st_init_bufferobject_functions(struct dd_function_table * functions)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